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

Robin Becker robin at reportlab.com
Mon Aug 20 11:38:10 EDT 2018

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

More information about the reportlab-users mailing list