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

clean dir

parent 9d2fdbd9
# -*- coding: utf-8 -*-
import dash
import dash_auth
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import plotly.graph_objs as go
import urllib
import pandas as pd
import sqlite3
from app_setting import server_setting, BDDPATH, BASEURL, ENABLE_AUTH, VALID_USERNAME_PASSWORD_PAIRS
def add_season(df):
"""
Add a season column to the DataFrame df from it index.
copy: Boolean, default False
either or not copy the initial dataframe
"""
month_to_season = pd.np.array([
None,
'DJF', 'DJF',
'MAM', 'MAM', 'MAM',
'JJA', 'JJA', 'JJA',
'SON', 'SON', 'SON',
'DJF'
])
df_tmp = df.copy()
# ensure we have date in index
df_tmp.index = pd.to_datetime(df_tmp["date"])
df_tmp["season"] = month_to_season[df_tmp.index.month]
df_tmp["season"] = df_tmp["season"].astype("category")
df_tmp["season"].cat.set_categories(["DJF","MAM","JJA","SON"], inplace=True)
return df_tmp
conn = sqlite3.connect("{BDDPATH}/db.sqlite".format(BDDPATH=BDDPATH))
df = pd.read_sql('SELECT * FROM `values_all`;', conn)
df.date = pd.to_datetime(df.date)
list_station= df.station.unique()
list_station_OP = df.loc[pd.notnull(df["PO_AA_m3"]),"station"].unique()
notNumeric = ["index", "number ID", "date", "sample ID","sample ID_PO",
"sample ID_chem", "Particle size",
"commentary", "big serie", "station"]
# do not add species to plot when we already have too many...
tooManyPlot = 30
minSample = 40
class AppOptions():
def __init__(self, tsplot=True, boxplot=True):
self.tsplot=tsplot
self.boxplot=boxplot
LocalOption=AppOptions()
getting_help_text= '''
### Getting help
#### Dash
This app is written with [Dash](https://plot.ly/dash/), so the graph are
interactive and responsive. *Hover* over points to see their values, *click* on
legend items to toggle traces, *click and drag* to zoom, *hold down shift, and
click and drag* to pan.
#### This app
Check the [README file](https://github.com/weber-s/apli_dash) on github for an
example on how to use this app.
'''
app = dash.Dash(url_base_pathname=BASEURL)
if ENABLE_AUTH:
auth = dash_auth.BasicAuth(
app,
VALID_USERNAME_PASSWORD_PAIRS
)
app.layout = html.Div(children=[
html.Div(children=[
html.Div(children=[
'''Select station(s) and specie(s).''',
html.Div(children=[
html.Label('Station'),
dcc.Dropdown(
id="station-dropdown",
options=[{'label': s, 'value': s} for s in list_station if
df[df["station"]==s].shape[0]>minSample],
multi=True,
value=["ANDRA-PM10"]
),
html.Div(children=[
"""Minimum sample #""",
dcc.Slider(
id='nbsample-slider',
marks={str(i): i for i in pd.np.arange(0,301,10)},
min=0,
max=300,
value=50
),
], style={'display':'inline-block', 'width':'80%'}),
html.Div(
dcc.Checklist(
id='hasOP_check',
options=[{'label': 'With OP', 'value': 'hasOP'}],
values=['noOP'],
labelStyle={'display':'block'}
),
style={'display': 'inline-block',
'vertical-align':'top',
'margin-left': '15px'}
),
html.Br(),
html.Label('Species'),
dcc.Dropdown(
id='specie-dropdown',
options=[{'label': "OC", 'value': "OC"}],
multi=True,
value=["date", "Particle size", "station"]
),
]),
html.Div([
html.Div([
html.Button(id='refresh-button',
children="Refresh download data"),
html.A(children='>Download link<',
id='download-data',download="rawdata.csv",
href="",target="_blank", style={"padding":"10px"})
],
style={"margin":"10px"}),
html.Div(children=[
dt.DataTable(
rows=[{}], # initialise the rows
row_selectable=True,
filterable=True,
sortable=True,
editable=False,
selected_row_indices=[],
id='datatable'
)
]),
],
style={"border-style": "solid",
"margin": "10px auto 10px"}),
html.Div([
dcc.Markdown(children=getting_help_text)
]),
], style={"display": "inline-block",
"width": "55%",
"vertical-align":"top"}),
html.Div(children=[
html.Div(children=[
dcc.Graph(
id='ts-graph',
figure={
'layout': {
'title': 'Time serie(s)'
}
}
)
]),
html.Div(children=[
dcc.Graph(
id='box-graph',
figure={
'layout': {
'title': 'Seasonal variation'
}
}
)
]),
],style={"display": "inline-block", "width": "40%"})
])
])
@app.callback(Output('station-dropdown', 'options'),
[Input('nbsample-slider', 'value'),
Input('hasOP_check', 'values')])
def set_station_option(nbsample, hasOP):
"""
Limit the station list to the ones with > X samples
"""
stations_tmp = []
if 'hasOP' in hasOP:
stations_tmp += [i for i in list_station if i in list_station_OP]
else:
stations_tmp = list_station
return [{'label': s, 'value': s}
for s in stations_tmp
if df[df["station"]==s].shape[0]>nbsample]
@app.callback(Output('specie-dropdown', 'options'),
[Input('station-dropdown', 'value')])
def set_specie_option(stations):
species=[]
for station in stations:
species = species + [i for i in
df[df["station"]==station].dropna(axis=1,
how="all").columns
if i not in species]
return [{'label': i, 'value': i} for i in species]
@app.callback(Output('datatable', 'rows'),
[Input('station-dropdown', 'value'),
Input('specie-dropdown', 'value'),
Input('hasOP_check', 'values')])
def update_datatable(stations, species, hasOP):
'''
For user selections, return the relevant table
'''
stations_tmp = []
if 'hasOP' in hasOP:
stations_tmp += [i for i in stations if i in list_station_OP]
else:
stations_tmp = stations
dftmp = df.loc[df["station"].isin(stations_tmp),species]
return dftmp.to_dict("records")
@app.callback(Output('datatable', 'columns'),
[Input('station-dropdown', 'value'),
Input('specie-dropdown', 'value')])
def update_datatable_columns(stations,species):
"""
Update columns
"""
default_col = ["date","station","Particle size"]
col = default_col + [i for i in species if i not in default_col]
return col
@app.callback(Output('download-data', 'href'),
[Input('refresh-button', 'n_clicks')],
[State('datatable','rows')])
def update_downloader(click,datatable):
dftmp = pd.DataFrame(datatable)
csvString = dftmp.to_csv(index=False,encoding='utf-8')
csvString = "data:text/csv;charset=utf-8," + urllib.parse.quote(csvString)
return csvString
@app.callback(Output('ts-graph', 'figure'),
[Input('datatable', 'rows')])
def update_ts_graph(datatable):
traces=[]
returnError = {'date': traces,
'layout': {'title': 'Time serie(s)'}
}
if not LocalOption.tsplot:
return returnError
nbPlot = 0 #len(stations) * len(set(species)-set(notNumeric))
if nbPlot > tooManyPlot:
print("TS: too many things to plot... skip it", nbPlot)
return returnError
dfdt = pd.DataFrame(datatable)
stations = dfdt.station.unique()
species = dfdt.columns
if "date" not in dfdt.columns:
print("TS: no date given")
return returnError
if "station" not in dfdt.columns:
print("TS: no station given")
return returnError
for station in stations:
dftmp = dfdt[dfdt["station"]==station]
for specie in species:
if specie in notNumeric:
continue
dftmp = dftmp.sort_values(by="date")
traces.append(go.Scatter(
x=dftmp.loc[:,"date"],
y=dftmp.loc[:,specie],
mode="lines+markers",
name=station+'-'+specie
))
return {
'data': traces,
'layout': go.Layout(
yaxis={"title": "ng or µg /m3"},
showlegend=True,
title="Time serie(s)",
margin=go.Margin(
l=50,
r=0,
b=50,
t=50,
pad=4
),
legend=dict(orientation="h")
)
}
@app.callback(Output('box-graph', 'figure'),
[Input('station-dropdown', 'value'),
Input('specie-dropdown', 'value'),
Input('datatable', 'rows')])
def update_box_grah(stations, species, datatable):
"""Seasonal boxplot"""
traces=[]
returnError = {'date': traces,
'layout': {'title': 'Seasonal dispersion'}
}
nbPlot = len(stations) * len(set(species)-set(notNumeric))
if nbPlot > tooManyPlot:
print("TS: too many things to plot... skip it", nbPlot)
return
if len(species) == 0:
print("BOX: no data to plot, sp:", species)
traces.append(go.Box( y=[0] ))
return {
'data': traces,
'layout': go.Layout(
showlegend=True,
boxmode='group'
)
}
if len(stations) == 0:
print("BOX: no station")
return
dfdt = pd.DataFrame(datatable)
dftmp = add_season(dfdt)
dftmp = dftmp.sort_values(by="season")
for station in stations:
idxStation = dftmp["station"]==station
for specie in species:
if specie in notNumeric:
continue
traces.append(go.Box(
y=dftmp.loc[idxStation,specie],
x=dftmp.loc[idxStation,"season"],
name=station+"-"+specie
))
return {
'data': traces,
'layout': go.Layout(
yaxis={"title": "ng or µg /m3"},
showlegend=True,
boxmode='group',
margin=go.Margin(
l=50,
r=0,
b=50,
t=50,
pad=4
),
legend=dict(orientation="h")
)
}
if __name__ == '__main__':
app.run_server(**server_setting)
# server settigns. Change it for production
server_setting = {
"debug":"True",
"host":"127.0.0.1",
"port":8050
}
# The path to your BDD
BDDPATH="/home/webersa/Documents/apli_dash/"
# base url
BASEURL="/"
# AUTH
ENABLE_AUTH = False
VALID_USERNAME_PASSWORD_PAIRS = [
["user", "mdp"]
]
......@@ -4,10 +4,10 @@
{% block title %}Home{% endblock %}
{% block content %}
The app is at <a href="/pmall_app/">pmall_app</a>.
{% if user.is_authenticated %}
Hi {{ user.username }}!
The app is at <a href="/pmall_app/"> pmall_app </a>
<p><a href="{% url 'logout' %}">logout</a></p>
{% else %}
<p>You are not logged in</p>
......
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