dataviz: add stacked bar percent chart type (#52845)

This commit is contained in:
Valentin Deniaud 2021-04-12 15:36:38 +02:00
parent 15651beb91
commit 434ac12426
3 changed files with 45 additions and 0 deletions

View File

@ -45,6 +45,7 @@ class Migration(migrations.Migration):
('bar', 'Bar'),
('horizontal-bar', 'Horizontal Bar'),
('stacked-bar', 'Stacked Bar'),
('stacked-bar-percent', 'Stacked Bar (%)'),
('line', 'Line'),
('pie', 'Pie'),
('dot', 'Dot'),

View File

@ -190,6 +190,7 @@ class ChartNgCell(CellBase):
('bar', _('Bar')),
('horizontal-bar', _('Horizontal Bar')),
('stacked-bar', _('Stacked Bar')),
('stacked-bar-percent', _('Stacked Bar (%)')),
('line', _('Line')),
('pie', _('Pie')),
('dot', _('Dot')),
@ -306,6 +307,7 @@ class ChartNgCell(CellBase):
'bar': pygal.Bar,
'horizontal-bar': pygal.HorizontalBar,
'stacked-bar': pygal.StackedBar,
'stacked-bar-percent': pygal.StackedBar,
'line': pygal.Line,
'pie': pygal.Pie,
'dot': pygal.Dot,
@ -337,6 +339,9 @@ class ChartNgCell(CellBase):
if data
]
if self.chart_type == 'stacked-bar-percent':
self.make_percent([serie['data'] for serie in data['series']])
for serie in data['series']:
chart.add(serie['label'], serie['data'])
@ -485,12 +490,16 @@ class ChartNgCell(CellBase):
def add_data_to_chart(self, chart, data, y_labels):
if self.chart_type != 'pie':
series_data = []
for i, serie_label in enumerate(y_labels):
if chart.axis_count < 2:
values = data
else:
values = [data[i][j] for j in range(len(chart.x_labels))]
series_data.append(values)
chart.add(serie_label, values)
if self.chart_type == 'stacked-bar-percent':
self.make_percent(series_data)
else:
# pie, create a serie by data, to get different colours
values = data
@ -529,3 +538,14 @@ class ChartNgCell(CellBase):
elif measure == 'percent':
percent_formatter = lambda x: '{:.1f}%'.format(x)
return percent_formatter
def make_percent(self, series_data):
for i, values in enumerate(zip(*series_data)):
sum_values = sum([v for v in values if v is not None])
if sum_values == 0:
continue
factor = 100 / sum_values
for values in series_data:
if values[i] is not None:
values[i] = round(values[i] * factor, 1)

View File

@ -441,6 +441,18 @@ def test_chartng_cell(app, statistics):
([122, 114, 2, 33], {'title': u'bar'}),
]
# stacked bar with percent
cell.chart_type = 'stacked-bar-percent'
cell.save()
chart = cell.get_chart()
assert chart.x_labels == ['web', 'mail', 'phone', 'email']
assert chart.raw_series == [
([64.5, 54, 0, 61.6], {'title': u'foo'}),
([35.5, 46, 100, 38.4], {'title': u'bar'}),
]
assert all(x + y == 100 for x, y in zip(chart.raw_series[0][0], chart.raw_series[1][0]))
# single data point
cell.chart_type = 'bar'
cell.statistic = Statistic.objects.get(slug='fourth')
@ -533,6 +545,18 @@ def test_chartng_cell_new_api(app, new_api_statistics):
assert chart.x_labels == ['2020-10', '2020-11', '2020-12']
assert chart.raw_series == [([None, 16, 2], {'title': 'Serie 1'}), ([2, 1, None], {'title': 'Serie 2'})]
# stacked bar with percent
cell.chart_type = 'stacked-bar-percent'
cell.save()
chart = cell.get_chart()
assert chart.x_labels == ['2020-10', '2020-11', '2020-12']
assert chart.raw_series == [
([None, 94.1, 100], {'title': 'Serie 1'}),
([100, 5.9, None], {'title': 'Serie 2'}),
]
assert all(x + y == 100 for x, y in zip(chart.raw_series[0][0], chart.raw_series[1][0]) if x and y)
cell.statistic = Statistic.objects.get(slug='no-data')
cell.save()