gonum / plot

A repository for plotting and visualizing data
BSD 3-Clause "New" or "Revised" License
2.74k stars 203 forks source link

Default labeling for X axis in timeseries is sparse. #296

Open zaddok opened 8 years ago

zaddok commented 8 years ago

When you render a timeseries, no matter how wide you render it, there are only three labels (dates) drawn on the x axis. Probably should include more by default. (Is there any way to change this programatically?)

deadlift

btracey commented 8 years ago

I agree with the general issue -- the algorithm for selecting tick labels could be better. For real numbers it could do a much better job of trying to find powers of 10 and other round numbers.

kortschak commented 8 years ago

@zaddok the distribution of ticks is not dependent on the spatial arrangement of the axis, but rather only the numerical span of the axis. You can see this here. You can see here how changing the start and end dates impact on the tick locations.

Remember that DefaultTicks is just that, a default. Maybe we should have a better heuristic with more knobs, but I think that we will probably still keep an extremely simple default as exists now.

zaddok commented 8 years ago

Thanks! I do strongly agree with the general principle of keeping code as simple as possible. I'll propose my reasons for the idea that, in this case, it may be warranted to improve the default behaviour:

  1. If the default behaviour is to create a graph that no-one would ever want, perhaps the default is not adequate.
  2. The default behaviour is possibly not user friendly for people new to the library. It would be more user friendly if the built in behaviour works out of the box. Although this could be mitigated by improving the example code for timeseries in the documentation.

Anyway, the tool is awesome either way. You guys have done some great work. This is just my feedback/reaction to the tool as a new user.

kortschak commented 8 years ago

Yeah, you are right. The timeseries (and indeed ticks in general) have PRs for changing behaviour that should make things better.

zaddok commented 8 years ago

Aaah great, I'll have a look at the PR's.

Im still learning the code, my initial reaction however, is that perhaps the SuggestedTicks in the default ticker:

func (DefaultTicks) Ticks(min, max float64) (ticks []Tick) {
   const SuggestedTicks = 3

could be exposed, so that it could be initialised like this:

p.X.Tick.Marker = plot.UnixTimeTicks{Format: "Jan 2", SuggestedTicks: 5}
zaddok commented 8 years ago

Furthermore, I am wondering, Would it be worth submitting a patch for a different ticker options, i.e. MonthlyTimeTicks, or WeeklyTimeTicks.

I'm going to do it anyway, just not sure if people would be receptive to receiving it into the main code. How many people using this library, do we think would have to go ahead and roll their own MonthlyTimeTicks, or WeeklyTimeTicks variants?

kortschak commented 8 years ago

They sound reasonable to me.

eaburns commented 8 years ago

The issue isn't the number of labels, but label density. Having too many labels in little space makes the plot very noisy (for example look at the y-axis in the plot on the original post here). Having too few makes it hard to comprehend the scale (the x-axis of the same plot).

The underlying problem here is that the ticker code doesn't know the final size of the plot. If it did, it would select the number of ticks and the number of labels based on the density. (I think Tufty has recommendations for tick density. We should check.)

The current algorithm is based off an algorithm that I hand-tuned a long time ago when I was interested in 3in x 3in plots for two-column academic papers. I certainly wouldn't say that it is a useless default; it's just not tuned for large plots. That is why I made the tick selection code configurable. More generally, this is why I made lots of things configurable (ticks, vg backbends, plotters, etc.): it's not possible to provide defaults that everyone will like.

That said, if there is a better default, let's use it.

zaddok commented 8 years ago

I'be created my own alternative to the built in unix time series. I'll submit it tomorrow with some sample images to see if people like it. I suspect it'll fill a use case for others as well, if useful then great, if not, no worries.

(And yes, code to measure the widths of the labels would be ideal, but That's no small amount of work for me.)

henryx commented 7 years ago

Hi. Any hints for this?

Student414 commented 4 years ago
// MyTicks 自定义Ticks
type MyTicks struct{}

// Ticks returns Ticks in the specified range.
func (MyTicks) Ticks(min, max float64) []plot.Tick {
    if max <= min {
        panic("illegal range")
    }
    var ticks []plot.Tick
    for i := min; i <= max; i++ {
        ticks = append(ticks, plot.Tick{Value: i, Label: strconv.FormatFloat(i, 'f', 0, 64)})
    }
    return ticks
}
.....
p.X.Tick.Marker = MyTicks{}
sbinet commented 4 years ago

FYI, I have also another Ticker implementation, here:

with a plot comparing gonum/plot default ticker with "mine":