From ce111655c5474f001bc3aaaaa6865460110cdc01 Mon Sep 17 00:00:00 2001 From: Alexandre Bourget Date: Mon, 12 Sep 2016 11:19:50 -0400 Subject: [PATCH 1/3] Implemented an AutoUnixTimeTicks, which should probably be the default eventually. It allows configurability of density of ticks with the `Width`, and aims to be legible on a per-inch basis. Normally, if you set Width to be the same width you render the graph with, things should look good. --- axis.go | 153 ++++++++++++++++++++++++++++++++++++++++++++ axis_test.go | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 330 insertions(+) diff --git a/axis.go b/axis.go index 4eacdd78..52669851 100644 --- a/axis.go +++ b/axis.go @@ -7,6 +7,7 @@ package plot import ( "image/color" "math" + "os" "strconv" "time" @@ -497,6 +498,158 @@ func (utt UnixTimeTicks) Ticks(min, max float64) []Tick { return ticks } +// AutoUnixTimeTicks is suitable for axes representing time values. +// AutoUnixTimeTicks expects values in Unix time seconds. It will +// adjust the number of ticks according to the specified Width. If +// not specified, Width defaults to 4 inches. +type AutoUnixTimeTicks struct { + // Width is the width of the underlying graph, used to calculate + // the number of ticks that can fit properly with their time + // shown. + Width vg.Length +} + +var _ Ticker = AutoUnixTimeTicks{} + +// Inspired by https://github.com/d3/d3-scale/blob/master/src/time.js +var tickIntervals = []tickRule{ + {time.Millisecond, + "15:04:05.000", "15:04:05", ".000", time.Millisecond}, + {200 * time.Millisecond, + "15:04:05.000", "15:04:05", ".000", 200 * time.Millisecond}, + {500 * time.Millisecond, + "15:04:05.000", "15:04:05", ".000", 500 * time.Millisecond}, + {time.Second, + "15:04:05", "15:04", ":05", time.Second}, + {2 * time.Second, + "15:04:05", "15:04", ":05", 2 * time.Second}, + {5 * time.Second, + "15:04:05", "15:04", ":05", 5 * time.Second}, + {15 * time.Second, + "Jan 02, 15:04", "Jan 02", "15:04", 15 * time.Second}, + {30 * time.Second, + "15:04:05", "15:04", ":05", 30 * time.Second}, + {time.Minute, + "15:04:05", "15:04", ":05", time.Minute}, + {2 * time.Minute, + "Jan 02, 3:04pm", "Jan 02", "3:04pm", 2 * time.Minute}, + {5 * time.Minute, + "Jan 02, 3:04pm", "Jan 02", "3:04pm", 5 * time.Minute}, + {15 * time.Minute, + "Jan 02, 3:04pm", "Jan 02", "3:04pm", 15 * time.Minute}, + {30 * time.Minute, + "Jan 02, 3:04pm", "Jan 02", "3:04pm", 30 * time.Minute}, + {time.Hour, + "Jan 2, 3pm", "Jan 2", "3pm", time.Hour}, + {3 * time.Hour, + "Jan 2, 3pm", "Jan 2", "3pm", 3 * time.Hour}, + {6 * time.Hour, + "Jan 2, 3pm", "Jan 2", "3pm", 6 * time.Hour}, + {12 * time.Hour, + "Jan 2", "Jan 2", "3pm", 12 * time.Hour}, + {24 * time.Hour, + "Jan 2", "Jan", "2", 24 * time.Hour}, + {48 * time.Hour, + "Jan 2", "Jan", "2", 48 * time.Hour}, + {7 * 24 * time.Hour, + "Jan 2", "Jan", "2", 7 * 24 * time.Hour}, + {aMonth, // 1 month + "Jan 2006", "2006", "Jan", aMonth}, + {3 * aMonth, // 3 months + "Jan 2006", "2006", "Jan", 3 * aMonth}, + {6 * aMonth, // 6 months + "Jan 2006", "2006", "Jan", 6 * aMonth}, + {12 * aMonth, // 1 year + "2006", "", "2006", 12 * aMonth}, + {2 * 12 * aMonth, // 2 years + "2006", "", "2006", 2 * 12 * aMonth}, + {5 * 12 * aMonth, // 5 years + "2006", "", "2006", 5 * 12 * aMonth}, + {10 * 12 * aMonth, // 10 years + "2006", "", "2006", 10 * 12 * aMonth}, +} + +var aMonth = 31 * 24 * time.Hour + +type tickRule struct { + DurationPerInch time.Duration // use this rule for a maximum Duration per inch + LongFormat string // longer format + WatchFormat string // show long format when WatchFormat changes between ticks + ShortFormat string // incremental format, shorter + TimeWindow time.Duration // interval for ticks +} + +// Ticks implements plot.Ticker. +func (t AutoUnixTimeTicks) Ticks(min, max float64) []Tick { + width := t.Width + if width == 0 { + width = 4 * vg.Inch + } + + minT := time.Unix(int64(min), 0).UTC() + maxT := time.Unix(int64(max), 0).UTC() + durationPerInch := maxT.Sub(minT) / time.Duration(width/vg.Inch) + + rule := tickIntervals[len(tickIntervals)-1] + for idx := range tickIntervals[:len(tickIntervals)-1] { + if durationPerInch < tickIntervals[idx+1].DurationPerInch { + rule = tickIntervals[idx] + break + } + } + + ticks := []Tick{ + // {Value: min, Label: minT.Format(rule.BeginFormat)}, + } + + monthsDelta := time.Month(rule.TimeWindow / aMonth) + + //fmt.Println("Months delta", int(monthsDelta)) + start := minT.Truncate(rule.TimeWindow) + count := 0 + lastWatch := "" + for { + count++ + if monthsDelta > 0 { + // Count in Months now + start = time.Date(start.Year(), start.Month()+monthsDelta, 1, 0, 0, 0, 0, time.UTC) + } else { + start = start.Add(rule.TimeWindow) + } + + if count > 20 { + os.Exit(0) + } + + if start.Before(minT) { + continue + } + if start.After(maxT) { + break + } + + label := "" + newWatch := start.Format(rule.WatchFormat) + if lastWatch == newWatch { + label = start.Format(rule.ShortFormat) + } else { + //TODO: overwrite the first tick with the long form if we + //haven't shown a lonform at all.. instead of always + //showing the longform first. + label = start.Format(rule.LongFormat) + } + lastWatch = newWatch + + ticks = append(ticks, Tick{ + Value: float64(start.UnixNano()) / float64(time.Second), + Label: label, + }) + + } + + return ticks +} + // A Tick is a single tick mark on an axis. type Tick struct { // Value is the data value marked by this Tick. diff --git a/axis_test.go b/axis_test.go index 32f49b2f..1d7dbfa1 100644 --- a/axis_test.go +++ b/axis_test.go @@ -5,9 +5,13 @@ package plot import ( + "fmt" "math" "reflect" "testing" + "time" + + "github.com/gonum/plot/vg" ) func TestAxisSmallTick(t *testing.T) { @@ -59,3 +63,176 @@ func labelsOf(ticks []Tick) []string { } return labels } + +func allLabelsOf(ticks []Tick) []string { + var labels []string + for _, t := range ticks { + labels = append(labels, t.Label) + } + return labels +} + +func TestAutoUnixTimeTicks(t *testing.T) { + d := AutoUnixTimeTicks{Width: 4 * vg.Inch} + for _, test := range []struct { + min, max string + want []string + }{ + { + min: "2016-01-01 12:56:30", + max: "2016-01-01 12:56:31", + want: []string{"12:56:30.200", ".400", ".600", ".800", "12:56:31.000"}, + }, + { + min: "2016-01-01 12:56:01", + max: "2016-01-01 12:56:59", + want: []string{"12:56:05", ":10", ":15", ":20", ":25", ":30", ":35", ":40", ":45", ":50", ":55"}, + }, + { + min: "2016-01-01 12:56:30", + max: "2016-01-01 12:57:29", + want: []string{"12:56:35", ":40", ":45", ":50", ":55", "12:57:00", ":05", ":10", ":15", ":20", ":25"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 12:07:00", + want: []string{"12:02:00", "12:03:00", "12:04:00", "12:05:00", "12:06:00", "12:07:00"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 12:17:00", + want: []string{"Jan 01, 12:02pm", "12:04pm", "12:06pm", "12:08pm", "12:10pm", "12:12pm", "12:14pm", "12:16pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 12:28:00", + want: []string{"Jan 01, 12:05pm", "12:10pm", "12:15pm", "12:20pm", "12:25pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 12:35:00", + want: []string{"Jan 01, 12:05pm", "12:10pm", "12:15pm", "12:20pm", "12:25pm", "12:30pm", "12:35pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 12:40:00", + want: []string{"Jan 01, 12:05pm", "12:10pm", "12:15pm", "12:20pm", "12:25pm", "12:30pm", "12:35pm", "12:40pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 12:45:00", + want: []string{"Jan 01, 12:05pm", "12:10pm", "12:15pm", "12:20pm", "12:25pm", "12:30pm", "12:35pm", "12:40pm", "12:45pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 13:05:00", + want: []string{"Jan 01, 12:15pm", "12:30pm", "12:45pm", "1:00pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 13:05:00", + want: []string{"Jan 01, 12:15pm", "12:30pm", "12:45pm", "1:00pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-01 16:05:00", + want: []string{"Jan 1, 1pm", "2pm", "3pm", "4pm"}, + }, + { + min: "2016-01-01 20:01:05", + max: "2016-01-02 07:59:00", + want: []string{"Jan 1, 9pm", "10pm", "11pm", "Jan 2, 12am", "1am", "2am", "3am", "4am", "5am", "6am", "7am"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-02 13:59:00", + want: []string{"Jan 1, 6pm", "Jan 2, 12am", "6am", "12pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-04 13:59:00", + want: []string{"Jan 2", "12pm", "Jan 3", "12pm", "Jan 4", "12pm"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-06 13:59:00", + want: []string{"Jan 2", "3", "4", "5", "6"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-09 13:59:00", + want: []string{"Jan 2", "4", "6", "8"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-01-25 13:59:00", + want: []string{"Jan 2", "4", "6", "8", "10", "12", "14", "16", "18", "20", "22", "24"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-02-06 13:59:00", + want: []string{"Jan 4", "11", "18", "25", "Feb 1"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-02-28 13:59:00", + want: []string{"Jan 4", "11", "18", "25", "Feb 1", "8", "15", "22"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-04-28 13:59:00", + want: []string{"Jan 4", "11", "18", "25", "Feb 1", "8", "15", "22", "29", "Mar 7", "14", "21", "28", "Apr 4", "11", "18", "25"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-09-28 13:59:00", + want: []string{"Feb 2016", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2016-12-28 13:59:00", + want: []string{"Feb 2016", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2017-02-28 13:59:00", + want: []string{"Feb 2016", "May", "Aug", "Nov", "Feb 2017"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2017-08-28 13:59:00", + want: []string{"Feb 2016", "May", "Aug", "Nov", "Feb 2017", "May", "Aug"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2018-08-28 13:59:00", + want: []string{"Feb 2016", "Aug", "Feb 2017", "Aug", "Feb 2018", "Aug"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2020-08-28 13:59:00", + want: []string{"2016", "2017", "2018", "2019", "2020"}, + }, + { + min: "2016-01-01 12:01:05", + max: "2048-08-28 13:59:00", + want: []string{"2017", "2022", "2027", "2032", "2037", "2042", "2047"}, + }, + } { + fmt.Println("For dates", test.min, test.max) + ticks := d.Ticks(dateToFloat64(test.min), dateToFloat64(test.max)) + got := allLabelsOf(ticks) + if !reflect.DeepEqual(got, test.want) { + t.Errorf("tick labels mismatch:\ndate1: %s\ndate2: %s\ngot: %#v\nwant:%q", test.min, test.max, got, test.want) + } + } +} + +func dateToFloat64(date string) float64 { + t, err := time.Parse("2006-01-02 15:04:05", date) + if err != nil { + panic(err) + } + + return float64(t.UTC().UnixNano()) / float64(time.Second) +} From 7832dacc5d15f07ae80fdb564ef2b69d61e81f49 Mon Sep 17 00:00:00 2001 From: Alexandre Bourget Date: Wed, 28 Sep 2016 22:38:53 -0400 Subject: [PATCH 2/3] Updated to take comments into account. Simplified rules as timeWindow and durationPerInch were exactly the same in our implementation (it differed in d3's implementation, but we got rid of those diffs). --- axis.go | 162 +++++++++++++++++++++------------------------------ axis_test.go | 3 +- 2 files changed, 67 insertions(+), 98 deletions(-) diff --git a/axis.go b/axis.go index 52669851..8f7f66ba 100644 --- a/axis.go +++ b/axis.go @@ -7,7 +7,6 @@ package plot import ( "image/color" "math" - "os" "strconv" "time" @@ -512,113 +511,85 @@ type AutoUnixTimeTicks struct { var _ Ticker = AutoUnixTimeTicks{} // Inspired by https://github.com/d3/d3-scale/blob/master/src/time.js -var tickIntervals = []tickRule{ - {time.Millisecond, - "15:04:05.000", "15:04:05", ".000", time.Millisecond}, - {200 * time.Millisecond, - "15:04:05.000", "15:04:05", ".000", 200 * time.Millisecond}, - {500 * time.Millisecond, - "15:04:05.000", "15:04:05", ".000", 500 * time.Millisecond}, - {time.Second, - "15:04:05", "15:04", ":05", time.Second}, - {2 * time.Second, - "15:04:05", "15:04", ":05", 2 * time.Second}, - {5 * time.Second, - "15:04:05", "15:04", ":05", 5 * time.Second}, - {15 * time.Second, - "Jan 02, 15:04", "Jan 02", "15:04", 15 * time.Second}, - {30 * time.Second, - "15:04:05", "15:04", ":05", 30 * time.Second}, - {time.Minute, - "15:04:05", "15:04", ":05", time.Minute}, - {2 * time.Minute, - "Jan 02, 3:04pm", "Jan 02", "3:04pm", 2 * time.Minute}, - {5 * time.Minute, - "Jan 02, 3:04pm", "Jan 02", "3:04pm", 5 * time.Minute}, - {15 * time.Minute, - "Jan 02, 3:04pm", "Jan 02", "3:04pm", 15 * time.Minute}, - {30 * time.Minute, - "Jan 02, 3:04pm", "Jan 02", "3:04pm", 30 * time.Minute}, - {time.Hour, - "Jan 2, 3pm", "Jan 2", "3pm", time.Hour}, - {3 * time.Hour, - "Jan 2, 3pm", "Jan 2", "3pm", 3 * time.Hour}, - {6 * time.Hour, - "Jan 2, 3pm", "Jan 2", "3pm", 6 * time.Hour}, - {12 * time.Hour, - "Jan 2", "Jan 2", "3pm", 12 * time.Hour}, - {24 * time.Hour, - "Jan 2", "Jan", "2", 24 * time.Hour}, - {48 * time.Hour, - "Jan 2", "Jan", "2", 48 * time.Hour}, - {7 * 24 * time.Hour, - "Jan 2", "Jan", "2", 7 * 24 * time.Hour}, - {aMonth, // 1 month - "Jan 2006", "2006", "Jan", aMonth}, - {3 * aMonth, // 3 months - "Jan 2006", "2006", "Jan", 3 * aMonth}, - {6 * aMonth, // 6 months - "Jan 2006", "2006", "Jan", 6 * aMonth}, - {12 * aMonth, // 1 year - "2006", "", "2006", 12 * aMonth}, - {2 * 12 * aMonth, // 2 years - "2006", "", "2006", 2 * 12 * aMonth}, - {5 * 12 * aMonth, // 5 years - "2006", "", "2006", 5 * 12 * aMonth}, - {10 * 12 * aMonth, // 10 years - "2006", "", "2006", 10 * 12 * aMonth}, -} - -var aMonth = 31 * 24 * time.Hour - +var tickRules = []tickRule{ + {time.Millisecond, "15:04:05.000", "15:04:05", ".000"}, + {200 * time.Millisecond, "15:04:05.000", "15:04:05", ".000"}, + {500 * time.Millisecond, "15:04:05.000", "15:04:05", ".000"}, + {time.Second, "15:04:05", "15:04", ":05"}, + {2 * time.Second, "15:04:05", "15:04", ":05"}, + {5 * time.Second, "15:04:05", "15:04", ":05"}, + {15 * time.Second, "Jan 02, 15:04", "Jan 02", "15:04"}, + {30 * time.Second, "15:04:05", "15:04", ":05"}, + {time.Minute, "15:04:05", "15:04", ":05"}, + {2 * time.Minute, "Jan 02, 3:04pm", "Jan 02", "3:04pm"}, + {5 * time.Minute, "Jan 02, 3:04pm", "Jan 02", "3:04pm"}, + {15 * time.Minute, "Jan 02, 3:04pm", "Jan 02", "3:04pm"}, + {30 * time.Minute, "Jan 02, 3:04pm", "Jan 02", "3:04pm"}, + {time.Hour, "Jan 2, 3pm", "Jan 2", "3pm"}, + {3 * time.Hour, "Jan 2, 3pm", "Jan 2", "3pm"}, + {6 * time.Hour, "Jan 2, 3pm", "Jan 2", "3pm"}, + {12 * time.Hour, "Jan 2", "Jan 2", "3pm"}, + {24 * time.Hour, "Jan 2", "Jan", "2"}, + {48 * time.Hour, "Jan 2", "Jan", "2"}, + {7 * 24 * time.Hour, "Jan 2", "Jan", "2"}, + {month, "Jan 2006", "2006", "Jan"}, + {3 * month, "Jan 2006", "2006", "Jan"}, + {6 * month, "Jan 2006", "2006", "Jan"}, + {12 * month, "2006", "", "2006"}, + {2 * year, "2006", "", "2006"}, + {5 * year, "2006", "", "2006"}, + {10 * year, "2006", "", "2006"}, +} + +const month = 31 * 24 * time.Hour +const year = 12 * month + +// tickRule defines a time display format for a given time window (per +// inch). +// +// This assumes a tick about each `durationPerInch`. The long format is +// shown each time the timestamp goes over a certain boundary +// (verified through `watchFormat`). This way you can show `Sep 2, +// 12pm` when you pass midnight after `11pm` on `Sep 1`. type tickRule struct { - DurationPerInch time.Duration // use this rule for a maximum Duration per inch - LongFormat string // longer format - WatchFormat string // show long format when WatchFormat changes between ticks - ShortFormat string // incremental format, shorter - TimeWindow time.Duration // interval for ticks + durationPerInch time.Duration // use this rule for a maximum Duration per inch, it is also used as an interval per ticks. + longFormat string // longer format + watchFormat string // show long format when watchFormat changes between ticks + shortFormat string // incremental format, shorter } -// Ticks implements plot.Ticker. +// Ticks implements plot.Ticker and displays appropriately spaced and +// formatted time labels. func (t AutoUnixTimeTicks) Ticks(min, max float64) []Tick { width := t.Width if width == 0 { - width = 4 * vg.Inch + width = 10 * vg.Centimeter } minT := time.Unix(int64(min), 0).UTC() maxT := time.Unix(int64(max), 0).UTC() durationPerInch := maxT.Sub(minT) / time.Duration(width/vg.Inch) - rule := tickIntervals[len(tickIntervals)-1] - for idx := range tickIntervals[:len(tickIntervals)-1] { - if durationPerInch < tickIntervals[idx+1].DurationPerInch { - rule = tickIntervals[idx] + lastElement := len(tickRules) - 1 + rule := tickRules[lastElement] + for idx, tickRule := range tickRules[:lastElement] { + if durationPerInch < tickRules[idx+1].durationPerInch { + rule = tickRule break } } - ticks := []Tick{ - // {Value: min, Label: minT.Format(rule.BeginFormat)}, - } - - monthsDelta := time.Month(rule.TimeWindow / aMonth) - - //fmt.Println("Months delta", int(monthsDelta)) - start := minT.Truncate(rule.TimeWindow) - count := 0 - lastWatch := "" + timeWindow := rule.durationPerInch + delta := time.Month(timeWindow / month) // in months + start := minT.Truncate(timeWindow) + var lastWatch string + var ticks []Tick for { - count++ - if monthsDelta > 0 { + if delta > 0 { // Count in Months now - start = time.Date(start.Year(), start.Month()+monthsDelta, 1, 0, 0, 0, 0, time.UTC) + start = time.Date(start.Year(), start.Month()+delta, 1, 0, 0, 0, 0, time.UTC) } else { - start = start.Add(rule.TimeWindow) - } - - if count > 20 { - os.Exit(0) + start = start.Add(timeWindow) } if start.Before(minT) { @@ -628,15 +599,15 @@ func (t AutoUnixTimeTicks) Ticks(min, max float64) []Tick { break } - label := "" - newWatch := start.Format(rule.WatchFormat) + var label string + newWatch := start.Format(rule.watchFormat) if lastWatch == newWatch { - label = start.Format(rule.ShortFormat) + label = start.Format(rule.shortFormat) } else { //TODO: overwrite the first tick with the long form if we - //haven't shown a lonform at all.. instead of always - //showing the longform first. - label = start.Format(rule.LongFormat) + // haven't shown a lonform at all.. instead of always + // showing the longform first. + label = start.Format(rule.longFormat) } lastWatch = newWatch @@ -644,7 +615,6 @@ func (t AutoUnixTimeTicks) Ticks(min, max float64) []Tick { Value: float64(start.UnixNano()) / float64(time.Second), Label: label, }) - } return ticks diff --git a/axis_test.go b/axis_test.go index 1d7dbfa1..3263529b 100644 --- a/axis_test.go +++ b/axis_test.go @@ -5,7 +5,6 @@ package plot import ( - "fmt" "math" "reflect" "testing" @@ -219,7 +218,7 @@ func TestAutoUnixTimeTicks(t *testing.T) { want: []string{"2017", "2022", "2027", "2032", "2037", "2042", "2047"}, }, } { - fmt.Println("For dates", test.min, test.max) + //fmt.Println("For dates", test.min, test.max) ticks := d.Ticks(dateToFloat64(test.min), dateToFloat64(test.max)) got := allLabelsOf(ticks) if !reflect.DeepEqual(got, test.want) { From d772503da8038c7bc95f9db8dd9a9c4f01ba016f Mon Sep 17 00:00:00 2001 From: Alexandre Bourget Date: Wed, 28 Sep 2016 22:40:37 -0400 Subject: [PATCH 3/3] Renamed AutoUnixTimeTicks to TimeTicks. --- axis.go | 12 ++++++------ axis_test.go | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/axis.go b/axis.go index 8f7f66ba..3c329e7b 100644 --- a/axis.go +++ b/axis.go @@ -497,18 +497,18 @@ func (utt UnixTimeTicks) Ticks(min, max float64) []Tick { return ticks } -// AutoUnixTimeTicks is suitable for axes representing time values. -// AutoUnixTimeTicks expects values in Unix time seconds. It will +// TimeTicks is suitable for axes representing time values. +// TimeTicks expects values in Unix time seconds. It will // adjust the number of ticks according to the specified Width. If -// not specified, Width defaults to 4 inches. -type AutoUnixTimeTicks struct { +// not specified, Width defaults to 10 centimeters. +type TimeTicks struct { // Width is the width of the underlying graph, used to calculate // the number of ticks that can fit properly with their time // shown. Width vg.Length } -var _ Ticker = AutoUnixTimeTicks{} +var _ Ticker = TimeTicks{} // Inspired by https://github.com/d3/d3-scale/blob/master/src/time.js var tickRules = []tickRule{ @@ -560,7 +560,7 @@ type tickRule struct { // Ticks implements plot.Ticker and displays appropriately spaced and // formatted time labels. -func (t AutoUnixTimeTicks) Ticks(min, max float64) []Tick { +func (t TimeTicks) Ticks(min, max float64) []Tick { width := t.Width if width == 0 { width = 10 * vg.Centimeter diff --git a/axis_test.go b/axis_test.go index 3263529b..970a4f9f 100644 --- a/axis_test.go +++ b/axis_test.go @@ -71,8 +71,8 @@ func allLabelsOf(ticks []Tick) []string { return labels } -func TestAutoUnixTimeTicks(t *testing.T) { - d := AutoUnixTimeTicks{Width: 4 * vg.Inch} +func TestTimeTicks(t *testing.T) { + d := TimeTicks{Width: 4 * vg.Inch} for _, test := range []struct { min, max string want []string