diff --git a/chart_test.go b/chart_test.go index dbbb34f..55db3e0 100644 --- a/chart_test.go +++ b/chart_test.go @@ -527,6 +527,8 @@ func TestChartE2ELine(t *testing.T) { func TestChartE2ELineWithFill(t *testing.T) { assert := assert.New(t) + logBuffer := new(bytes.Buffer) + c := Chart{ Height: 50, Width: 50, @@ -550,7 +552,7 @@ func TestChartE2ELineWithFill(t *testing.T) { YValues: LinearRangeWithStep(0, 4, 1), }, }, - Log: NewLogger(), + Log: NewLogger(OptLoggerStdout(logBuffer), OptLoggerStderr(logBuffer)), } assert.Equal(5, len(c.Series[0].(ContinuousSeries).XValues)) diff --git a/logger.go b/logger.go index a2fa397..28fc003 100644 --- a/logger.go +++ b/logger.go @@ -12,12 +12,16 @@ var ( ) // NewLogger returns a new logger. -func NewLogger() Logger { - return &StdoutLogger{ +func NewLogger(options ...LoggerOption) Logger { + stl := &StdoutLogger{ TimeFormat: time.RFC3339Nano, Stdout: os.Stdout, Stderr: os.Stderr, } + for _, option := range options { + option(stl) + } + return stl } // Logger is a type that implements the logging interface. @@ -30,8 +34,6 @@ type Logger interface { FatalErr(error) Error(...interface{}) Errorf(string, ...interface{}) - Println(...interface{}) - Errorln(...interface{}) } // Info logs an info message if the logger is set. @@ -66,6 +68,23 @@ func Debugf(log Logger, format string, arguments ...interface{}) { log.Debugf(format, arguments...) } +// LoggerOption mutates a stdout logger. +type LoggerOption = func(*StdoutLogger) + +//OptLoggerStdout sets the Stdout writer. +func OptLoggerStdout(wr io.Writer) LoggerOption { + return func(stl *StdoutLogger) { + stl.Stdout = wr + } +} + +// OptLoggerStderr sets the Stdout writer. +func OptLoggerStderr(wr io.Writer) LoggerOption { + return func(stl *StdoutLogger) { + stl.Stderr = wr + } +} + // StdoutLogger is a basic logger. type StdoutLogger struct { TimeFormat string diff --git a/percent_change_series.go b/percent_change_series.go new file mode 100644 index 0000000..3767893 --- /dev/null +++ b/percent_change_series.go @@ -0,0 +1,89 @@ +package chart + +// Interface Assertions. +var ( + _ Series = (*PercentChangeSeries)(nil) + _ FirstValuesProvider = (*PercentChangeSeries)(nil) + _ LastValuesProvider = (*PercentChangeSeries)(nil) + _ ValueFormatterProvider = (*PercentChangeSeries)(nil) +) + +// PercentChangeSeriesSource is a series that +// can be used with a PercentChangeSeries +type PercentChangeSeriesSource interface { + Series + FirstValuesProvider + LastValuesProvider + ValuesProvider + ValueFormatterProvider +} + +// PercentChangeSeries applies a +// percentage difference function to a given continuous series. +type PercentChangeSeries struct { + Name string + Style Style + YAxis YAxisType + InnerSeries PercentChangeSeriesSource +} + +// GetName returns the name of the time series. +func (pcs PercentChangeSeries) GetName() string { + return pcs.Name +} + +// GetStyle returns the line style. +func (pcs PercentChangeSeries) GetStyle() Style { + return pcs.Style +} + +// Len implements part of Series. +func (pcs PercentChangeSeries) Len() int { + return pcs.InnerSeries.Len() +} + +// GetFirstValues implements FirstValuesProvider. +func (pcs PercentChangeSeries) GetFirstValues() (x, y float64) { + return pcs.InnerSeries.GetFirstValues() +} + +// GetValues gets x, y values at a given index. +func (pcs PercentChangeSeries) GetValues(index int) (x, y float64) { + _, fy := pcs.InnerSeries.GetFirstValues() + x0, y0 := pcs.InnerSeries.GetValues(index) + x = x0 + y = PercentDifference(fy, y0) + return +} + +// GetValueFormatters returns value formatter defaults for the series. +func (pcs PercentChangeSeries) GetValueFormatters() (x, y ValueFormatter) { + x, _ = pcs.InnerSeries.GetValueFormatters() + y = PercentValueFormatter + return +} + +// GetYAxis returns which YAxis the series draws on. +func (pcs PercentChangeSeries) GetYAxis() YAxisType { + return pcs.YAxis +} + +// GetLastValues gets the last values. +func (pcs PercentChangeSeries) GetLastValues() (x, y float64) { + _, fy := pcs.InnerSeries.GetFirstValues() + x0, y0 := pcs.InnerSeries.GetLastValues() + x = x0 + y = PercentDifference(fy, y0) + return +} + +// Render renders the series. +func (pcs PercentChangeSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) { + style := pcs.Style.InheritFrom(defaults) + Draw.LineSeries(r, canvasBox, xrange, yrange, style, pcs) +} + +// Validate validates the series. +func (pcs PercentChangeSeries) Validate() error { + return pcs.InnerSeries.Validate() +} diff --git a/percent_change_series_test.go b/percent_change_series_test.go new file mode 100644 index 0000000..3114bb2 --- /dev/null +++ b/percent_change_series_test.go @@ -0,0 +1,35 @@ +package chart + +import ( + "testing" + + "github.com/blend/go-sdk/assert" +) + +func TestPercentageDifferenceSeries(t *testing.T) { + assert := assert.New(t) + + cs := ContinuousSeries{ + XValues: LinearRange(1.0, 10.0), + YValues: LinearRange(1.0, 10.0), + } + + pcs := PercentChangeSeries{ + Name: "Test Series", + InnerSeries: cs, + } + + assert.Equal("Test Series", pcs.GetName()) + assert.Equal(10, pcs.Len()) + x0, y0 := pcs.GetValues(0) + assert.Equal(1.0, x0) + assert.Equal(0, y0) + + xn, yn := pcs.GetValues(9) + assert.Equal(10.0, xn) + assert.Equal(9.0, yn) + + xn, yn = pcs.GetLastValues() + assert.Equal(10.0, xn) + assert.Equal(9.0, yn) +}