Commit dde358df authored by Samuël Weber's avatar Samuël Weber
Browse files

estimate works

parent bf7ad3e1
......@@ -4,6 +4,7 @@ import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
import sqlite3
import pyOPestimator
def get_station_dropdown_component(stations):
......@@ -632,6 +633,59 @@ def get_estimate_warning_component():
return component
def get_monthly_relative_contribution():
"""TODO: Docstring for get_monthly_relative_contribution.
:returns: TODO
"""
dfpm = pd.DataFrame(
index = pd.DatetimeIndex(freq="M", start="2018-01-01",
end="2019-01-01"),
columns=["PM10"],
data=[10,10,10,10,10,10,10,10,10,10,10,10]
)
dfpm.index.name = "Date"
dfpm = dfpm.reset_index()
dfopDTT, dfrel = pyOPestimator.get_op_from_pm10(dfpm, "DTTv")
dfopAA, _ = pyOPestimator.get_op_from_pm10(dfpm, "AAv")
dfopDTT = dfopDTT.melt(id_vars=["Date", "totalOP", "month", "PM10"], var_name="Factor",
value_name="OP")
dfopAA = dfopAA.melt(id_vars=["Date", "totalOP", "month", "PM10"], var_name="Factor",
value_name="OP")
factors = dfopDTT['Factor'].unique()
colors = {}
for factor in factors:
colors[factor] = get_sourceColor(source=factor)
fignormDTT = px.area(
dfopDTT,
x="Date",
y="OP",
color="Factor",
color_discrete_map=colors
)
fignormDTT.update_yaxes(
{"title": "OP DTT relative montly contribution (%)"}
)
fignormAA = px.area(
dfopAA,
x="Date",
y="OP",
color="Factor",
color_discrete_map=colors
)
fignormAA.update_yaxes(
{"title": "OP AA relative montly contribution (%)"}
)
component = dbc.Row(
dbc.Col(
)
)
def plot_ts(df, station, var, groupby):
"""Set a trace for plotly of the timeserie var in df for the given station,
grouped by groupby.
......
......@@ -20,6 +20,7 @@ NCLICKED = 0
layout = dbc.Container(
id="container-results",
children=[
dcc.Store(id='memory-op'),
dbc.Row([
dbc.Col(
id="upload-col",
......@@ -28,20 +29,18 @@ layout = dbc.Container(
id='upload-data',
children=html.Div([
dcc.Markdown("""
[Select Files](#ref) (`.csv` or `.xls(x)` with a `Date` and `PM10` column)
[Select Files](#ref)
(`.csv` or `.xls(x)` with a `Date` and `PM10` column)
""",
id="select-file"
),
]),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
# Allow multiple files to be uploaded
multiple=False
......@@ -72,13 +71,49 @@ layout = dbc.Container(
id="graph-col",
width=9,
children=[
ac.get_options_estimate_component(),
dcc.Markdown("### First order estimator of OP from PM10 concentration"),
dcc.Loading(dcc.Graph(id="graph")),
ac.get_estimate_warning_component()
]
)
])
dbc.Row(
[
dbc.Col(
[
dcc.Markdown("### First order estimator of OP from PM10 concentration"),
ac.get_options_estimate_component(),
dcc.Loading(
[dcc.Graph(id="graph-abs")]
),
],
className="col-12"
),
dbc.Col(
html.Div(
id='output-data-op',
children=[
dash_table.DataTable(
id="datatable-op",
sort_action="native",
sort_mode="multi",
filter_action='native',
page_size=5,
export_columns='all',
export_format="xlsx",
style_cell={
'overflow': 'hidden',
'textOverflow': 'ellipsis',
'maxWidth': 0,
},
),
]
),
className='col-9'
),
],
className="justify-content-center"
),
dbc.Row(
ac.get_estimate_warning_component(),
)
]
)
])
],
fluid=True,
# end container
......@@ -124,6 +159,9 @@ def parse_contents(contents, filename):
def update_output(content, name, clicked):
errors = []
global NCLICKED
if clicked is None:
clicked = 0
if clicked > NCLICKED:
df = pyOPestimator.load_dataset("atmoaura_GRE-fr_pm10")
data = df.to_dict('records')
......@@ -158,11 +196,32 @@ def update_output(content, name, clicked):
)
return (data, columns, flash)
@app.callback(Output('graph', 'figure'),
[Input('datatable', 'derived_virtual_data'),
Input('option-OPtype', 'value'),
Input('option-temporality', 'value'),
])
@app.callback(Output('memory-op', 'data'),
[
Input('datatable', 'derived_virtual_data'),
Input('option-OPtype', 'value'),
])
def update_storage(dfpm, OPtype):
if dfpm is None or len(dfpm) == 0:
raise PreventUpdate
dfpm = pd.DataFrame(dfpm)
dfpm["Date"] = pd.to_datetime(dfpm["Date"])
dfop = pyOPestimator.get_op_from_pm10(dfpm, OPtype)
factors = list(dfop.drop(["Date", "month", "PM10", "totalOP"], axis=1).columns)
# dfop = dfop.melt(id_vars=["Date", "totalOP", "month", "PM10"], var_name="Factor",
# value_name="OP")
return dfop.to_dict('record')
@app.callback(Output('graph-abs', 'figure'),
[
Input('datatable', 'derived_virtual_data'),
Input('option-OPtype', 'value'),
Input('option-temporality', 'value'),
],
)
def update_graph(dfpm, OPtype, temporality):
"""update the estimated PM OP graph
......@@ -185,20 +244,48 @@ def update_graph(dfpm, OPtype, temporality):
dfop = dfop.shift(-15, freq="D").reset_index()
dfop = dfop.melt(id_vars=["Date", "totalOP", "month", "PM10"], var_name="Factor",
value_name="OP")
# dfop = pd.DataFrame(dfop)
# factors = dfop["Factor"].unique()
#
# if temporality == "monthly":
# dfop = dfop.groupby(
# pd.Grouper(key="Date", freq="M")
# ).mean()
# dfop = dfop.shift(-15, freq="D").reset_index()
colors = {}
for factor in factors:
colors[factor] = ac.get_sourceColor(source=factor)
fig = px.area(
figabs = px.area(
dfop,
x="Date",
y="OP",
color="Factor",
color_discrete_map=colors
)
fig.update_yaxes(
figabs.update_yaxes(
{"title": "OP {} estimation (nmol.min⁻¹.m⁻³)".format(OPtype)}
)
return fig
return figabs
@app.callback([
Output('datatable-op', 'data'),
Output('datatable-op', 'columns')
],
[
Input('memory-op', 'data')
],
[
State('option-OPtype', 'value'),
]
)
def add_op_to_datatable(dfop, OPtype):
df = pd.DataFrame(dfop)
df["Date"] = pd.to_datetime(df["Date"])
df["total_{}".format(OPtype)] = df["totalOP"]
df.drop("totalOP", axis=1, inplace=True)
data = df.to_dict('records')
columns = [{'name': i, 'id': i} for i in df.columns]
return (data, columns)
......@@ -3,24 +3,35 @@
### Method
Gathering several research program in France metropolitan area succeed to estimate a
climatology of the PM10 sources contribution to the ambient PM10 concentration.
We are then able to estimate a roughly monthly mean relative contribution of each sources to the PM10.
Then, for a given day of PM10 measurement, we can estimate the relative
contribution of a set of common sources found in the metropolitan territory.
We should keep in mind that this is a crude approximation since it does not
climatology of the PM<sub>10</sub> sources contribution to the ambient
PM<sub>10</sub> concentration in urbanized area ([Weber et al.
2019](https://www.mdpi.com/2073-4433/10/6/310) & the SOURCES project
[http://pmsources.u-ga.fr/](http://pmsources.u-ga.fr/)). Hence, we are able to
estimate a roughly monthly mean relative contribution of each sources to the
PM<sub>10</sub> concentration.
Thus, we can roughly estimate the contribution of the majority sources of PM<sub>10</sub>
for a given day, considering that this sampling is representative of our data
set. We should keep in mind that this is a crude approximation since it does not
take into account for local specificities nor for variation over year of the
sources contributions.
Finally, thanks to the recent development of the scientific community, and notably
Weber et al. 2020 for the France area, we can attribute an oxidative
[Weber et al. 2020](#ref) for the France area, we can attribute an oxidative
potential (OP) of a set of sources. A simple multiplication end up with the
sources contribution to the oxidative potential of PM.
sources contribution to the oxidative potential of PM<sub>10</sub>.
### Pitfall
This method is a crude, first order approximation of the sources contribution
to the ambient PM10 concentration. The learning set is representative of
urbanized area over France, for year between 2013 to 2018.
The oxidative potential of the sources does present some variation for a given source
at different location. In this method we only take into account for the mean value of them.
For this two reason, this method should be used cautiously and only give a first
idea of what could be the OP of your PM10 timeserie.
**This method is a crude, first order approximation** of the sources contribution
to the ambient PM<sub>10</sub> concentration. The learning set is representative of
14 urbanized area over France, for years between 2013 to 2018 and your site
location may be influenced by sources not present in our learning set. Notably,
it assumes a steady state situation for the relative contribution of the
sources which may be deemed invalid when evaluating the impact of Low Emission Zone for
instance.
Moreover, **the oxidative potential of the sources do present some variation for a given source**
at different location but this method we only take into account for the mean value of them.
For this two reasons, this method should be used cautiously and only give a first
idea of what could be the OP of your PM<sub>10</sub> timeserie.
......@@ -21,7 +21,6 @@ matplotlib==3.0.3
numpy==1.18.1
pandas==0.25.3
patsy==0.5.1
pkg-resources==0.0.0
plotly==4.5.0
py4pm==0.3
pyOPestimator==0.1.1
......
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