[reportlab-users] Set verticalbarchart label x, y positions depending on value

Kostadin Atanasov kostadin.atanasov at gmail.com
Mon Aug 20 16:48:47 EDT 2018

I usually calculate the value of each series (segment in the bar) as a % of the max Y scale value and use it to decide whether to display the label at all (the label is still in absolute units, the % is only for decision). My cutoff is around 3 or 4%. Typically if the value is so low nobody is very worried that the label is missing. If you have many cases of values below 4% this means that your bar is very fragmented - then you have a different problem - probably bar is not the best visualisation.

Kostadin Atanasov

From: reportlab-users <reportlab-users-bounces at lists2.reportlab.com> on behalf of Robin Becker <robin at reportlab.com>
Sent: Monday, August 20, 2018 5:38:10 PM
To: reportlab-users
Subject: Re: [reportlab-users] Set verticalbarchart label x, y positions depending on value

On 18/08/2018 00:14, Matt Bartolome wrote:
> Hi, I have a stacked vertical bar chart where I need to either manually
> place labels or iterate over the existing labels and move them based on
> their position (crossing my fingers that there is a simpler way). The
> problem I have is that my stacked bar chart has overlapping labels when the
> y values are close to zero because of the scale of my chart.
> My barLabels settings are like so:
> self.chart.barLabelFormat = lambda x: '${0}'.format(x) if x > 0 else None
> self.chart.barLabels.boxAnchor = 'w'
> self.chart.barLabels.boxFillColor = None
> self.chart.barLabels.boxStrokeColor = None
> self.chart.barLabels.fontName = fontName
> self.chart.barLabels.fontSize = 6
> self.chart.barLabels.dy = 5
> self.chart.barLabels.dx = -8
> self.chart.barLabels.boxTarget = 'mid'
> I was hoping there was a setting to avoid overlap, but if that doesn't
> exist I would like to loop over the x,y positions of the existing labels
> and create my own simple labels to replace them but I can't figure out how

I don't think we have a magic way to get the bar labels to not overlap; normally people want stacked bar labels to be inside the
bar, but as you observe when bars become short there's no place to put the label inside.

However, here is some code I have used in the past

def label_fixer(chart,colors,needed):
        vA = chart.valueAxis
        vA.setPosition(chart.x, chart.y, chart.height)

        barLabels = chart.barLabels
        for i,d in enumerate(chart.data):
                for j, v in enumerate(d):
                        if v is None: continue
                        h = v * vA._scaleFactor
                        bl = barLabels[(i,j)]
                        if needed<=h:
                                bl.boxAnchor = 'n'
                                bl.fillColor = barLabels.fillColor
                                bl.dx = bl.dy = 0
                        elif v>0:
                                bl.fillColor = colors[i]
                                if not i:
                                        bl.boxAnchor = 'nw'
                                        bl.dx = chart.barWidth * 0.5
                                        bl.boxAnchor = 's'

and in the chart code getContents method

label_fixer(chart=chart,needed=1.2*chart.barLabels.fontSize+4, colors=[self._orange,self._grey])

this was for a simple chart where the top of two stacked bars was likely to be too small. If that happens the bar is moved up so
is outside. If the lower bar needs a fix we moved the label to the side and downwards (bl.boxAnchor = 'nw'),

The main idea is to get the scaling and then you can check how tall the bar is going to be. Then you need a strategy for changing
the default position.

> to do that.
> Thanks,
> Matt
Robin Becker
reportlab-users mailing list
reportlab-users at lists2.reportlab.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://pairlist2.pair.net/pipermail/reportlab-users/attachments/20180820/b38f16cd/attachment.html>

More information about the reportlab-users mailing list