Project

General

Profile

Download (9.34 KB) Statistics
| Branch: | Tag: | Revision:
1
import base64
2
import datetime
3
import io
4
import argparse
5

    
6

    
7
import dash
8
import dash_core_components as dcc
9
import dash_html_components as html
10
import dash_table
11
from dash.dependencies import Input, Output, State
12

    
13
import plotly.express as px
14
import plotly.graph_objects as go
15
from plotly.subplots import make_subplots
16

    
17
import pandas as pd
18

    
19

    
20
parser = argparse.ArgumentParser(description='Launch dash app to display tubes.')
21
parser.add_argument('datacsv', metavar='data.csv', type=str, 
22
                    help='a csv file with bounds on signals')
23
args = parser.parse_args()
24

    
25
# initial load
26
init_df = pd.read_csv(args.datacsv,index_col=False)
27
init_df_json=init_df.to_json(date_format='iso', orient='split')
28
init_types=init_df['type'].unique()
29
init_typesel_options=[{'label': t, 'value': t} for t in init_types]
30
init_signals = init_df['varid'].unique()
31
init_signals_option = [{'label': i, 'value': i} for i in init_signals]
32

    
33
# TODO: retravailler le cas bool3 pour voir si on a des infos partitionnees
34
# TODO: generer une vrai figure par signal
35
# TODO: extraire les suffixes de contexte booleens pour construire, pour chaque signal, la liste des signaux de partitionnement
36

    
37

    
38
app = dash.Dash(__name__)
39

    
40
app.layout = html.Div([
41
    dcc.Upload(
42
        id='upload-data',
43
        children=html.Div([
44
            'Drag and Drop or ',
45
            html.A('Select Files')
46
        ]),
47
        style={
48
            'width': '100%',
49
            'height': '60px',
50
            'lineHeight': '60px',
51
            'borderWidth': '1px',
52
            'borderStyle': 'dashed',
53
            'borderRadius': '5px',
54
            'textAlign': 'center',
55
            'margin': '10px'
56
        },
57
        # Allow multiple files to be uploaded
58
        multiple=True
59
    ),
60
    dcc.Dropdown(
61
        id="signal_sel",
62
        options=[],
63
        multi=True,
64
        value = []
65
    ),
66
    dcc.Checklist(
67
        id="sameplotcheck",
68
        options=[
69
            {'label': 'Plot on same graph', 'value': 'samegraph'},
70
        ],
71
        value=[]
72
    ),
73
    dcc.Checklist(
74
        id="typesel",
75
        options=[], 
76
        value=[] 
77
    ),
78
    dcc.Graph(id="graph"),
79
    #html.Button("Switch Min/Max", id='btn', n_clicks=0),
80
    html.Div(id='selected-data'),    
81
    html.Div(id='output-data-upload'),    
82
    # Hidden div inside the app that stores the intermediate value
83
    #html.Div(children='Dash: A web application framework for Python.', style={
84
    #    'textAlign': 'center',
85
    #    'color': colors['text']
86
    #}),
87
    html.Div(id='global_df', style={'display': 'none'},
88
             children=init_df_json
89
             )
90
])
91

    
92
# # @app.callback(
93
# #     Output("graph", "figure"), 
94
# #     [Input("btn", "n_clicks")])
95
# # def display_graph(n_clicks):
96
# #     if n_clicks % 2 == 0:
97
# #         x, y = 'timestep', ' __lego_anti_windup_real_10_min'
98
# #     else:
99
# #         x, y = 'timestep', ' __lego_anti_windup_real_10_max'
100

    
101
# #     fig = px.line(df, x=x, y=y)    
102
# #     return fig
103

    
104

    
105
def onesigfig(fig,signal_df,name,row,col):
106
    color='rgba(0,250,0,0.4)'
107
    x, y_min, y_max = 'timestep', 'min', 'max'
108
    type=signal_df['type'].unique()
109
    fig.add_traces(
110
        go.Scatter(
111
            x = signal_df[x],
112
            y = signal_df[y_min],
113
            line = dict(color='rgba(0,0,0,0)',shape='hv'),
114
            name=None),
115
        rows=row,cols=col)
116
    fig.add_traces(
117
        go.Scatter(
118
            x = signal_df[x],
119
            y = signal_df[y_max],
120
            fill='tonexty',
121
            line = dict(shape='hv'),
122
            name=name,
123
            fillcolor =color),
124
        rows=row,cols=col)
125
    fig.add_traces(
126
        go.Scatter(
127
            x=signal_df[x],
128
            y = signal_df[y_max],
129
            line = dict(color = 'black', width=1,shape='hv'),
130
            name=name+'_max'),
131
        rows=row,cols=col)
132
    fig.add_traces(
133
        go.Scatter(
134
            x=signal_df[x],
135
            y = signal_df[y_min],
136
            mode='lines',
137
            line = dict(color = 'black', width=1,shape='hv'),
138
            name=name+'_min'),
139
        rows=row,
140
        cols=col)
141
    if type != 'bool':
142
        fig.update_yaxes(type='linear')
143
    return fig
144
    # fig.add_traces(go.Scatter(x = signal_df[x], y = signal_df[y_min],
145
    #                       line = dict(color='rgba(0,0,0,0)')))
146
    # fig.add_traces(go.Scatter(x = signal_df[x], y = signal_df[y_max],
147
    #                           fill='tonexty',
148
    #                           fillcolor =color))
149
    # fig.add_traces(go.Scatter(x=signal_df[x], y = signal_df[y_max],
150
    #                   line = dict(color = 'black', width=1)))
151
    # fig.add_traces(go.Scatter(x=signal_df[x], y = signal_df[y_min],
152
    #                   line = dict(color = 'black', width=1)))
153
    
154
    #fig = px.line(signal_df, x=x, y=[y_min,y_max],line_shape='hv')
155
    #, fill='tonexty')
156
    #    fig.add_scatter(df, x=x, y=y_max, mode='lines')
157

    
158
def extract_selection(df):
159
    children = html.Div([
160
        html.Hr(),  # horizontal line
161
        dash_table.DataTable(
162
            data=df.to_dict('records'),
163
            columns=[{'name': i, 'id': i} for i in df.columns]
164
        ),
165
        html.Hr(),  # horizontal line
166
    ])
167
    return children
168
        
169
        
170
# Changing dropdown menu or same/split view updates the figure
171
@app.callback(
172
    Output("graph", "figure"),
173
    Output('selected-data', 'children'),
174
    [Input("signal_sel", "value"),
175
     Input("sameplotcheck", "value"),
176
     Input("global_df", 'children')
177
     ])
178
def display_graph_signal(selection,checkval,jsonified):
179
    if 'samegraph' in checkval:
180
        plot_on_same_graph = True
181
    else:
182
        plot_on_same_graph = False
183
    color='rgba(0,250,0,0.4)'
184
    x, y_min, y_max = 'timestep', 'min', 'max'
185
    if selection is None or selection == [] or jsonified == None:
186
        return {}, None
187
        #selection=signals
188
    else:
189
        df=pd.read_json(jsonified, orient='split')
190
        if plot_on_same_graph:
191
            nb_rows=1
192
            fig = make_subplots(rows=nb_rows,
193
                                cols=1,
194
                                )
195
        else:
196
            nb_rows=len(selection)
197
            fig = make_subplots(rows=nb_rows,
198
                                cols=1,
199
                                subplot_titles=selection)
200
        for idx, sig in enumerate(selection):
201
            signal_df = df.query("varid=='" + sig + "'")
202
            if plot_on_same_graph:
203
                row_id=1
204
            else:
205
                row_id=idx+1
206
            onesigfig(fig,signal_df,sig,row_id,1)
207
        fig.update_layout(height=300 * nb_rows)
208
        signals_data=df.query("varid in " + str(selection))
209
        data=extract_selection(signals_data)
210
        return fig, data
211

    
212
# Changing global_df or choice of types updates dropdown menu
213
@app.callback(Output("signal_sel", "options"),
214
              Output("signal_sel", "value"),
215
              Input("global_df", 'children'),
216
              Input('typesel', 'value')
217
              )
218
def update_available_signals(jsonified, typesel):
219
    if jsonified == None:
220
        return [],[]
221
    else:
222
        df=pd.read_json(jsonified, orient='split')
223
        signals_data=df.query('type in ' +str(typesel))
224
        signals=signals_data['varid'].unique()
225
        signals_options=[{'label': i, 'value': i} for i in signals]
226
        return signals_options, signals
227

    
228

    
229
def parse_contents(contents, filename, date):
230
    content_type, content_string = contents.split(',')
231
    decoded = base64.b64decode(content_string)
232
    try:
233
        if 'csv' in filename:
234
            # Assume that the user uploaded a CSV file
235
            #print(decoded)
236
            df = pd.read_csv(
237
                io.StringIO(decoded.decode('utf-8')),
238
                index_col=False
239
            )
240
            #types=df['type'].unique()
241
            #signals = df['varid'].unique()
242
        
243
    except Exception as e:
244
        print(e)
245
        return None, [], [], html.Div([
246
            'There was an error processing this file.'
247
        ])
248

    
249
    return df, html.Div([
250
        html.H5(filename),
251
        html.H6(datetime.datetime.fromtimestamp(date)),
252

    
253
        dash_table.DataTable(
254
            data=df.to_dict('records'),
255
            columns=[{'name': i, 'id': i} for i in df.columns]
256
        ),
257

    
258
        html.Hr(),  # horizontal line
259

    
260
        # For debugging, display the raw contents provided by the web browser
261
        html.Div('Raw Content'),
262
        html.Pre(contents[0:200] + '...', style={
263
            'whiteSpace': 'pre-wrap',
264
            'wordBreak': 'break-all'
265
        })
266
    ])
267

    
268
# Loading new csv, updates types and global_df
269
@app.callback(Output("typesel", 'options'),
270
              Output("typesel", 'value'),
271
              Output("global_df", 'children'),
272
              Output('output-data-upload', 'children'),
273
              Input('upload-data', 'contents'),
274
              State('upload-data', 'filename'),
275
              State('upload-data', 'last_modified')
276
              )
277
def update_df_and_outputlog(list_of_contents, list_of_names, list_of_dates):
278
    if list_of_contents is not None:
279
        #args= zip(list_of_contents, list_of_names, list_of_dates)
280
        #c,n,d= args[0]
281
        df, children = parse_contents(list_of_contents[0], list_of_names[0], list_of_dates[0])
282
        # for c, n, d in
283
        
284
        df_json=df.to_json(date_format='iso', orient='split')
285
        types=df['type'].unique()
286
        typesel_options = [{'label': t, 'value': t} for t in types]
287
        return typesel_options, types, df_json, children
288
    else:
289
        return init_typesel_options, init_types, init_df_json, None
290
        
291
app.run_server(debug=True)
(3-3/3)