diff --git a/src/assets/css/style.css b/src/assets/css/style.css
index 326523f..9705af4 100644
--- a/src/assets/css/style.css
+++ b/src/assets/css/style.css
@@ -190,6 +190,13 @@ p.version > a {
grid-row: 1;
}
+/* --- Dashboard inputs --- */
+
+.Select--multi .Select-value {
+ color: var(--primary-color);
+ background-color: rgba(255, 240, 240, 0.4);
+}
+
/* --- Tables (Dash & Custom) --- */
/* Table Menu (Exports etc) */
diff --git a/src/figures.py b/src/figures.py
index 215847f..c32f865 100644
--- a/src/figures.py
+++ b/src/figures.py
@@ -624,6 +624,25 @@ def make_card(
return card
+def make_donut(lff: pl.LazyFrame, names_col):
+ title = data_schema[names_col]["title"]
+ lff = lff.rename({names_col: title})
+ lff = lff.select("uid", title)
+ lff = lff.group_by(title).len("Nombre")
+ lff = lff.with_columns(pl.col(title).replace(None, pl.lit("?")))
+ fig = px.pie(
+ lff.collect(engine="streaming"),
+ values="Nombre",
+ names=title,
+ hole=0.4,
+ color_discrete_sequence=px.colors.qualitative.Safe,
+ )
+ fig = fig.update_traces(texttemplate="%{label}
%{percent}")
+ fig = fig.update_layout(showlegend=False, font=dict(size=14))
+ graph = dcc.Graph(figure=fig)
+ return graph
+
+
def make_column_picker(page: str):
table_data = []
table_columns = [
diff --git a/src/pages/statistiques.py b/src/pages/statistiques.py
index 4a1f970..9de6a29 100644
--- a/src/pages/statistiques.py
+++ b/src/pages/statistiques.py
@@ -5,7 +5,7 @@ import polars as pl
import polars.selectors as cs
from dash import Input, Output, callback, dcc, html, register_page
-from src.figures import get_geographic_maps, make_card
+from src.figures import get_geographic_maps, make_card, make_donut
from src.utils import (
departements,
df,
@@ -69,7 +69,7 @@ layout = [
options=get_enum_values_as_dict(
"acheteur_categorie"
),
- placeholder="Catégorie d'acheteur",
+ placeholder="Catégorie",
),
),
dbc.Row(
@@ -81,14 +81,44 @@ layout = [
options=options_departements,
),
),
+ html.H5("Titulaire"),
+ dbc.Row(
+ dcc.Dropdown(
+ id="dashboard_titulaire_categorie",
+ placeholder="Catégorie",
+ options=get_enum_values_as_dict(
+ "titulaire_categorie"
+ ),
+ ),
+ ),
html.H5("Marché"),
dbc.Row(
dcc.Dropdown(
id="dashboard_marche_type",
- placeholder="Type de marché",
+ placeholder="Type",
options=get_enum_values_as_dict("type"),
),
),
+ dbc.Row(
+ dcc.Dropdown(
+ id="dashboard_marche_considerationsSociales",
+ placeholder="Considérations sociales",
+ options=get_enum_values_as_dict(
+ "considerationsSociales"
+ ),
+ multi=True,
+ ),
+ ),
+ dbc.Row(
+ dcc.Dropdown(
+ id="dashboard_marche_considerationsEnvironnementales",
+ placeholder="Considérations environnementales",
+ multi=True,
+ options=get_enum_values_as_dict(
+ "considerationsEnvironnementales"
+ ),
+ ),
+ ),
],
),
dbc.Col(
@@ -112,13 +142,19 @@ layout = [
Input("dashboard_year", "value"),
Input("dashboard_acheteur_categorie", "value"),
Input("dashboard_acheteur_departement_code", "value"),
+ Input("dashboard_titulaire_categorie", "value"),
Input("dashboard_marche_type", "value"),
+ Input("dashboard_marche_considerationsSociales", "value"),
+ Input("dashboard_marche_considerationsEnvironnementales", "value"),
)
def udpate_dashboard_cards(
dashboard_year,
dashboard_acheteur_categorie,
dashboard_acheteur_departement_code,
+ dashboard_titulaire_categorie,
dashboard_marche_type,
+ dashboard_marche_considerationsSociales,
+ dashboard_marche_considerationsEnvironnementales,
):
lff: pl.LazyFrame = df.lazy()
lff = lff.select(
@@ -127,10 +163,14 @@ def udpate_dashboard_cards(
cs.starts_with("titulaire"),
"dateNotification",
"montant",
+ "considerationsSociales",
+ "considerationsEnvironnementales",
)
# Application des filtres
+ ## Période
+
if dashboard_year:
lff = lff.filter(pl.col("dateNotification").dt.year() == int(dashboard_year))
else:
@@ -138,6 +178,8 @@ def udpate_dashboard_cards(
pl.col("dateNotification") > (datetime.now() - timedelta(days=365))
)
+ ## Acheteur
+
if dashboard_acheteur_categorie:
lff = lff.filter(pl.col("acheteur_categorie") == dashboard_acheteur_categorie)
@@ -148,12 +190,38 @@ def udpate_dashboard_cards(
)
)
+ ## Titulaire
+
+ if dashboard_titulaire_categorie:
+ lff = lff.filter(pl.col("titulaire_categorie") == dashboard_titulaire_categorie)
+
+ ## Marché
+
if dashboard_marche_type:
lff = lff.filter(pl.col("type") == dashboard_marche_type)
- # Génération des métriques
- dff = lff.collect()
+ if dashboard_marche_considerationsSociales:
+ lff = lff.filter(
+ pl.col("considerationsSociales")
+ .str.split(", ")
+ .list.set_intersection(dashboard_marche_considerationsSociales)
+ .list.len()
+ > 0
+ )
+ if dashboard_marche_considerationsEnvironnementales:
+ lff = lff.filter(
+ pl.col("considerationsEnvironnementales")
+ .str.split(", ")
+ .list.set_intersection(dashboard_marche_considerationsEnvironnementales)
+ .list.len()
+ > 0
+ )
+
+ # Génération des métriques
+ dff = lff.collect(engine="streaming")
+
+ # À transformer en fonction
nb_acheteurs = dff.select("acheteur_id").n_unique()
nb_titulaires = dff.select("titulaire_id", "titulaire_typeIdentifiant").n_unique()
@@ -165,7 +233,6 @@ def udpate_dashboard_cards(
cards = []
- # À transformer en fonction
card_basic_counts = [
html.P(["Nombre de marchés : ", html.Strong(str(format_number(nb_marches)))]),
html.P(
@@ -179,6 +246,14 @@ def udpate_dashboard_cards(
cards.append(make_card(title="Résumé", paragraphs=card_basic_counts))
+ donut_acheteur_categorie = make_donut(lff, "acheteur_categorie")
+ cards.append(make_card(title="Catégorie d'acheteur", fig=donut_acheteur_categorie))
+
+ donut_titulaire_categorie = make_donut(lff, "titulaire_categorie")
+ cards.append(
+ make_card(title="Catégorie d'entreprise", fig=donut_titulaire_categorie)
+ )
+
geographic_maps: list[dbc.Col] = get_geographic_maps(dff)
return dbc.Row(children=cards + geographic_maps)
diff --git a/src/utils.py b/src/utils.py
index b334d01..642bad4 100644
--- a/src/utils.py
+++ b/src/utils.py
@@ -697,13 +697,13 @@ def get_button_properties(height):
def get_enum_values_as_dict(column_name):
- for column in data_schema:
- if column == column_name:
- options = {}
- for value in data_schema[column]["enum"]:
- options[value] = value
- return options
- return {"not_found": "not found"}
+ try:
+ options = {}
+ for value in data_schema[column_name]["enum"]:
+ options[value] = value
+ return options
+ except KeyError:
+ return {"not_found": "not found"}
def invert_columns(columns):