plot
plot copied to clipboard
How to LogScale in reverse?
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?
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.
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
Yeah, that makes sense. Either of the approaches I mention above would work for you.
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.
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.
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.
Try with an explicit 100 for the uses of max in Normalize, or set the axis max to 100.
It exits now correctly but there's no values or ticks along the axis and there's no visible line drawn.
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.
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{}.
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.
This is an example of what I'm talking about:
https://twitter.com/benalexau/status/790782407301435392