import warnings
import numpy as np
import pandas as pd
from matplotlib.gridspec import GridSpec
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.colors as mcolors
import seaborn as sns
from .utils import get_sourceColor, add_season
def _pretty_specie(text):
map_species = {
"Cl-": "Cl$^-$",
"Na+": "Na$^+$",
"K+": "K$^+$",
"NO3-": "NO$_3^-$",
"NH4+": "NH$_4^+$",
"SO42-": "SO$_4^{2-}$",
"Mg2+": "Mg$^{2+}$",
"Ca2+": "Ca$^{2+}$",
"nss-SO42-": "nss-SO$_4^{2-}$",
"OP_DTT_m3": "OP$^{DTT}_v$",
"OP_AA_m3": "OP$^{AA}_v$",
"OP_DTT_µg": "OP$^{DTT}_m$",
"OP_AA_µg": "OP$^{AA}_m$",
"PM_µg/m3": "PM mass",
}
if text in map_species.keys():
return map_species[text]
else:
return text
[docs]def pretty_specie(text):
if isinstance(text, list):
mapped = [_pretty_specie(x) for x in text]
elif isinstance(text, str):
mapped = _pretty_specie(text)
else:
raise KeyError(
"`text` must be a {x,y}ticklabels, a list of string or string"
)
return mapped
[docs]class Plotter():
"""
Lot's of plot in this class for a PMF object!
"""
def __init__(self, pmf, savedir):
self.pmf = pmf
self.savedir = savedir
def _save_plot(self, formats=["png"], name="plot", DIR=""):
"""Save plot in a given format.
Parameters
----------
formats : list of str, format of the figure (see plt.savefig)
name : string, default "plot". File name.
DIR : string, default "". Directory for saving.
"""
for fmt in formats:
plt.savefig("{DIR}{name}.{fmt}".format(DIR=DIR,
name=name.replace("/", "-"), fmt=fmt))
def _plot_per_microgramm(self, df=None, constrained=True, profile=None, species=None,
new_figure=False, **kwargs):
"""Internal method
"""
pmf = self.pmf
if new_figure:
plt.figure(figsize=(12, 4))
ax = plt.gca()
elif "ax" in kwargs:
ax = kwargs["ax"]
if constrained:
dfprofiles = pmf.dfprofiles_c
else:
dfprofiles = pmf.dfprofiles_b
if df is not None:
d = df.xs(profile, level="Profile") \
/ (df.xs(profile, level="Profile").loc[pmf.totalVar])
d = d.reindex(species).unstack().reset_index()
else:
d = None
dref = dfprofiles[profile] / dfprofiles.loc[pmf.totalVar, profile]
dref = dref.reset_index()
if df is not None:
sns.boxplot(data=d.replace({0: np.nan}), x="Specie", y=0,
color="grey", ax=ax)
sns.stripplot(data=dref.replace({0: np.nan}), x="Specie", y=profile,
ax=ax, jitter=False, color="red")
ax.set_yscale('log')
ax.set_xticklabels(
pretty_specie([t.get_text() for t in ax.get_xticklabels()]),
rotation=90
)
ax.set_ylim((10e-6, 3))
ax.set_ylabel("µg/µg")
ax.set_xlabel("")
ax.set_title(profile)
#Create custom artists
refArtist = plt.Line2D((0, 1),(0, 0), color='red', marker='o', linestyle='')
BSArtist = plt.Rectangle((0, 0), 0, 0, color="grey")
handles = [refArtist, BSArtist]
labels = ["Ref. run", "BS"]
ax.legend(handles=handles, labels=labels, loc="upper left", bbox_to_anchor=(1., 1.), frameon=False)
def _plot_totalspeciesum(self, df=None, constrained=True, profile=None,
species=None, sumsp=None, new_figure=False,
**kwargs):
"""TODO: Docstring for _plot_totalspeciesum.
Parameters
----------
df : TODO
constrained : Boolean, either to use the constrained run or the base run
profile : TODO
species : TODO
sumsp : dataframe with the sum of each species
new_figure : TODO
"""
pmf = self.pmf
if new_figure:
plt.figure(figsize=(12, 4))
ax = plt.gca()
elif "ax" in kwargs:
ax = kwargs["ax"]
if constrained:
dfprofiles = pmf.dfprofiles_c
else:
dfprofiles = pmf.dfprofiles_b
if sumsp is None and df is not None:
sumsp = pd.DataFrame(columns=species, index=['sum'])
for sp in species:
sumsp[sp] = df.loc[(sp, slice(None)), :].mean(axis=1).sum()
if df is not None:
d = df.xs(profile, level="Profile").divide(sumsp.iloc[0], axis=0) * 100
d.index.names = ["Specie"]
d = d.reindex(species).unstack().reset_index()
dref = dfprofiles[profile].divide(dfprofiles.sum(axis=1)) * 100
dref = dref.reset_index()
if df is not None:
sns.barplot(data=d, x="Specie", y=0, color="grey", ci="sd", ax=ax, label="BS (sd)")
sns.stripplot(data=dref, x="Specie", y=0, color="red", jitter=False,
ax=ax, label="Ref. run")
ax.set_xticklabels(
pretty_specie([t.get_text() for t in ax.get_xticklabels()]),
rotation=90
)
ax.set_ylim((0, 100))
ax.set_ylabel("% of total specie sum")
ax.set_xlabel("")
ax.set_title(profile)
h, l = ax.get_legend_handles_labels()
h = h[-2:]
l = l[-2:]
ax.legend(handles=h, labels=l, loc="upper left", bbox_to_anchor=(1., 1.), frameon=False)
def _plot_contrib(self, constrained=True, dfBS=None, dfDISP=None, dfcontrib=None,
profile=None, specie=None, BS=True, DISP=True,
BSDISP=False, new_figure=False, **kwargs):
"""TODO: Docstring for _plot_contrib.
Parameters
----------
dfBS : pd.DataFrame
dfDISP : TODO
dfcontrib : TODO
profile : TODO
specie : TODO
BS : TODO
DISP : TODO
BSDISP : TODO
new_figure : TODO
"""
pmf = self.pmf
if new_figure:
plt.figure(figsize=(12, 4))
ax = plt.gca()
elif "ax" in kwargs:
ax = kwargs["ax"]
if constrained:
dfprofiles = pmf.dfprofiles_c
else:
dfprofiles = pmf.dfprofiles_b
fill_kwarg = dict(
alpha=0.5,
edgecolor="black",
linewidth=0,
)
with sns.axes_style("ticks"):
if BS:
d = pd.DataFrame(
columns=dfBS.columns,
index=dfcontrib.index
)
for BS in dfBS.columns:
d[BS] = dfcontrib[profile] * dfBS.xs(profile, level="Profile").loc[specie][BS]
mstd = d.std(axis=1)
ma = d.mean(axis=1)
plt.fill_between(
ma.index, ma-mstd, ma+mstd,
label="BS (sd)", **fill_kwarg
)
# d.mean(axis=1).plot(marker="*")
if DISP:
d = pd.DataFrame(
columns=dfDISP.columns,
index=dfcontrib.index
)
for DISP in ["DISP Min", "DISP Max"]:
d[DISP] = dfcontrib[profile] * dfDISP.xs(profile, level="Profile").loc[specie][DISP]
plt.fill_between(
d.index, d["DISP Min"], d["DISP Max"],
label="DISP (min-max)", **fill_kwarg
)
plt.plot(
dfcontrib.index, dfcontrib[profile] * dfprofiles.loc[specie, profile],
color="#888a85", marker="*", label="Ref. run"
)
ax.set_ylabel("Contribution to {} ($µg.m^{{-3}}$)".format(specie))
ax.set_xlabel("")
ax.set_title(profile)
ax.legend(loc="upper left", bbox_to_anchor=(1., 1.), frameon=False)
def _plot_profile(self, constrained=True, dfcontrib=None, dfBS=None, dfDISP=None, profile=None,
specie=None, BS=False, DISP=False, BSDISP=False):
"""TODO: Docstring for _plot_profile.
constrained : Boolean, either to use the constrained run or the base one
dfcontrib : TODO
profile : TODO
specie : TODO
BS : TODO
DISP : TODO
BSDISP : TODO
"""
pmf = self.pmf
gs_profile = GridSpec(nrows=2, ncols=1, top=0.95, bottom=0.41, hspace=0.15)
gs_contrib = GridSpec(nrows=3, ncols=1)
fig = plt.figure(figsize=(12, 12))
ax1 = fig.add_subplot(gs_profile[0])
ax2 = fig.add_subplot(gs_profile[1], sharex=ax1)
ax3 = fig.add_subplot(gs_contrib[2])
self._plot_per_microgramm(
df=dfBS, constrained=constrained, profile=profile, species=pmf.species,
new_figure=False, ax=ax1
)
self._plot_totalspeciesum(
df=dfBS, constrained=constrained, profile=profile, species=pmf.species,
new_figure=False, ax=ax2
)
self._plot_contrib(
constrained=constrained,
dfcontrib=dfcontrib,
dfBS=dfBS, dfDISP=dfDISP,
BS=BS, DISP=DISP,
profile=profile, specie=specie,
new_figure=False, ax=ax3
)
# axes[0].xaxis.tick_top()
for ax in fig.axes:
ax.set_title("")
# ax1.set_xticklabels("")
plt.setp(ax1.get_xticklabels(), visible=False)
fig.suptitle(profile)
fig.subplots_adjust(
top=0.95,
bottom=0.05,
left=0.125,
right=0.865,
hspace=0.40,
wspace=0.015
)
def _plot_ts_stackedbarplot(self, df, ax):
idx = df.index
c = get_sourceColor()
# Date index
x = df.index
# Width
# Set it to 1.5 when no overlapping, 1 otherwise.
width = np.ones(len(x))*1.5
deltal = x[1:]-x[:-1]
deltal = deltal.append(pd.TimedeltaIndex([10,], 'D'))
deltar = pd.TimedeltaIndex([3], 'D')
deltar = deltar.append(x[1:]-x[:-1])
width[deltal < np.timedelta64(2, 'D')] = 1
width[deltar < np.timedelta64(2, 'D')] = 1
# Stacked bar plot
count = 0
default_colors = iter(mcolors.TABLEAU_COLORS.values())
for i in range(df.shape[1]):
bottom=df.iloc[:,0:count].sum(axis=1)
count += 1
try:
color = c[df.columns[i]]
except:
color = next(default_colors)
ax.bar(x, df[df.columns[i]],
bottom=bottom,
label=df.columns[i],
width=width,
color=color)
ax.set_ylim(bottom=0)
def _get_polluted_days_mean(self, specie=None, constrained=True, threshold=None):
"""Get the mean contribution of the sources for the given specie for polluted and
non-polluted days define by the threshold
Parameters
----------
specie : str
constrained : boolean
threshold : int
Returns
-------
df : pd.DataFrame
Mean contribution by profile for the 2 categories
"""
if specie is None:
specie = self.pmf.totalVar
df = self.pmf.to_cubic_meter(specie=specie, constrained=constrained)
df["polluted"] = df.sum(axis=1) > threshold
n_polluted = df["polluted"].sum()
n_not_polluted = df["polluted"].count() - n_polluted
df["polluted"].replace(
{
True: "> {} µg/m³\n(n={})".format(threshold, n_polluted),
False: "≤ {} µg/m³\n(n={})".format(threshold, n_not_polluted)
},
inplace=True
)
df = df.melt(id_vars=["polluted"], var_name=["Profile"], value_name=specie)\
.groupby(["polluted", "Profile"])\
.mean()\
.reset_index()\
.pivot(index=["polluted"], columns=["Profile"])
df.columns = df.columns.get_level_values("Profile")
return df
[docs] def plot_per_microgramm(self, df=None, constrained=True, profiles=None, species=None,
plot_save=False, savedir=None):
"""Plot profiles in concentration unique (µg/m3).
Parameters
----------
df : DataFrame with multiindex [species, profile] and an arbitrary
number of column. Default to dfBS_profile_c.
constrained : Boolean, either to use the constrained run or the base run
profiles : list of str, profile to plot (one figure per profile)
species : list of str, specie to plot (x-axis)
plot_save : boolean, default False. Save the graph in savedir.
savedir : string, directory to save the plot.
"""
pmf = self.pmf
if df is None:
if constrained:
if pmf.dfBS_profile_c is None:
pmf.read.read_constrained_bootstrap()
df = pmf.dfBS_profile_c
if pmf.dfprofiles_c is None:
pmf.read.read_constrained_profiles()
else:
if pmf.dfBS_profile_b is None:
pmf.read.read_base_bootstrap()
df = pmf.dfBS_profile_b
if pmf.dfprofiles_b is None:
pmf.read.read_base_profiles()
elif not(isinstance(df, pd.DataFrame)):
raise TypeError("df should be a pandas DataFrame.")
if profiles is None:
if pmf.profiles is None:
pmf.read.read_metadata()
profiles = pmf.profiles
elif not(isinstance(profiles, list)):
raise TypeError("profiles should be a list.")
if species is None:
if pmf.species is None:
pmf.read.read_metadata()
species = pmf.species
elif not(isinstance(species, list)):
raise TypeError("species should be a list.")
if savedir is None:
savedir = self.savedir
for p in profiles:
self._plot_per_microgramm(df=df, constrained=constrained, profile=p, species=species,
new_figure=True)
plt.subplots_adjust(left=0.1, right=0.9, bottom=0.3, top=0.9)
if plot_save:
self._save_plot(DIR=savedir, name=p+"_profile_perµg")
[docs] def plot_totalspeciesum(self, df=None, profiles=None, species=None, constrained=True,
plot_save=False, savedir=None, **kwargs):
"""Plot profiles in percentage of total specie sum (%).
Parameters
----------
df : DataFrame with multiindex [species, profile] and an arbitrary
number of column. Default to dfBS_profile_c.
profiles : list, profile to plot (one figure per profile)
species : list, specie to plot (x-axis)
plot_save : boolean, default False. Save the graph in savedir.
savedir : string, directory to save the plot.
"""
pmf = self.pmf
if df is None:
if constrained:
if pmf.dfBS_profile_c is None:
pmf.read.read_constrained_bootstrap()
df = pmf.dfBS_profile_c
if pmf.dfprofiles_c is None:
pmf.read.read_constrained_profiles()
else:
if pmf.dfBS_profile_b is None:
pmf.read.read_base_bootstrap()
df = pmf.dfBS_profile_b
if pmf.dfprofiles_b is None:
pmf.read.read_base_profiles()
if profiles is None:
if pmf.profiles is None:
pmf.read.read_metadata()
profiles = pmf.profiles
if species is None:
if pmf.species is None:
pmf.read.read_metadata()
species = pmf.species
if savedir is None:
savedir = self.savedir
new_figure = kwargs.pop("new_figure", True)
sumsp = pd.DataFrame(columns=species, index=['sum'])
for sp in species:
sumsp[sp] = df.loc[(sp, slice(None)),:].mean(axis=1).sum()
for p in profiles:
self._plot_totalspeciesum(df=df, profile=p, species=species,
sumsp=sumsp, new_figure=new_figure,
**kwargs)
plt.subplots_adjust(left=0.1, right=0.9, bottom=0.3, top=0.9)
if plot_save:
self._save_plot(DIR=savedir, name=p+"_profile")
[docs] def plot_contrib(self, dfBS=None, dfDISP=None, dfcontrib=None, profiles=None,
specie=None, constrained=True, plot_save=False, savedir=None,
BS=True, DISP=True, BSDISP=False, new_figure=True, **kwargs):
"""Plot temporal contribution in µg/m3.
Parameters
----------
df : pd.DataFrame, default self.dfBS_profile_c
DataFrame with multiindex [species, profile] and an arbitrary number
of column.
dfcontrib : pd.DataFrame, default self.dfcontrib_c
Profile as column and specie as index.
profiles : list of string, default self.profiles
profile to plot (one figure per profile)
specie : string, default totalVar.
specie to plot (y-axis)
plot_save : boolean, default False
Save the graph in savedir.
savedir : string
directory to save the plot
"""
pmf = self.pmf
if (dfBS is None) and (BS):
if constrained:
if pmf.dfBS_profile_c is None:
pmf.read.read_constrained_bootstrap()
dfBS = pmf.dfBS_profile_c
else:
if pmf.dfBS_profile_b is None:
pmf.read.read_base_bootstrap()
dfBS = pmf.dfBS_profile_b
if (dfDISP is None) and (DISP):
if constrained:
if pmf.df_uncertainties_summary_c is None:
pmf.read.read_constrained_uncertainties_summary()
dfDISP = pmf.df_uncertainties_summary_c[["DISP Min", "DISP Max"]]
else:
if pmf.df_uncertainties_summary_b is None:
pmf.read.read_base_uncertainties_summary()
dfDISP = pmf.df_uncertainties_summary_b[["DISP Min", "DISP Max"]]
if dfcontrib is None:
if constrained:
if pmf.dfcontrib_c is None:
pmf.read.read_constrained_contributions()
dfcontrib = pmf.dfcontrib_c
else:
if pmf.dfcontrib_b is None:
pmf.read.read_base_contributions()
dfcontrib = pmf.dfcontrib_b
if profiles is None:
if pmf.profiles is None:
pmf.read.read_metadata()
profiles = pmf.profiles
# if pmf.dfprofiles_c is None:
# pmf.read.read_constrained_profiles()
if specie is None:
if pmf.totalVar is None:
pmf.read.read_metadata()
specie = pmf.totalVar
elif not isinstance(specie, str):
raise ValueError(
"`specie` should be a string, got {}.".format(specie)
)
if savedir is None:
savedir = self.savedir
for p in profiles:
self._plot_contrib(dfBS=dfBS, dfDISP=dfDISP,
dfcontrib=dfcontrib, constrained=constrained,
profile=p, specie=specie, BS=BS, DISP=DISP,
BSDISP=BSDISP, new_figure=new_figure,
**kwargs)
plt.subplots_adjust(left=0.1, right=0.85, bottom=0.1, top=0.9)
if plot_save:
self._save_plot(DIR=savedir, name=p+"_contribution")
[docs] def plot_all_profiles(self, constrained=True, profiles=None, specie=None,
BS=True, DISP=True, BSDISP=False, plot_save=False,
savedir=None):
"""TODO: Docstring for plot_all_profiles.
Parameters
----------
constrained : Boolean, default True
Either to use the constrained run or the base one
profiles : list of string
Profiles to plot
species : ?
{BS, DISP, BSDISP} : boolean, default True, True, False
Use them as error estimation
plot_save : boolean, default False
Either or not saving the plot
savedir : str
Path to save the plot
"""
pmf = self.pmf
if profiles is None:
if pmf.profiles is None:
pmf.read.read_metadata()
profiles = pmf.profiles
if BS:
if constrained:
if pmf.dfBS_profile_c is None:
pmf.read.read_constrained_bootstrap()
dfBS = pmf.dfBS_profile_c
else:
if pmf.dfBS_profile_b is None:
pmf.read.read_base_bootstrap()
dfBS = pmf.dfBS_profile_b
else:
dfBS = None
if DISP:
if constrained:
if pmf.df_uncertainties_summary_c is None:
pmf.read.read_constrained_uncertainties_summary()
dfDISP = pmf.df_uncertainties_summary_c[["DISP Min", "DISP Max"]]
else:
if pmf.df_uncertainties_summary_b is None:
pmf.read.read_base_uncertainties_summary()
dfDISP = pmf.df_uncertainties_summary_b[["DISP Min", "DISP Max"]]
else:
dfDISP = None
if constrained:
if pmf.dfcontrib_c is None:
pmf.read.read_constrained_contributions()
dfcontrib = pmf.dfcontrib_c
else:
if pmf.dfcontrib_b is None:
pmf.read.read_base_contributions()
dfcontrib = pmf.dfcontrib_b
if constrained:
if pmf.dfprofiles_c is None:
pmf.read.read_constrained_profiles()
else:
if pmf.dfprofiles_b is None:
pmf.read.read_base_profiles()
if specie is None:
if pmf.totalVar is None:
pmf.read.read_metadata()
specie = pmf.totalVar
if savedir is None:
savedir = self.savedir
for p in profiles:
self._plot_profile(
constrained=constrained, dfcontrib=dfcontrib, dfBS=dfBS, dfDISP=dfDISP, profile=p,
specie=specie, BS=BS, DISP=DISP, BSDISP=BSDISP
)
if plot_save:
self._save_plot(
DIR=savedir,
name=pmf._site+"_"+p+"_contribution_and_profiles"
)
[docs] def plot_stacked_contributions(self, constrained=True, order=None, plot_kwargs=None,
savedir=None, plot_save=False):
"""Plot a stacked plot for the contributions
Parameters
----------
constrained : TODO
order : TODO
plot_kwargs : TODO
plot_save : boolean, default False
Either or not saving the plot
savedir : str
Path to save the plot
"""
pmf = self.pmf
df = pmf.to_cubic_meter(constrained=constrained)
if order:
if isinstance(order, list):
df = df.reindex(order, axis=1)
else:
df = df.reindex(sorted(df.columns), axis=1)
labels = df.columns
y = np.vstack(df.values).T
colors = [
get_sourceColor(c) for c in labels #get_sourcesCategories(labels)
]
fig, ax = plt.subplots(figsize=(14, 4))
ax.stackplot(df.index, y, colors=colors, labels=labels)
ax.set_ylabel(pmf.totalVar + " (µg m⁻³)")
ax.set_ylim(0, ax.get_ylim()[1])
ax.legend(frameon=False, loc="upper left", bbox_to_anchor=(1., 1.))
plt.subplots_adjust(
top=0.961,
bottom=0.081,
left=0.042,
right=0.87,
hspace=0.2,
wspace=0.2
)
if plot_save:
self._save_plot(
DIR=savedir,
name=pmf._site+"_stacked_contributions"
)
[docs] def plot_seasonal_contribution(self, *args, **kwargs):
warnings.warn(
"plot_seasonal_contribution is deprecated, use plot_seasonal_contributions instead (plural)",
PendingDeprecationWarning
)
self.plot_seasonal_contributions(*args, **kwargs)
[docs] def plot_seasonal_contributions(self, constrained=True, dfcontrib=None, dfprofiles=None, profiles=None,
specie=None, plot_save=False, savedir=None, annual=True,
normalize=True, ax=None, barplot_kwarg={}):
"""Plot the relative contribution of the profiles.
Parameters
----------
dfcontrib : DataFrame with contribution as column and date as index.
dfprofiles : DataFrame with profile as column and specie as index.
profiles : list, profile to plot (one figure per profile)
specie : string, default totalVar. specie to plot
plot_save : boolean, default False. Save the graph in savedir.
savedir : string, directory to save the plot.
annual : plot annual contribution
normalize : plot relative contribution or absolute contribution.
Return
------
df : DataFrame
"""
pmf = self.pmf
if dfcontrib is None:
if constrained:
if pmf.dfcontrib_c is None:
pmf.read.read_constrained_contributions()
dfcontrib = pmf.dfcontrib_c
else:
if pmf.dfcontrib_b is None:
pmf.read.read_base_contributions()
dfcontrib = pmf.dfcontrib_b
if dfprofiles is None:
if constrained:
if pmf.dfprofiles_c is None:
pmf.read.read_constrained_profiles()
dfprofiles = pmf.dfprofiles_c
else:
if pmf.dfprofiles_b is None:
pmf.read.read_base_profiles()
dfprofiles = pmf.dfprofiles_b
if profiles is None:
if pmf.profiles is None:
pmf.read.read_metadata()
profiles = pmf.profiles
if specie is None:
if pmf.totalVar is None:
pmf.read.read_metadata()
specie = pmf.totalVar
if savedir is None:
savedir = self.savedir
if ax is None:
f, ax = plt.subplots(nrows=1, ncols=1, figsize=(7.5, 4.7))
df = pmf.get_seasonal_contribution(specie=specie, normalize=normalize,
annual=annual,
constrained=constrained)
colors = [get_sourceColor(c) for c in df.columns]
df.index = [l.replace("_", " ") for l in df.index]
axes = df.plot.bar(
stacked=True,
rot=0,
color=colors,
ax=ax,
**barplot_kwarg
)
ax.set_ylabel("Normalized contribution" if normalize else "$µg.m^{-3}$")
if normalize:
ax.set_ylim([0, 1])
ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1))
ax.legend("", frameon=False)
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles[::-1], labels[::-1], loc='center left',
bbox_to_anchor=(1, 0.5), frameon=False)
ax.set_xlabel("")
ax.set_title(specie)
plt.subplots_adjust(top=0.90, bottom=0.10, left=0.15, right=0.72)
if plot_save:
title = "_seasonal_contribution_{specie}_{normalize}{annual}".format(
specie=specie,
normalize="normalized" if normalize else "absolute",
annual="_with_annual" if annual else ""
)
self._save_plot(DIR=savedir, name=pmf._site+title)
return (df)
[docs] def plot_stacked_profiles(self, constrained=True, savedir=None, plot_save=False):
"""plot the repartition of the species among the profiles, normalized to
100%
Parameters
----------
constrained : boolean, default True
use the constrained run or not
plot_save : boolean, default False. Save the graph in savedir.
savedir : string, directory to save the plot.
Returns
-------
ax : the axe
"""
pmf = self.pmf
df = pmf.get_total_specie_sum(constrained=constrained)
df = df.sort_index(axis=1)
colors = [get_sourceColor(c) for c in df.columns]
fig, ax = plt.subplots(1, 1, figsize=(12, 4))
df.plot(kind="bar", stacked=True, color=colors, ax=ax)
xticklabels = [t.get_text() for t in ax.get_xticklabels()]
ax.set_xticklabels(pretty_specie(xticklabels), rotation=90)
ax.set_xlabel("")
ax.yaxis.set_major_formatter(mticker.PercentFormatter())
ax.set_ylabel("Normalized contribution (%)")
ax.set_ylim(0, 100)
h, l = ax.get_legend_handles_labels()
h = reversed(h)
l = reversed(l)
ax.legend(h, l, loc="upper left", bbox_to_anchor=(1, 1), frameon=False)
fig.subplots_adjust(bottom=0.275, top=0.96, left=0.09, right=0.83)
if plot_save:
if savedir is None:
savedir = self.savedir
title = "_stacked_profiles"
self._save_plot(DIR=savedir, name=pmf._site+title)
return ax
[docs] def plot_polluted_contribution(self, constrained=True, threshold=None, specie=None,
normalize=True, plot_save=False, savedir=None):
"""Plot a barplot splited by polluted/non-polluted days defined by the threshold
given.
Parameters
----------
constrained : boolean, default True
use the constrained run or not
threshold : int, default 50
Threshold in µg/m³ to define a polluted days
specie : str, default to total variable
specie to use
normalize : boolean, default True
normalized the graph
plot_save : boolean, default False. Save the graph in savedir.
savedir : string, directory to save the plot.
"""
if specie is None:
specie = self.pmf.totalVar
df = self._get_polluted_days_mean(
constrained=constrained,
specie=specie,
threshold=threshold
)
if normalize:
df = (df.T / df.sum(axis=1)).T
colors = get_sourceColor()[df.columns].loc["color"].to_dict()
fig, ax = plt.subplots(1, 1, figsize=(5, 4))
df.plot(
kind="bar",
stacked=True,
color=colors,
ax=ax
)
ax.legend(
loc="center left",
bbox_to_anchor=(1.05, 0.5),
frameon=False
)
fig.subplots_adjust(right=0.6)
if normalize:
ax.set_ylim([0, 1])
ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1))
plt.setp(ax.get_xticklabels(), rotation=0)
ax.set_xlabel("")
fig.suptitle("{}\nContribution of the sources for {}".format(self.pmf._site, specie))
if plot_save:
title = "_polluted_contributions_{}_threshold_{}".format(specie, threshold)
self._save_plot(DIR=savedir, name=pmf._site+title)
[docs] def plot_samples_sources_contribution(self, constrained=True, specie=None,
savedir=None, plot_save=False):
"""Plot bar plot of the contribution per sample (timeserie)
Parameters
----------
constrained : boolean, True
Use the constrained run or the base one
specie : str, default to totalVar
Specie to use
savedir : str, default to self.savedir
Path where to save figure
plot_save : boolean, False
Save the plot as png
"""
pmf = self.pmf
if specie is None:
specie = self.pmf.totalVar
df = pmf.to_cubic_meter(specie=specie)
fig, ax = plt.subplots(figsize=(12, 4))
self._plot_ts_stackedbarplot(df, ax=ax)
# legend stuff
f = plt.gcf()
h, l = ax.get_legend_handles_labels()
f.legend(h, l, loc=7, frameon=False)
ax.set_ylabel(f"{specie} (µg m⁻³)")
fig.subplots_adjust(top=0.90, bottom=0.10, left=0.10, right=0.775)
if plot_save:
if savedir is None:
savedir = self.savedir
self._save_plot(DIR=savedir, name="{}_stacked_sample_for_{}".format(pmf._site, specie))