diff --git a/diagnostic_word/renderers.py b/diagnostic_word/renderers.py index 2d54b5fab..b5d2e38e4 100644 --- a/diagnostic_word/renderers.py +++ b/diagnostic_word/renderers.py @@ -16,6 +16,9 @@ from public_data.domain.impermeabilisation.difference.ImpermeabilisationDifferenceService import ( ImpermeabilisationDifferenceService, ) +from public_data.infra.consommation.progression.export.ConsoByDeterminantExportTableMapper import ( + ConsoByDeterminantExportTableMapper, +) from public_data.infra.consommation.progression.export.ConsoComparisonExportTableMapper import ( ConsoComparisonExportTableMapper, ) @@ -197,7 +200,15 @@ def get_context_data(self) -> Dict[str, Any]: series=annual_total_conso_chart.get_series(), line=False ), "communes_data_table": add_total_line_column(chart_conso_cities.get_series()), - "determinants_data_table": add_total_line_column(det_chart.get_series()), + "determinants_data_table": ConsoByDeterminantExportTableMapper.map( + consommation_progression=PublicDataContainer.consommation_progression_service() + .get_by_land( + land=diagnostic.land_proxy, + start_date=int(diagnostic.analyse_start_date), + end_date=int(diagnostic.analyse_end_date), + ) + .consommation + ), # Target 2031 "target_2031_consumed": target_2031_consumption, "projection_zan_cumulee_ref": round(objective_chart.total_2020, 1), diff --git a/project/charts/AnnualConsoByDeterminantChart.py b/project/charts/AnnualConsoByDeterminantChart.py index 868315564..68f8981c2 100644 --- a/project/charts/AnnualConsoByDeterminantChart.py +++ b/project/charts/AnnualConsoByDeterminantChart.py @@ -2,27 +2,67 @@ from project.charts.constants import ( CEREMA_CREDITS, DEFAULT_VALUE_DECIMALS, - HIGHLIGHT_COLOR, LEGEND_NAVIGATION_EXPORT, ) +from public_data.domain.containers import PublicDataContainer class AnnualConsoByDeterminantChart(ProjectChart): """ Graphique en barre de consommation annuelle par destination (habitat, activité, mixte etc.) - avec une courbe de consommation totale en pointillés. """ name = "determinant per year" + def _get_series(self): + """ + Génère et retourne la liste des séries à utiliser dans le graphique. + """ + consommation_progression = PublicDataContainer.consommation_progression_service().get_by_land( + land=self.project.land_proxy, + start_date=self.project.analyse_start_date, + end_date=self.project.analyse_end_date, + ) + + category_to_attr = { + "Habitat": "habitat", + "Activité": "activite", + "Mixte": "mixte", + "Route": "route", + "Ferré": "ferre", + "Inconnu": "non_renseigne", + "Total": "total", + } + + data = {category: {} for category in category_to_attr.keys()} + + for annual_conso in consommation_progression.consommation: + for category, attr in category_to_attr.items(): + data[category][annual_conso.year] = getattr(annual_conso, attr) + + series = [ + { + "name": determinant, + "data": [{"name": year, "y": value} for year, value in data[determinant].items()], + **( + {"id": "main", "type": "column", "zIndex": 0, "stacking": None, "color": "#CFD1E5"} + if determinant == "Total" + else {"type": "column", "stacking": "normal", "zIndex": 1} + ), + } + for determinant in data + ] + + return series + @property def param(self): return super().param | { "chart": {"type": "column"}, "title": {"text": "Par an"}, "yAxis": { - "title": {"text": "Consommation annuelle (en ha)"}, - "stackLabels": {"enabled": True, "format": "{total:,.1f}"}, + "title": {"text": "Consommation d'espaces NAF (en ha)"}, + "stackLabels": {"enabled": True, "format": "{total:,.2f}"}, }, "tooltip": { "headerFormat": "{point.key}
", @@ -37,32 +77,13 @@ def param(self): "align": "right", "verticalAlign": "middle", }, - "plotOptions": { - "column": { - "stacking": "normal", - "dataLabels": {"enabled": True, "format": "{point.y:,.1f}"}, - } - }, - "series": [], + "plotOptions": {"series": {"grouping": False, "borderWidth": 0}}, + "series": self._get_series(), } - def get_series(self): - if not self.series: - self.series = self.project.get_determinants(group_name=self.group_name) - return self.series - + # To remove after refactoring def add_series(self): - super().add_series() - if not self.group_name: - self.add_serie( - "Total", - self.project.get_conso_per_year(), - **{ - "type": "line", - "color": HIGHLIGHT_COLOR, - "dashStyle": "ShortDash", - }, - ) + pass class AnnualConsoByDeterminantChartExport(AnnualConsoByDeterminantChart): diff --git a/project/charts/AnnualTotalConsoChart.py b/project/charts/AnnualTotalConsoChart.py index dc2f8962c..8fb8af6b4 100644 --- a/project/charts/AnnualTotalConsoChart.py +++ b/project/charts/AnnualTotalConsoChart.py @@ -16,7 +16,7 @@ def param(self): return super().param | { "chart": {"type": "column"}, "title": {"text": ""}, - "yAxis": {"title": {"text": "Consommé (ha)"}}, + "yAxis": {"title": {"text": "Consommation d'espaces NAF (ha)"}}, "xAxis": {"type": "category"}, "tooltip": { "headerFormat": DEFAULT_HEADER_FORMAT, diff --git a/project/charts/ConsoByDeterminantPieChart.py b/project/charts/ConsoByDeterminantPieChart.py index a805e9608..c6fe877bb 100644 --- a/project/charts/ConsoByDeterminantPieChart.py +++ b/project/charts/ConsoByDeterminantPieChart.py @@ -1,10 +1,43 @@ from project.charts.base_project_chart import ProjectChart from project.charts.constants import CEREMA_CREDITS +from public_data.domain.containers import PublicDataContainer class ConsoByDeterminantPieChart(ProjectChart): + """ + Graphique en secteurs de consommation totale par destination (habitat, activité, mixte etc.) + """ + name = "determinant overview" + def _get_series(self): + """ + Génère et retourne la liste des séries à utiliser dans le graphique. + """ + consommation_total = PublicDataContainer.consommation_stats_service().get_by_land( + land=self.project.land_proxy, + start_date=self.project.analyse_start_date, + end_date=self.project.analyse_end_date, + ) + + category_to_attr = { + "Habitat": "habitat", + "Activité": "activite", + "Mixte": "mixte", + "Route": "route", + "Ferré": "ferre", + "Inconnu": "non_renseigne", + } + + data = {category: getattr(consommation_total, attr) for category, attr in category_to_attr.items()} + + return [ + { + "name": "Destinations", + "data": [{"name": category, "y": value} for category, value in data.items()], + } + ] + @property def param(self): return super().param | { @@ -12,32 +45,24 @@ def param(self): "title": { "text": "Sur la période", }, - "tooltip": {"enabled": True, "pointFormat": "{point.y:.1f} Ha"}, + "tooltip": {"enabled": False}, "plotOptions": { "pie": { "allowPointSelect": True, "cursor": "pointer", "dataLabels": { + "distance": 15, "enabled": True, - "format": "{point.name} : {point.y:.1f} Ha", + "format": "{point.name}
{point.y:.2f} Ha", }, } }, - "series": [], + "series": self._get_series(), } - def __init__(self, *args, **kwargs): - if "series" in kwargs: - self.series = kwargs.pop("series") - super().__init__(*args, **kwargs) - - def get_series(self): - if not self.series: - self.series = self.project.get_determinants(group_name=self.group_name) - return {"Destinations": {n: sum(v.values()) for n, v in self.series.items()}} - + # To remove after refactoring def add_series(self): - super().add_series(sliced=True) + pass class ConsoByDeterminantPieChartExport(ConsoByDeterminantPieChart): diff --git a/project/models/project_base.py b/project/models/project_base.py index 43a010f42..056af3deb 100644 --- a/project/models/project_base.py +++ b/project/models/project_base.py @@ -554,27 +554,6 @@ def get_look_a_like(self): self.save(update_fields=["look_a_like"]) return sorted(lands, key=lambda x: x.name) - def get_determinants(self, group_name=None): - from public_data.domain.containers import PublicDataContainer - - conso = PublicDataContainer.consommation_progression_service().get_by_land( - land=self.land_proxy, - start_date=self.analyse_start_date, - end_date=self.analyse_end_date, - ) - data = {"Habitat": {}, "Activité": {}, "Mixte": {}, "Route": {}, "Ferré": {}, "Inconnu": {}} - - for annual_conso in conso.consommation: - year_as_str = str(annual_conso.year) - data["Habitat"][year_as_str] = annual_conso.habitat - data["Activité"][year_as_str] = annual_conso.activite - data["Mixte"][year_as_str] = annual_conso.mixte - data["Route"][year_as_str] = annual_conso.route - data["Ferré"][year_as_str] = annual_conso.ferre - data["Inconnu"][year_as_str] = annual_conso.non_reseigne - - return data - def get_bilan_conso(self): """Return the space consummed between 2011 and 2020 in hectare""" from public_data.domain.containers import PublicDataContainer diff --git a/project/templates/project/components/dashboard/consommation.html b/project/templates/project/components/dashboard/consommation.html index e7889f71b..5a023c160 100644 --- a/project/templates/project/components/dashboard/consommation.html +++ b/project/templates/project/components/dashboard/consommation.html @@ -139,38 +139,7 @@
Calcul

Données brutes, sans calcul

Données
-
-
-
-
- - - - - - {% for year in project.years %} - - {% endfor %} - - - - - {% for determinant_name, data in data_determinant.items %} - - - {% for year, val in data.items %} - - {% endfor %} - - {% endfor %} - -
- Consommation d'espace annuelle sur le territoire par destination (en ha) -
Destination{{ year }}Total
{{ determinant_name }}+{{ val|floatformat:1 }}
-
-
-
-
+ {{ determinant_data_table }} diff --git a/project/views/report.py b/project/views/report.py index 487bb611e..6d5fffec0 100644 --- a/project/views/report.py +++ b/project/views/report.py @@ -34,6 +34,9 @@ from public_data.domain.impermeabilisation.difference.ImperSolTableMapper import ( ImperSolTableMapper, ) +from public_data.infra.consommation.progression.table.ConsoByDeterminantTableMapper import ( + ConsoByDeterminantTableMapper, +) from public_data.infra.consommation.progression.table.ConsoComparisonTableMapper import ( ConsoComparisonMapper, ) @@ -104,10 +107,7 @@ def get_context_data(self, **kwargs): # Déterminants det_chart = charts.AnnualConsoByDeterminantChart(project) - det_pie_chart = charts.ConsoByDeterminantPieChart( - project, - series=det_chart.get_series(), - ) + det_pie_chart = charts.ConsoByDeterminantPieChart(project) # CONSO consommation_progression = ( @@ -174,7 +174,15 @@ def get_context_data(self, **kwargs): "population_conso_comparison_chart": charts.PopulationConsoComparisonChart(project), # data tables "annual_conso_data_table": annual_conso_data_table, - "data_determinant": add_total_line_column(det_chart.get_series()), + "determinant_data_table": ConsoByDeterminantTableMapper.map( + consommation_progression=PublicDataContainer.consommation_progression_service() + .get_by_land( + land=project.land_proxy, + start_date=int(project.analyse_start_date), + end_date=int(project.analyse_end_date), + ) + .consommation + ), "comparison_table": ConsoComparisonMapper.map( consommation_progression=PublicDataContainer.consommation_progression_service().get_by_lands( lands=project.comparison_lands_and_self_land(), diff --git a/public_data/domain/consommation/entity/AnnualConsommation.py b/public_data/domain/consommation/entity/AnnualConsommation.py index 2511cdf1e..bd05a9fba 100644 --- a/public_data/domain/consommation/entity/AnnualConsommation.py +++ b/public_data/domain/consommation/entity/AnnualConsommation.py @@ -9,6 +9,6 @@ class AnnualConsommation: mixte: float route: float ferre: float - non_reseigne: float + non_renseigne: float total: float per_mille_of_area: float diff --git a/public_data/domain/consommation/entity/ConsommationStatistics.py b/public_data/domain/consommation/entity/ConsommationStatistics.py index f5ac9ccbe..883664f82 100644 --- a/public_data/domain/consommation/entity/ConsommationStatistics.py +++ b/public_data/domain/consommation/entity/ConsommationStatistics.py @@ -10,3 +10,9 @@ class ConsommationStatistics: end_date: int total: float total_percent: float + activite: float + habitat: float + mixte: float + route: float + ferre: float + non_renseigne: float diff --git a/public_data/infra/consommation/progression/ConsommationProgressionService.py b/public_data/infra/consommation/progression/ConsommationProgressionService.py index a836447bf..65e68c037 100644 --- a/public_data/infra/consommation/progression/ConsommationProgressionService.py +++ b/public_data/infra/consommation/progression/ConsommationProgressionService.py @@ -42,7 +42,7 @@ def get_by_land( mixte=c.mixte / 10000, route=c.route / 10000, ferre=c.ferroviaire / 10000, - non_reseigne=c.inconnu / 10000, + non_renseigne=c.inconnu / 10000, total=c.total / 10000, per_mille_of_area=c.total / 10000 / land.area * 1000, ) diff --git a/public_data/infra/consommation/progression/export/ConsoByDeterminantExportTableMapper.py b/public_data/infra/consommation/progression/export/ConsoByDeterminantExportTableMapper.py new file mode 100644 index 000000000..c8e9066fa --- /dev/null +++ b/public_data/infra/consommation/progression/export/ConsoByDeterminantExportTableMapper.py @@ -0,0 +1,36 @@ +from public_data.domain.consommation.entity import ConsommationCollection + + +class ConsoByDeterminantExportTableMapper: + @staticmethod + def map(consommation_progression: list[ConsommationCollection]): + category_to_attr = { + "Habitat": "habitat", + "Activité": "activite", + "Mixte": "mixte", + "Route": "route", + "Ferré": "ferre", + "Inconnu": "non_renseigne", + "Total": "total", + } + + headers = [str(conso.year) for conso in consommation_progression] + ["Total"] + + rows = [] + for category in category_to_attr: + category_values = [getattr(conso, category_to_attr[category]) for conso in consommation_progression] + category_total = sum(category_values) + # On arrondit ensuite pour ne pas fausser le total + category_values_rounded = [round(value, 2) for value in category_values] + category_total_rounded = round(category_total, 2) + rows.append( + { + "name": category, + "data": category_values_rounded + [category_total_rounded], + } + ) + + return { + "headers": headers, + "rows": rows, + } diff --git a/public_data/infra/consommation/progression/table/ConsoByDeterminantTableMapper.py b/public_data/infra/consommation/progression/table/ConsoByDeterminantTableMapper.py new file mode 100644 index 000000000..b4eec6e27 --- /dev/null +++ b/public_data/infra/consommation/progression/table/ConsoByDeterminantTableMapper.py @@ -0,0 +1,36 @@ +from django.template.loader import render_to_string + +from public_data.domain.consommation.entity import ConsommationCollection + + +class ConsoByDeterminantTableMapper: + @staticmethod + def map(consommation_progression: list[ConsommationCollection]): + category_to_attr = { + "Habitat": "habitat", + "Activité": "activite", + "Mixte": "mixte", + "Route": "route", + "Ferré": "ferre", + "Inconnu": "non_renseigne", + "Total": "total", + } + + headers = ["Destination"] + [str(conso.year) for conso in consommation_progression] + ["Total"] + + data = [] + for category in category_to_attr: + category_values = [getattr(conso, category_to_attr[category]) for conso in consommation_progression] + category_total = sum(category_values) + # On arrondit ensuite pour ne pas fausser le total + category_values_rounded = [round(value, 2) for value in category_values] + category_total_rounded = round(category_total, 2) + data.append([category] + category_values_rounded + [category_total_rounded]) + + return render_to_string( + "public_data/partials/conso_by_determinant_table.html", + { + "headers": headers, + "data": data, + }, + ) diff --git a/public_data/infra/consommation/stats/ConsommationStatsService.py b/public_data/infra/consommation/stats/ConsommationStatsService.py index 26668b739..3bb700630 100644 --- a/public_data/infra/consommation/stats/ConsommationStatsService.py +++ b/public_data/infra/consommation/stats/ConsommationStatsService.py @@ -24,6 +24,12 @@ def get_by_land( end_date=end_date, total=conso_stats.total / 10000, total_percent=conso_stats.total_percent, + habitat=conso_stats.habitat / 10000, + activite=conso_stats.activite / 10000, + mixte=conso_stats.mixte / 10000, + route=conso_stats.route / 10000, + ferre=conso_stats.ferroviaire / 10000, + non_renseigne=conso_stats.inconnu / 10000, ) def get_by_lands( diff --git a/public_data/templates/public_data/partials/conso_by_determinant_table.html b/public_data/templates/public_data/partials/conso_by_determinant_table.html new file mode 100644 index 000000000..1ba98cfc3 --- /dev/null +++ b/public_data/templates/public_data/partials/conso_by_determinant_table.html @@ -0,0 +1,33 @@ +
+
+
+
+ + + + + {% for header in headers %} + + {% endfor %} + + + + {% for row in data %} + + {% for cell in row %} + + {% endfor %} + + {% endfor %} + +
+ Consommation d'espaces NAF sur le territoire par an et par destination (en ha) +
+ {{ header }} +
+ {{ cell }} +
+
+
+
+