patch: prevent overlapping axis labels

1 view
Skip to first unread message

Matt Brown

unread,
Oct 21, 2010, 3:22:25 PM10/21/10
to haskell...@googlegroups.com
Hi all,

I've been playing around with timeplot, and found that sometimes x-axis labels overlap each other.  I've attached a patch to renderAxis to prevent this.


Before drawing a label, it ensures the label's "draw rectangle" would not overlap with that of of the last drawn label.  

A few questions:
1) Does this already exist elsewhere?  I'm very new to chart; wouldn't be surprised if I missed it.
2) Is it appropriate to hard code label overlap prevention into renderAxis?  Is it something everyone would always want?  Would it be better to add a flag somewhere (perhaps AxisStyle)?
3) I'm not confident in my implementations of yBounds.  I'm treating VTA_BaseLine as equivalent to VTA_Bottom, which I expect is wrong.

Any suggestions are welcome!

-matt

Note:  the examples were generated from:
tplot -o /tmp/biglog.png -or 250x960 -k 'GET.*' 'quantile 300 0.25,0.5,0.75' -k 'Cache/.*' 'freq 300 stacked' -k Cache 'freq 300 stacked' -k Reload event -k Page 'freq 300 stacked' -if /tmp/Program.trace -fromTime '2009-10-23 08:50:00' -toTime '2009-10-23 10:00:00'

prevent_overlapping_labels.dpatch

Malcolm Wallace

unread,
Oct 21, 2010, 5:44:14 PM10/21/10
to haskell...@googlegroups.com

On 21 Oct 2010, at 20:22, Matt Brown wrote:
> I've been playing around with timeplot, and found that sometimes x-
> axis labels overlap each other. I've attached a patch to renderAxis
> to prevent this.

Hey, this is a cool idea. I recently reworked the axis-label code for
time axes, in some sort of attempt to ensure there were never too many
(or too few) labels. But my decisions were based purely on the ranges
of data points, not on the space physically available (which changes
depending on how small or large you render the whole layout).
Automatically eliding labels that overlap makes the chart look slicker
at all sizes. This may even permit the existing code in Graphics/
Rendering/Chart/Axis/LocalTime.hs to become a bit freer in assigning
more labels, confident in the knowledge that renderAxis will will tidy
up any resulting clutter.

> 3) I'm not confident in my implementations of yBounds. I'm treating
> VTA_BaseLine as equivalent to VTA_Bottom, which I expect is wrong.

I think you probably want to use the properties "fontExtentsAscent"
etc, as in the code for drawTextR nearby:

yadj VTA_Top te fe = C.fontExtentsAscent fe
yadj VTA_Centre te fe = - (C.textExtentsYbearing te) / 2
yadj VTA_BaseLine te fe = 0
yadj VTA_Bottom te fe = -(C.fontExtentsDescent fe)

Regards,
Malcolm

Matt Brown

unread,
Oct 22, 2010, 4:02:18 AM10/22/10
to haskell...@googlegroups.com

Hey, this is a cool idea.  

Thanks!
 
I recently reworked the axis-label code for time axes, in some sort of attempt to ensure there were never too many (or too few) labels.  

I noticed the improvement: after pulling from darcs the labels didn't overlap in my error case anymore.  Had to tweak it to get them to again :)
 
I think you probably want to use the properties "fontExtentsAscent" etc, as in the code for drawTextR nearby:

Thanks for the tip.  I rewrote axisLabelRect (now Graphics.Rendering.Chart.textDrawRect) using drawTextR as a guide.  Patch attached.

-matt

prevent_overlapping_labels2.dpatch

Tim Docker

unread,
Oct 23, 2010, 6:58:09 AM10/23/10
to haskell...@googlegroups.com
I agree that this is a good idea. It's nice how the labels get
added/removed dynamically as the chart size is adjusted.

I wonder if it might look better if it worked such that labels were
hidden consistently across the axis, rather than testing each one as we
draw them. ie we first consider all the labels, and if there are no
overlaps, draw them. If there are overlaps, then consider taking just
every second label. If that still has overlaps, take every third label, etc.


Tim

Matt Brown

unread,
Oct 23, 2010, 1:29:07 PM10/23/10
to haskell...@googlegroups.com

I wonder if it might look better if it worked such that labels were hidden consistently across the axis, rather than testing each one as we draw them. ie we first consider all the labels, and if there are no overlaps, draw them. If there are overlaps, then consider taking just every second label. If that still has overlaps, take every third label, etc.
 
This does seem like a better way.  Here's another patch that implements it, and also prevents overlapping axis_context_ labels.

Also included is a new attempt to prevent the labels from being too close to each other, by requiring some horizontal buffer between them.  Any ideas how best to set a reasonable buffer size for variable graph and label sizes?  As a start I'm simply extending each label's draw rectangle by 50%.  It looks nice for my example, but the labels are all pretty much the same width.  Perhaps a buffer based on the average label width would be better?

-matt
prevent_overlapping_labels3.dpatch

Tim Docker

unread,
Oct 24, 2010, 9:53:58 PM10/24/10
to haskell...@googlegroups.com
Hi Matt,


I wonder if it might look better if it worked such that labels were hidden consistently across the axis, rather than testing each one as we draw them. ie we first consider all the labels, and if there are no overlaps, draw them. If there are overlaps, then consider taking just every second label. If that still has overlaps, take every third label, etc.
 
This does seem like a better way.  Here's another patch that implements it, and also prevents overlapping axis_context_ labels.

This seems to work nicely. I've pushed the 4 patches. Thanks!

It actually overlaps with a change I am working on to remove the context labels, and just make labels a list of lists (ie so that we support multiple layers of context). It's probably not that useful, but does simplify the code a bit.


Also included is a new attempt to prevent the labels from being too close to each other, by requiring some horizontal buffer between them.  Any ideas how best to set a reasonable buffer size for variable graph and label sizes?  As a start I'm simply extending each label's draw rectangle by 50%.  It looks nice for my example, but the labels are all pretty much the same width.  Perhaps a buffer based on the average label width would be better?

What you've done so far works pretty well for my examples too - I'm happy to consider something more complex if we need it.

Prior to a release I still plan to:

      - include my multi-layer labels patch
      - include Eugene K's patches to allow time labels to be align on the ticks or at the interval centres.

Tim

Reply all
Reply to author
Forward
0 new messages