Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
pmall
app_OP
Commits
33da8852
Commit
33da8852
authored
Nov 13, 2020
by
Samuël Weber
Browse files
add component to plot individual pmf
parent
09b98717
Changes
2
Hide whitespace changes
Inline
Side-by-side
apps/app_components.py
View file @
33da8852
...
...
@@ -2,6 +2,7 @@ import dash_core_components as dcc
import
dash_bootstrap_components
as
dbc
import
dash_html_components
as
html
import
plotly.graph_objs
as
go
import
plotly.express
as
px
import
pandas
as
pd
import
sqlite3
import
pyOPestimator
...
...
@@ -15,7 +16,7 @@ def get_station_dropdown_component(stations):
id
=
"station-dropdown"
,
options
=
[{
'label'
:
s
,
'value'
:
s
}
for
s
in
stations
],
multi
=
True
,
value
=
stations
value
=
[
"CHAM"
]
)
],
style
=
{
"position"
:
"relative"
}
...
...
@@ -282,6 +283,48 @@ def get_rawdata_timeserie_component():
]
return
timeserie_component
def
get_profile_and_contribution_component
():
profile_component
=
html
.
Div
(
id
=
"pmf-profile-and-contribution-per-station"
,
children
=
[
html
.
H3
(
"""PMF solution obtained for a given site
"""
,
id
=
"title-pmf-per-station"
,
),
dcc
.
Markdown
(
"""
Percentage of each species apportionned by the given source (in %) and relative
mass contribution to the PM10 mass (in g.g⁻¹). The contribution timeserie is in
µg.m⁻³.
The variability presented here come from the 100 bootstraps (BS) uncertainties
estimation.
"""
),
dbc
.
Row
(
[
dcc
.
Graph
(
id
=
"concentration-graph-per-station"
,
figure
=
{
'data'
:
[],
"layout"
:
{
"title"
:
"Relative concentration"
}},
className
=
"col-12 col-xl-6"
),
dcc
.
Graph
(
id
=
"totalspeciesum-graph-per-station"
,
figure
=
{
'data'
:
[],
"layout"
:
{
"title"
:
"Contribution to total specie sum"
}},
className
=
"col-12 col-xl-6"
),
dcc
.
Graph
(
id
=
"contribution-graph-per-station"
,
figure
=
{
'data'
:
[],
"layout"
:
{
"title"
:
"Temporal contribution"
}},
className
=
"col-12"
)
]
)
]
)
return
profile_component
def
get_profile_component
():
profile_component
=
html
.
Div
(
id
=
"tab-concentration"
,
...
...
@@ -772,6 +815,57 @@ def plot_box(df, trace_name, x_var, y_var, groupby=None, plot_type="box"):
return
traces
def
plot_ts_errorbar
(
df_mean
,
df_std
,
source
,
hue
=
None
):
if
hue
is
None
:
hue
=
"Station"
levels
=
df_mean
[
hue
].
unique
()
traces
=
[]
for
level
in
levels
:
mean
=
df_mean
.
loc
[
df_mean
[
hue
]
==
level
].
sort_values
(
by
=
"Date"
)
std
=
df_std
.
loc
[
df_std
[
hue
]
==
level
].
sort_values
(
by
=
"Date"
)
# mean
traces
.
append
(
go
.
Scatter
(
x
=
mean
.
loc
[:,
"Date"
],
y
=
mean
.
loc
[:,
source
],
mode
=
"lines+markers"
,
marker
=
dict
(
color
=
get_sourceColor
(
source
),
),
name
=
source
)
)
# std
traces
.
append
(
go
.
Scatter
(
x
=
std
[
"Date"
],
y
=
mean
[
source
]
+
std
[
source
],
mode
=
"lines"
,
line
=
dict
(
width
=
0
),
marker
=
dict
(
color
=
"#444"
),
showlegend
=
False
,
name
=
'BS std'
,
)
)
traces
.
append
(
go
.
Scatter
(
x
=
std
[
"Date"
],
y
=
mean
[
source
]
-
std
[
source
],
mode
=
"lines"
,
line
=
dict
(
width
=
0
),
marker
=
dict
(
color
=
"#444"
),
fillcolor
=
'rgba(68, 68, 68, 0.3)'
,
fill
=
'tonexty'
,
showlegend
=
False
,
name
=
'BS std'
,
)
)
return
traces
def
get_contribution
(
factors
,
species
,
stations
):
# contribtmp = contrib.set_index(["station", "date"], drop=True)
# profiletmp = profile.set_index(["station", "specie"], drop=True)
...
...
apps/app_results.py
View file @
33da8852
...
...
@@ -59,6 +59,7 @@ COMPONENTS = collections.OrderedDict({})
COMPONENTS
[
"rd_ts"
]
=
ac
.
get_rawdata_timeserie_component
()
COMPONENTS
[
"rd_monthly"
]
=
ac
.
get_rawdata_monthly_component
()
COMPONENTS
[
"rd_seasonal"
]
=
ac
.
get_rawdata_seasonal_component
()
COMPONENTS
[
"pmf_profile_and_contribution"
]
=
ac
.
get_profile_and_contribution_component
()
COMPONENTS
[
"pmf_profiles"
]
=
ac
.
get_profile_component
()
COMPONENTS
[
"pmf_deltatool"
]
=
ac
.
get_deltatool_component
()
COMPONENTS
[
"pmf_unc"
]
=
ac
.
get_uncertainty_component
()
...
...
@@ -102,11 +103,12 @@ layout = dbc.Container(
),
dbc
.
Row
(
id
=
"main"
,
className
=
"justify-content-around"
,
children
=
[
# first column
dbc
.
Col
(
id
=
"first-column"
,
sm
=
1
2
,
md
=
4
,
xl
=
3
,
sm
=
2
,
children
=
[
dbc
.
Navbar
([
dbc
.
NavbarToggler
(
id
=
"items-toggler"
),
...
...
@@ -118,32 +120,34 @@ layout = dbc.Container(
[
dbc
.
ListGroupItemHeading
(
"Raw data"
),
dbc
.
NavLink
(
'Timeserie'
,
href
=
"/results?component=rd_ts"
,
id
=
'item-rd_ts'
,
n_clicks
=
0
),
href
=
"/results?component=rd_ts"
,
id
=
'item-rd_ts'
),
dbc
.
NavLink
(
'Montlhy'
,
href
=
"/results?component=rd_monthly"
,
id
=
'item-rd_monthly'
,
n_clicks
=
0
),
href
=
"/results?component=rd_monthly"
,
id
=
'item-rd_monthly'
),
dbc
.
NavLink
(
'Seasonal'
,
href
=
"/results?component=rd_seasonal"
,
id
=
'item-rd_seasonal'
,
n_clicks
=
0
),
href
=
"/results?component=rd_seasonal"
,
id
=
'item-rd_seasonal'
),
dbc
.
ListGroupItemHeading
(
"PMF factor chemistry"
),
dbc
.
NavLink
(
'Profile and contribution per station'
,
href
=
'/results?component=pmf_profile_and_contribution'
,
id
=
'item-pmf_profile_and_contribution'
),
dbc
.
NavLink
(
'Profiles comparison'
,
href
=
'/results?component=pmf_profiles'
,
id
=
'item-pmf_profiles'
,
n_clicks
=
0
),
href
=
'/results?component=pmf_profiles'
,
id
=
'item-pmf_profiles'
),
dbc
.
NavLink
(
'DeltaTool'
,
href
=
"/results?component=pmf_deltatool"
,
id
=
'item-pmf_deltatool'
,
n_clicks
=
0
),
href
=
"/results?component=pmf_deltatool"
,
id
=
'item-pmf_deltatool'
),
dbc
.
NavLink
(
'Uncertainties'
,
href
=
"/results?component=pmf_unc"
,
id
=
'item-pmf_unc'
,
n_clicks
=
0
),
href
=
"/results?component=pmf_unc"
,
id
=
'item-pmf_unc'
),
dbc
.
NavLink
(
'Species repartition'
,
href
=
"/results?component=pmf_speciesrepartition"
,
id
=
'item-pmf_speciesrepartition'
,
n_clicks
=
0
),
href
=
"/results?component=pmf_speciesrepartition"
,
id
=
'item-pmf_speciesrepartition'
),
dbc
.
ListGroupItemHeading
(
"OP model"
),
dbc
.
NavLink
(
'Obs. vs. model'
,
href
=
"/results?component=op_obsvsmodel"
,
id
=
'item-op_obsvsmodel'
,
n_clicks
=
0
),
href
=
"/results?component=op_obsvsmodel"
,
id
=
'item-op_obsvsmodel'
),
dbc
.
NavLink
(
'Intrinsic OP'
,
href
=
"/results?component=op_beta"
,
id
=
'item-op_beta'
,
n_clicks
=
0
),
href
=
"/results?component=op_beta"
,
id
=
'item-op_beta'
),
dbc
.
NavLink
(
'OP contribution (all)'
,
href
=
"/results?component=op_contrib"
,
id
=
'item-op_contrib'
,
n_clicks
=
0
),
href
=
"/results?component=op_contrib"
,
id
=
'item-op_contrib'
),
dbc
.
NavLink
(
'OP contribution (timeseries)'
,
href
=
"/results?component=op_contrib_ts"
,
id
=
'item-op_contrib_ts'
,
n_clicks
=
0
),
href
=
"/results?component=op_contrib_ts"
,
id
=
'item-op_contrib_ts'
),
dbc
.
ListGroupItemHeading
(
"I need help!"
),
dbc
.
NavLink
(
"Don't worry, click here."
,
href
=
"/results?component=help"
,
id
=
"item-help"
,
n_clicks
=
0
)
href
=
"/results?component=help"
,
id
=
"item-help"
)
],
vertical
=
True
,
pills
=
True
...
...
@@ -157,7 +161,7 @@ layout = dbc.Container(
# second column
dbc
.
Col
(
id
=
"graph-component"
,
sm
=
1
2
,
md
=
8
,
xl
=
9
,
sm
=
1
0
,
children
=
ac
.
get_about_app_results_component
()
)
],
...
...
@@ -322,7 +326,7 @@ def get_graph_component(search):
source_disabled
=
True
specie_disabled
=
True
OP_disabled
=
True
if
clicked
in
[
'rd_ts'
,
'rd_monthly'
,
'rd_seasonal'
,
'pmf_profiles'
,
'pmf_deltatool'
,
'pmf_unc'
,
'op_beta'
]:
if
clicked
in
[
'rd_ts'
,
'rd_monthly'
,
'rd_seasonal'
,
'pmf_profile_and_contribution'
,
'pmf_profiles'
,
'pmf_deltatool'
,
'pmf_unc'
,
'op_beta'
]:
source_disabled
=
False
if
clicked
in
[
'pmf_unc'
]:
specie_disabled
=
False
...
...
@@ -751,6 +755,219 @@ def update_concentration_graph(sources, stations):
return
figure
@
app
.
callback
([
Output
(
'title-pmf-per-station'
,
'children'
),
Output
(
'concentration-graph-per-station'
,
'figure'
),
Output
(
'totalspeciesum-graph-per-station'
,
'figure'
),
Output
(
'contribution-graph-per-station'
,
'figure'
),
],
[
Input
(
'source-dropdown'
,
'value'
),
Input
(
'station-dropdown'
,
'value'
),
])
def
update_pmf_details_per_station
(
sources
,
stations
):
data_per_microgram
=
[]
data_total_specie_sum
=
[]
data_ts
=
[]
figure_per_microgram
=
{
"data"
:
data_per_microgram
,
"layout"
:
{
"title"
:
"Relative concentration"
}
}
figure_total_specie_sum
=
{
"data"
:
data_total_specie_sum
,
"layout"
:
{
"title"
:
"Contribution to total specie sum"
}
}
figure_ts
=
{
"data"
:
data_ts
,
"layout"
:
{
"title"
:
"Temporal contribution"
}
}
figures
=
[
figure_per_microgram
,
figure_total_specie_sum
,
figure_ts
]
title
=
"PMF solution obtained for a given site"
if
len
(
stations
)
==
0
:
for
figure
in
figures
:
figure
[
"layout"
][
"title"
]
=
"Select at least one station"
return
[
title
]
+
figures
if
len
(
sources
)
==
0
:
for
figure
in
figures
:
figure
[
"layout"
][
"title"
]
=
"Select at least one source"
return
[
title
]
+
figures
if
len
(
stations
)
!=
1
:
for
figure
in
figures
:
figure
[
"layout"
][
"title"
]
=
"Select one (and only one) station"
return
[
title
]
+
figures
query_contrib
=
"SELECT
\"
{sources}
\"
FROM SRC WHERE Station IN ('{stations}');"
.
format
(
sources
=
'", "'
.
join
(
sources
+
[
"Station"
,
"Date"
]),
stations
=
"', '"
.
join
(
stations
),
)
query_profile
=
"SELECT
\"
{sources}
\"
FROM profiles_constrained WHERE Station IN ('{stations}');"
.
format
(
sources
=
'", "'
.
join
(
sources
+
[
"Station"
,
"Specie"
]),
stations
=
"', '"
.
join
(
stations
),
)
query_BS
=
(
"SELECT * FROM BS_profiles_constrained "
"WHERE Station IN ('{stations}') "
"AND Specie IN ('{species}') "
).
format
(
stations
=
"', '"
.
join
(
stations
),
species
=
"', '"
.
join
(
SPECIES_ORDER_WO_OP
),
)
conn
=
sqlite3
.
connect
(
DBPATH
)
contrib
=
pd
.
read_sql
(
query_contrib
,
con
=
conn
,
index_col
=
[
"Station"
,
"Date"
],
parse_dates
=
[
"Date"
])
profiles
=
pd
.
read_sql
(
query_profile
,
con
=
conn
,
index_col
=
[
"Station"
,
"Specie"
])
BS_profiles
=
pd
.
read_sql
(
query_BS
,
con
=
conn
,
index_col
=
[
"Profile"
,
"Specie"
,
"Station"
])
conn
.
close
()
# Per microgram ================================================================
profiles_normalized
=
profiles
/
profiles
.
xs
(
"PM10"
,
level
=
"Specie"
)
profiles_normalized
=
profiles_normalized
.
reset_index
()
for
source
in
sources
:
BS_normalized
=
(
BS_profiles
.
xs
(
source
,
level
=
"Profile"
)
/
(
BS_profiles
.
xs
(
source
,
level
=
"Profile"
).
loc
[
"PM10"
])
).
reset_index
().
melt
(
id_vars
=
[
"Station"
,
"Specie"
],
value_name
=
source
)
df_plot
=
BS_normalized
.
loc
[
BS_normalized
[
"Station"
].
isin
(
stations
)]
data_per_microgram
.
append
(
go
.
Box
(
x
=
df_plot
[
"Specie"
],
y
=
df_plot
[
source
],
marker
=
dict
(
color
=
ac
.
get_sourceColor
(
source
)),
name
=
"{}"
.
format
(
source
)
)
)
# specie to plot
figure_per_microgram
=
{
'data'
:
data_per_microgram
,
'layout'
:
go
.
Layout
(
title
=
"Contribution to the mass of PM10"
,
yaxis
=
{
"title"
:
"g/g of PM10"
,
"type"
:
"log"
,
"range"
:
[
-
6
,
1
]
},
xaxis
=
{
'categoryorder'
:
'array'
,
'categoryarray'
:
SPECIES_ORDER_WO_OP
,
},
showlegend
=
True
,
boxmode
=
'group'
,
margin
=
go
.
layout
.
Margin
(
l
=
50
,
r
=
00
,
b
=
50
,
t
=
50
,
pad
=
0
),
legend
=
dict
(
orientation
=
"h"
)
)
}
# Total specie sum =============================================================
for
source
in
sources
:
BS_sum
=
BS_profiles
.
groupby
(
"Specie"
).
sum
()
species
=
BS_profiles
.
index
.
get_level_values
(
"Specie"
).
unique
()
df_plot
=
pd
.
DataFrame
(
columns
=
BS_sum
.
columns
,
index
=
BS_sum
.
index
)
for
BS
in
BS_sum
.
columns
:
df_plot
[
BS
]
=
BS_profiles
.
xs
(
source
,
level
=
"Profile"
).
droplevel
(
"Station"
)[
BS
].
divide
(
BS_sum
[
BS
])
*
100
df_plot
.
index
.
names
=
[
"Specie"
]
df_plot
=
df_plot
.
reset_index
().
melt
(
id_vars
=
[
"Specie"
],
value_name
=
"BS"
)
data_total_specie_sum
.
append
(
go
.
Box
(
x
=
df_plot
[
"Specie"
],
y
=
df_plot
[
"BS"
],
marker
=
dict
(
color
=
ac
.
get_sourceColor
(
source
)),
name
=
source
)
)
figure_total_specie_sum
=
{
'data'
:
data_total_specie_sum
,
'layout'
:
go
.
Layout
(
title
=
"Contribution to total specie sum"
,
yaxis
=
{
"title"
:
"% of total specie sum"
,
"range"
:
[
0
,
100
]
},
xaxis
=
{
'categoryorder'
:
'array'
,
'categoryarray'
:
SPECIES_ORDER_WO_OP
},
showlegend
=
True
,
boxmode
=
'group'
,
margin
=
go
.
layout
.
Margin
(
l
=
50
,
r
=
00
,
b
=
50
,
t
=
50
,
pad
=
0
),
legend
=
dict
(
orientation
=
"h"
)
)
}
# Temporal contribution ================================================================
contrib_norm
=
(
contrib
/
profiles
.
xs
(
"PM10"
,
level
=
"Specie"
))
df_mean
=
pd
.
DataFrame
(
index
=
contrib_norm
.
index
,
columns
=
sources
)
df_std
=
pd
.
DataFrame
(
index
=
contrib_norm
.
index
,
columns
=
sources
)
# compute the mean and std given the BS
for
specie
in
[
"PM10"
]:
for
source
in
sources
:
d
=
pd
.
DataFrame
(
columns
=
BS_profiles
.
columns
,
index
=
contrib_norm
.
index
)
for
BS
in
BS_profiles
.
columns
:
d
[
BS
]
=
contrib_norm
[
source
]
*
BS_profiles
.
xs
(
source
,
level
=
"Profile"
).
loc
[
specie
][
BS
]
df_mean
[
source
]
=
d
.
mean
(
axis
=
1
)
df_std
[
source
]
=
d
.
std
(
axis
=
1
)
for
source
in
sources
:
data_ts
+=
ac
.
plot_ts_errorbar
(
df_mean
.
reset_index
(),
df_std
.
reset_index
(),
source
)
figure_ts
=
{
'data'
:
data_ts
,
'layout'
:
go
.
Layout
(
title
=
"Contribution to the mass of PM10"
,
yaxis
=
{
"title"
:
"µg/m⁻³"
,
},
showlegend
=
True
,
margin
=
go
.
layout
.
Margin
(
l
=
50
,
r
=
00
,
b
=
50
,
t
=
50
,
pad
=
0
),
legend
=
dict
(
orientation
=
"h"
)
)
}
figures
[
0
]
=
figure_per_microgram
figures
[
1
]
=
figure_total_specie_sum
figures
[
2
]
=
figure_ts
title
=
"PMF solution obtained for the site of {}"
.
format
(
stations
[
0
])
values
=
[
title
]
+
figures
return
values
@
app
.
callback
(
Output
(
'uncertainty-graph-conc'
,
'figure'
),
[
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment