Commit ee27a2f4 authored by Christophe Benz's avatar Christophe Benz

Use local CSV, add Tailwind style

parent 5832ab4f
.mypy_cache/
__pycache__/
.env
organizations.csv
......@@ -17,5 +17,10 @@ pip install -r requirements-dev.txt
## Run
```
wget https://git.opendatafrance.net/observatoire/observatoire-data/raw/master/organizations.csv
cp .env.example .env
# fill .env especially MAPBOX_TOKEN
python3 app.py
```
`MAPBOX_TOKEN` is required, you can create one on https://mapbox.com/
"""Interactive OpenDataFrance dashboard."""
import os
from random import randint
......@@ -12,6 +11,9 @@ from dotenv import load_dotenv
import app_data
"""Interactive OpenDataFrance dashboard."""
COLORS = [
"rgba(31,119,180,1)",
"rgba(255,127,14,1)",
......@@ -44,34 +46,71 @@ def compute_dept_dropdown_options(reg_code=None):
load_dotenv()
external_stylesheets = ["https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css"]
server = flask.Flask(__name__)
server.secret_key = os.environ.get("secret_key", str(randint(0, 1000000)))
px.set_mapbox_access_token(os.getenv("MAPBOX_TOKEN"))
app = dash.Dash(__name__, server=server)
app = dash.Dash(__name__, server=server, external_stylesheets=external_stylesheets)
app.layout = html.Div(
className="container mx-auto px-4",
children=[
html.H1(children="Observatoire opendata des territoires"),
dcc.Dropdown(
id="reg_dd",
options=[
{"label": "-- région --", "value": ""},
*[{"label": reg[1], "value": reg[0]} for reg in app_data.reg_list],
html.H1(
children="Observatoire open data des territoires", className="text-4xl my-4"
),
html.Div(
className="my-4 md:w-1/2",
children=[
html.Div(
className="mb-2",
children=[
dcc.Dropdown(
id="region",
options=[
{"label": "-- région --", "value": ""},
*[
{"label": reg[1], "value": reg[0]}
for reg in app_data.reg_list
],
],
value="",
),
],
),
html.Div(
className="mb-2",
children=[
dcc.Dropdown(
id="departement",
options=compute_dept_dropdown_options(),
value="",
),
],
),
],
value="",
),
dcc.Dropdown(id="dep_dd", options=compute_dept_dropdown_options(), value=""),
dcc.Graph(id="type_bar"),
dcc.Graph(id="map"),
]
dcc.Loading(
id="loading-charts",
children=[
html.Div(
className="flex",
children=[
dcc.Graph(id="bar-chart", className="w-1/2"),
dcc.Graph(id="map", className="w-1/2"),
],
)
],
),
],
)
@app.callback(
[
Output(component_id="dep_dd", component_property="options"),
Output(component_id="dep_dd", component_property="value"),
Output(component_id="departement", component_property="options"),
Output(component_id="departement", component_property="value"),
],
[Input(component_id="reg_dd", component_property="value")],
[Input(component_id="region", component_property="value")],
)
def update_dept_dropdown_options(reg_code):
"""Update department list when a region has been chosen."""
......@@ -94,10 +133,10 @@ def filter_df(df, reg_code, dep_code):
@app.callback(
Output(component_id="type_bar", component_property="figure"),
Output(component_id="bar-chart", component_property="figure"),
[
Input(component_id="reg_dd", component_property="value"),
Input(component_id="dep_dd", component_property="value"),
Input(component_id="region", component_property="value"),
Input(component_id="departement", component_property="value"),
],
)
def update_type_bar(reg_code, dep_code):
......@@ -107,6 +146,10 @@ def update_type_bar(reg_code, dep_code):
"""
df = filter_df(app_data.df, reg_code, dep_code)
df = df.groupby("type").size()
missing_cols = set(app_data.COLL_TYPES) - set(df.index)
for col in missing_cols:
df[col] = 0
df = df.sort_index()
return px.bar(
df,
x=df.index,
......@@ -120,8 +163,8 @@ def update_type_bar(reg_code, dep_code):
@app.callback(
Output(component_id="map", component_property="figure"),
[
Input(component_id="reg_dd", component_property="value"),
Input(component_id="dep_dd", component_property="value"),
Input(component_id="region", component_property="value"),
Input(component_id="departement", component_property="value"),
],
)
def update_map(reg_code, dep_code):
......
"""Manage data used in dashboard."""
import unicodedata
from collections import defaultdict
from operator import itemgetter
from pathlib import Path
from typing import Dict, List
import pandas as pd
OPENDATA_ORG_CSV_URL = (
"https://git.opendatafrance.net/observatoire/observatoire-data"
+ "/raw/master/organizations.csv"
)
"""Manage data used in dashboard."""
ORGANIZATIONS_CSV = "organizations.csv"
def unaccentize(str_with_accents):
......@@ -25,8 +25,12 @@ def unaccentize(str_with_accents):
)
# Get data and prepare global variables
df = pd.read_csv(OPENDATA_ORG_CSV_URL)
# Get data and prepare global variables.
if not Path(ORGANIZATIONS_CSV).is_file():
raise FileNotFoundError(f"Could not find {ORGANIZATIONS_CSV!r}")
df = pd.read_csv(ORGANIZATIONS_CSV)
df.columns = [c.replace("-", "_") for c in df.columns]
df = df.astype({"reg_code": str, "dep_code": str})
......@@ -41,12 +45,6 @@ reg_list = sorted(reg_set, key=lambda t: unaccentize(t[1]))
reg_dep_list = [(t[0], t[2], t[3]) for t in sorted(reg_dep_set, key=itemgetter(2))]
reg_dep_list_map: Dict[str, List[str]] = defaultdict(list)
for t in reg_dep_set:
reg_dep_list_map[t[0]].append(t[2])
dep_reg_map = {t[1]: t[0] for t in reg_dep_list}
def compute_dep_list(reg_code=None):
"""Compute department tuples (name, code)."""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment