dataviz: add pie percent chart type (#71666)
gitea/combo/pipeline/head This commit looks good Details

This commit is contained in:
Valentin Deniaud 2024-04-24 17:19:15 +02:00
parent af473d684e
commit 32c912b978
3 changed files with 42 additions and 4 deletions

View File

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

View File

@ -241,6 +241,7 @@ class ChartNgCell(CellBase):
('stacked-bar-percent', _('Stacked Bar (%)')),
('line', _('Line')),
('pie', _('Pie')),
('pie-percent', _('Pie (%)')),
('dot', _('Dot')),
('table', _('Table')),
('table-inverted', _('Table (inverted)')),
@ -381,6 +382,7 @@ class ChartNgCell(CellBase):
'stacked-bar-percent': pygal.StackedBar,
'line': pygal.Line,
'pie': pygal.Pie,
'pie-percent': pygal.Pie,
'dot': pygal.Dot,
'table': pygal.Bar,
'table-inverted': pygal.Bar,
@ -418,7 +420,7 @@ class ChartNgCell(CellBase):
data['series'][0]['data'] = self.process_one_dimensional_data(
chart, data['series'][0]['data']
)
if self.chart_type == 'pie':
if self.chart_type in ('pie', 'pie-percent'):
data['series'] = [
{'label': chart.config.x_value_formatter(label), 'data': [data]}
for label, data in zip(chart.x_labels, data['series'][0]['data'])
@ -429,6 +431,9 @@ class ChartNgCell(CellBase):
if self.chart_type == 'stacked-bar-percent':
self.make_percent([serie['data'] for serie in data['series']])
elif self.chart_type == 'pie-percent':
self.make_global_percent([serie['data'] for serie in data['series']])
chart.config.value_formatter = self.get_value_formatter(measure='percent')
for serie in data['series']:
chart.add(serie['label'], serie['data'])
@ -586,6 +591,9 @@ class ChartNgCell(CellBase):
elif width:
chart.truncate_legend = width // 20
def configure_pie_percent_chart(self, *args, **kwargs):
self.configure_pie_chart(*args, **kwargs)
def configure_chart(self, chart, width, height):
auto_height_scale = pygal.style.DefaultStyle.legend_font_size * 1.75
chart.config.margin = 0
@ -620,7 +628,7 @@ class ChartNgCell(CellBase):
if hasattr(self, custom_configure_method_name):
getattr(self, custom_configure_method_name)(chart, width, height)
if self.chart_type != 'pie':
if self.chart_type not in ('pie', 'pie-percent'):
if width and width < 500:
chart.legend_at_bottom = True
# restore demanded chart's height
@ -698,7 +706,7 @@ class ChartNgCell(CellBase):
chart.add(gettext('Total'), line_totals)
def add_data_to_chart(self, chart, data, y_labels):
if self.chart_type != 'pie':
if self.chart_type not in ('pie', 'pie-percent'):
series_data = []
for i, serie_label in enumerate(y_labels):
if chart.axis_count < 2:
@ -718,7 +726,7 @@ class ChartNgCell(CellBase):
chart.add(label, value)
@staticmethod
def get_value_formatter(unit, measure='duration'):
def get_value_formatter(unit=None, measure='duration'):
if unit == 'seconds' or measure == 'duration':
def format_duration(value):
@ -743,6 +751,17 @@ class ChartNgCell(CellBase):
if values[i] is not None:
values[i] = round(values[i] * factor, 1)
def make_global_percent(self, series_data):
sum_values = sum(v for values in series_data for v in values if v is not None)
if sum_values == 0:
return
factor = 100 / sum_values
for serie in series_data:
for i, value in enumerate(serie):
if value is not None:
serie[i] = round(value * factor, 1)
@staticmethod
def aggregate_data(data, interval):
series_data = [serie['data'] for serie in data['series']]

View File

@ -1011,6 +1011,24 @@ def test_chartng_cell_new_api(app, new_api_statistics):
assert chart.x_labels == []
assert chart.raw_series == []
# pie with percent
cell.statistic = Statistic.objects.get(slug='two-series')
cell.chart_type = 'pie-percent'
cell.save()
chart = cell.get_chart()
assert chart.raw_series == [
([None, 76.2, 9.5], {'title': 'Serie 1'}),
([9.5, 4.8, None], {'title': 'Serie 2'}),
]
cell.statistic = Statistic.objects.get(slug='no-data')
cell.save()
chart = cell.get_chart()
assert chart.x_labels == []
assert chart.raw_series == []
cell.statistic = Statistic.objects.get(slug='not-found')
cell.save()
with pytest.raises(HTTPError):