plot icon indicating copy to clipboard operation
plot copied to clipboard

How to LogScale in reverse?

Open kellabyte opened this issue 8 years ago • 12 comments

I have duration in seconds on the Y scale and percentages on the X scale but when I set LogScale I get the top and right parts of the graph squished. How can I log scale in reverse so the later values are higher resolution instead?

kellabyte avatar Oct 06 '16 19:10 kellabyte

That's not achievable in the general sense, at least not without further configuration. To do this you need to have a known upper bound, otherwise you are attempting to increase resolution as to also increase the size of the function range. Are you sure you really want to do this? Can you explain your end goal?

If you do have an upper bound, the trivial solution is to plot the difference from that upper bound, thus inverting the sign of your function. An alternative is to implement your own Normalizer and Ticker types that know your upper bound. To get that to work well, you will probably need to copy the plot.precisionOf and plot.formatFloatTick functions (maybe we should export them to aid this kind of endeavour.

kortschak avatar Oct 06 '16 21:10 kortschak

The log scale it does currently looks like this on the X axis and compresses the tail.

-----------------------------------------------
0                    30 |        50 |   70 | 90          

But when measuring latency, showing the 90-100 percentiles in greater detail is more important than 0-30 percentiles so I would rather something that compresses the head like this:

-----------------------------------------------
0 | 30 | 50    | 70        | 90                         

kellabyte avatar Oct 07 '16 01:10 kellabyte

Yeah, that makes sense. Either of the approaches I mention above would work for you.

kortschak avatar Oct 07 '16 01:10 kortschak

If you do have an upper bound, the trivial solution is to plot the difference from that upper bound, thus inverting the sign of your function.

Could you explain or give an example? I'm not sure I understand.

kellabyte avatar Oct 07 '16 02:10 kellabyte

The trivial approach is to convert the value you are plotting from a latency percentile one hundred minus the latency percentile (I can't think of a good name for this - which is probably a long-term argument against it). The alternative approach is to fork the code here and here to implement a Ticker and a Normalizer that does what you want. Actually, thinking more, you don't need the Ticker, since you can just use a ConstantTicks - then it's just the Normalizer, which is trivial. Something like this:

// ReverseLogScale can be used as the value of an Axis.Scale function to
// set the axis to a log scale.
type ReverseLogScale struct{}

// Normalize returns the fractional logarithmic distance of
// x between min and max.
func (ReverseLogScale) Normalize(min, max, x float64) float64 {
    logMin := math.Log(min)
    return 1 - ((math.Log(max-x) - logMin) / (math.Log(max) - logMin))
}

Demonstrated here.

kortschak avatar Oct 07 '16 03:10 kortschak

Oh interesting, thank you! Although when I run this with the plotter the process never completes. It must be causing some endless loop I'm suspecting.

kellabyte avatar Oct 07 '16 03:10 kellabyte

Try with an explicit 100 for the uses of max in Normalize, or set the axis max to 100.

kortschak avatar Oct 07 '16 03:10 kortschak

It exits now correctly but there's no values or ticks along the axis and there's no visible line drawn.

kellabyte avatar Oct 07 '16 04:10 kellabyte

Debugging code remotely without being able to see it is sort of tricky. If you can't sort this out, you should probably put it up somewhere for people to look at.

kortschak avatar Oct 07 '16 04:10 kortschak

Making a plot with unusual axis scaling may be more confusing than helpful for the audience anyway. Another option could be to make two plots and put them side-by-side, where one plot has an axis spanning 0-100 percentile, and the other plot has an axis spanning 90-100 or whatever. To make multiple plots in one image you can use draw.Tiles{}.

ctessum avatar Oct 07 '16 15:10 ctessum

I've seen this kind of scaling in this domain in the past, so I think this is a perfectly reasonable thing to do.

I am interested in seeing why this is not working though (and investigating the previous non-termination behaviour). To look into those I need a minimal reproducer.

kortschak avatar Oct 07 '16 23:10 kortschak

This is an example of what I'm talking about:

https://twitter.com/benalexau/status/790782407301435392

kellabyte avatar Oct 26 '16 05:10 kellabyte