sabiharustam /
voltcycle
| 1 | |||
|
0 ignored issues
–
show
|
|||
| 2 | import dash_resumable_upload |
||
| 3 | import dash |
||
| 4 | import dash_html_components as html |
||
| 5 | from dash.dependencies import Input, Output |
||
| 6 | import base64 |
||
| 7 | from os import listdir,system,path,remove |
||
|
0 ignored issues
–
show
|
|||
| 8 | import dash_table_experiments as dt |
||
| 9 | import dash_core_components as dcc |
||
| 10 | from os.path import isfile, join |
||
| 11 | import shutil |
||
| 12 | import time |
||
| 13 | import core |
||
| 14 | import io |
||
| 15 | import plotly.graph_objs as go |
||
| 16 | import pandas as pd |
||
| 17 | import numpy as np |
||
| 18 | |||
| 19 | #try: |
||
| 20 | # system("rm -r uploads")
|
||
| 21 | #except: |
||
| 22 | # pass |
||
| 23 | |||
| 24 | directory = './uploads' |
||
| 25 | |||
| 26 | if path.exists(directory): |
||
| 27 | system("rm -r uploads")
|
||
| 28 | # remove(directory) |
||
| 29 | else: |
||
| 30 | pass |
||
|
0 ignored issues
–
show
|
|||
| 31 | |||
| 32 | app = dash.Dash('')
|
||
| 33 | |||
| 34 | #external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css', 'https://codepen.io/rmarren1/pen/eMQKBW.css'] |
||
|
0 ignored issues
–
show
|
|||
| 35 | #app = dash.Dash(__name__, external_stylesheets=external_stylesheets) |
||
| 36 | |||
| 37 | colors = {
|
||
| 38 | 'background': '#ECF0F1', |
||
| 39 | 'text': '#800000' |
||
| 40 | } |
||
| 41 | |||
| 42 | image_filename = 'Logo.png' # replace with your own image |
||
| 43 | encoded_image = base64.b64encode(open(image_filename, 'rb').read()).decode('ascii')
|
||
| 44 | |||
| 45 | dash_resumable_upload.decorate_server(app.server, "uploads") |
||
| 46 | |||
| 47 | app.scripts.config.serve_locally = True # Uploaded to npm, this can work online now too. |
||
| 48 | |||
| 49 | |||
| 50 | app.css.append_css({
|
||
| 51 | "external_url": "https://codepen.io/rmarren1/pen/eMQKBW.css" |
||
| 52 | }) |
||
| 53 | |||
| 54 | app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[
|
||
| 55 | html.H1( |
||
| 56 | children='VoltCycle', |
||
| 57 | style={
|
||
| 58 | 'textAlign': 'center', |
||
| 59 | 'color': colors['text'] |
||
| 60 | } |
||
| 61 | ), |
||
| 62 | |||
| 63 | html.Div([ |
||
| 64 | html.Img(draggable=True, style={
|
||
| 65 | 'height': '20%', |
||
|
0 ignored issues
–
show
|
|||
| 66 | 'width': '20%' |
||
|
0 ignored issues
–
show
|
|||
| 67 | }, src='data:image/png;base64,{}'.format(encoded_image))
|
||
|
0 ignored issues
–
show
|
|||
| 68 | ], style={'textAlign': 'center'}),
|
||
|
0 ignored issues
–
show
|
|||
| 69 | |||
| 70 | html.H2(children='A Tool for Accelerating the Analysis of Cyclic Voltammetry Data', style={
|
||
| 71 | 'textAlign': 'center', |
||
| 72 | 'color': colors['text'] |
||
| 73 | }), |
||
| 74 | html.Br(), |
||
| 75 | html.Div([ |
||
| 76 | html.Link(rel='stylesheet', href='https://codepen.io/rmarren1/pen/eMQKBW.css'), |
||
|
0 ignored issues
–
show
|
|||
| 77 | dash_resumable_upload.Upload( |
||
|
0 ignored issues
–
show
|
|||
| 78 | id='upload', |
||
| 79 | maxFiles=1, |
||
| 80 | maxFileSize=1024*1024*1000, # 100 MB |
||
| 81 | service="/upload_resumable", |
||
| 82 | textLabel="Upload Files", |
||
| 83 | startButton=False) |
||
| 84 | ]), |
||
| 85 | html.Div(id='output_uploaded_file'), |
||
| 86 | html.Br(), |
||
| 87 | html.H2( |
||
| 88 | children='Select File to Analyze', |
||
| 89 | style={
|
||
| 90 | 'textAlign': 'center', |
||
| 91 | 'color': colors['text'] |
||
| 92 | } |
||
| 93 | ), |
||
| 94 | html.Div([ |
||
| 95 | dcc.Dropdown(id='files_dropdown') |
||
|
0 ignored issues
–
show
|
|||
| 96 | ],style={'width': '70%', 'height': '40', 'display': 'inline-block', 'textAlign': 'center'}
|
||
|
0 ignored issues
–
show
|
|||
| 97 | ), |
||
|
0 ignored issues
–
show
|
|||
| 98 | html.Div([ |
||
| 99 | html.Br(), |
||
| 100 | dcc.Graph(id='CV_graph'), |
||
| 101 | ],style={
|
||
|
0 ignored issues
–
show
|
|||
| 102 | 'columnCount': 1, |
||
| 103 | 'width':'70%', |
||
| 104 | 'height': '80%', |
||
| 105 | } |
||
| 106 | ), |
||
|
0 ignored issues
–
show
|
|||
| 107 | |||
|
0 ignored issues
–
show
|
|||
| 108 | |||
|
0 ignored issues
–
show
|
|||
| 109 | html.Div([ |
||
| 110 | html.Br(), |
||
| 111 | html.H2( |
||
| 112 | children='Redox Properties', |
||
| 113 | style={
|
||
| 114 | 'color': colors['text'] |
||
| 115 | } |
||
| 116 | ), |
||
| 117 | dt.DataTable( |
||
| 118 | rows=[{}],
|
||
| 119 | row_selectable=True, |
||
| 120 | filterable=True, |
||
| 121 | selected_row_indices=[], |
||
| 122 | id='datatable_initial' |
||
| 123 | ), |
||
| 124 | html.Div(id='selected-indexes'), |
||
| 125 | |||
| 126 | ], |
||
| 127 | style={
|
||
|
0 ignored issues
–
show
|
|||
| 128 | 'width': '98%', |
||
| 129 | #'height': '60px', |
||
| 130 | #'lineHeight': '60px', |
||
| 131 | 'margin': '10px' |
||
| 132 | }, |
||
| 133 | ) |
||
|
0 ignored issues
–
show
|
|||
| 134 | |||
| 135 | ]) |
||
| 136 | |||
| 137 | |||
| 138 | def parse_contents(value): |
||
| 139 | |||
| 140 | if path.exists(directory): |
||
| 141 | lines1 = base64.b64encode(open("uploads/%s" % (value), 'rb').read())
|
||
| 142 | lines2 = base64.b64decode(lines1).decode('utf-8').split('\n')
|
||
| 143 | dict_1, n_cycle = core.read_file_dash(lines2) |
||
| 144 | #print(n_cycle) |
||
| 145 | df = core.data_frame(dict_1, 1) |
||
| 146 | return df |
||
| 147 | |||
| 148 | |||
| 149 | def data_analysis(df): |
||
| 150 | results_dict = {}
|
||
| 151 | |||
| 152 | # df = main.data_frame(dict_1,1) |
||
| 153 | x = df['Potential'] |
||
| 154 | y = df['Current'] |
||
| 155 | # Peaks are here [list] |
||
| 156 | peak_index = core.peak_detection_fxn(y) |
||
| 157 | # Split x,y to get baselines |
||
| 158 | x1,x2 = core.split(x) |
||
|
0 ignored issues
–
show
|
|||
| 159 | y1,y2 = core.split(y) |
||
|
0 ignored issues
–
show
|
|||
| 160 | y_base1 = core.linear_background(x1,y1) |
||
|
0 ignored issues
–
show
|
|||
| 161 | y_base2 = core.linear_background(x2,y2) |
||
|
0 ignored issues
–
show
|
|||
| 162 | # Calculations based on baseline and peak |
||
| 163 | values = core.peak_values(x,y) |
||
|
0 ignored issues
–
show
|
|||
| 164 | Et = values[0] |
||
| 165 | Eb = values[2] |
||
| 166 | dE = core.del_potential(x,y) |
||
|
0 ignored issues
–
show
|
|||
| 167 | half_E = min(Et,Eb) + core.half_wave_potential(x,y) |
||
|
0 ignored issues
–
show
|
|||
| 168 | ia = core.peak_heights(x,y)[0] |
||
|
0 ignored issues
–
show
|
|||
| 169 | ic = core.peak_heights(x,y)[1] |
||
|
0 ignored issues
–
show
|
|||
| 170 | ratio_i = core.peak_ratio(x,y) |
||
|
0 ignored issues
–
show
|
|||
| 171 | results_dict['Peak Current Ratio'] = ratio_i |
||
| 172 | results_dict['Ipc (A)'] = ic |
||
| 173 | results_dict['Ipa (A)'] = ia |
||
| 174 | results_dict['Epc (V)'] = Eb |
||
| 175 | results_dict['Epa (V)'] = Et |
||
| 176 | results_dict['∆E (V)'] = dE |
||
| 177 | results_dict['Redox Potential (V)'] = half_E |
||
| 178 | if dE>0.3: |
||
|
0 ignored issues
–
show
|
|||
| 179 | results_dict['Reversible'] = 'No' |
||
| 180 | else: |
||
| 181 | results_dict['Reversible'] = 'Yes' |
||
| 182 | |||
|
0 ignored issues
–
show
|
|||
| 183 | if half_E>0 and 'Yes' in results_dict.values(): |
||
|
0 ignored issues
–
show
|
|||
| 184 | results_dict['Type'] = 'Catholyte' |
||
| 185 | elif 'Yes' in results_dict.values(): |
||
| 186 | results_dict['Type'] = 'Anolyte' |
||
| 187 | return results_dict, x1, x2, y1, y2, y_base1, y_base2, peak_index |
||
| 188 | #return results_dict |
||
| 189 | |||
| 190 | |||
| 191 | @app.callback(Output('output_uploaded_file', 'children'),
|
||
| 192 | [Input('upload', 'fileNames')])
|
||
| 193 | def display_files(fileNames): |
||
| 194 | if fileNames is not None: |
||
| 195 | return html.Ul([html.Li(html.A(x), style={'textAlign': 'center'}) for x in fileNames])
|
||
| 196 | return html.Ul(html.Li("No Files Uploaded Yet!"), style={'textAlign': 'center'})
|
||
| 197 | |||
| 198 | |||
| 199 | @app.callback(Output('files_dropdown', 'options'),
|
||
| 200 | [Input('upload','fileNames')])
|
||
|
0 ignored issues
–
show
|
|||
| 201 | def dropdown_files(fileNames): |
||
| 202 | mypath='./uploads/' |
||
|
0 ignored issues
–
show
|
|||
| 203 | onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))] |
||
| 204 | return [{'label': i, 'value': i} for i in onlyfiles]
|
||
| 205 | |||
| 206 | |||
| 207 | @app.callback( #update charge datatable |
||
| 208 | Output('datatable_initial', 'rows'),
|
||
| 209 | [Input('files_dropdown', 'value')])
|
||
| 210 | def update_table1(value): |
||
| 211 | |||
|
0 ignored issues
–
show
|
|||
| 212 | df = parse_contents(value) |
||
| 213 | #print(df.head()) |
||
| 214 | #final_dict = data_analysis(df) |
||
| 215 | final_dict, x_1, x_2, y_1, y_2, ybase_1, ybase_2, peak_i = data_analysis(df) |
||
| 216 | df1=pd.DataFrame.from_records([final_dict]) |
||
|
0 ignored issues
–
show
|
|||
| 217 | return df1.to_dict('records')
|
||
| 218 | |||
| 219 | |||
| 220 | @app.callback( |
||
| 221 | Output('CV_graph', 'figure'),
|
||
| 222 | [Input('files_dropdown', 'value')])
|
||
| 223 | def update_figure(value): |
||
| 224 | df = parse_contents(value) |
||
| 225 | final_dict, x_1, x_2, y_1, y_2, ybase_1, ybase_2, peak_i = data_analysis(df) |
||
| 226 | |||
|
0 ignored issues
–
show
|
|||
| 227 | trace1 = go.Scatter( |
||
| 228 | x = df['Potential'], |
||
|
0 ignored issues
–
show
|
|||
| 229 | y = df['Current'], |
||
|
0 ignored issues
–
show
|
|||
| 230 | marker={
|
||
|
0 ignored issues
–
show
|
|||
| 231 | 'size': 15, |
||
| 232 | 'opacity': 0.5, |
||
| 233 | 'color' : '#F00000' |
||
| 234 | }) |
||
| 235 | trace2 = go.Scatter( |
||
| 236 | x = x_1, |
||
|
0 ignored issues
–
show
|
|||
| 237 | y = ybase_1, |
||
|
0 ignored issues
–
show
|
|||
| 238 | mode = 'lines', |
||
|
0 ignored issues
–
show
|
|||
| 239 | line = dict( |
||
|
0 ignored issues
–
show
|
|||
| 240 | color = ('rgb(0, 0, 256)'),
|
||
|
0 ignored issues
–
show
|
|||
| 241 | width = 3, |
||
|
0 ignored issues
–
show
|
|||
| 242 | dash = 'dash') |
||
|
0 ignored issues
–
show
|
|||
| 243 | ) |
||
|
0 ignored issues
–
show
|
|||
| 244 | trace3 = go.Scatter( |
||
| 245 | x = x_2, |
||
|
0 ignored issues
–
show
|
|||
| 246 | y = ybase_2, |
||
|
0 ignored issues
–
show
|
|||
| 247 | mode = 'lines', |
||
|
0 ignored issues
–
show
|
|||
| 248 | line = dict( |
||
|
0 ignored issues
–
show
|
|||
| 249 | color = ('rgb(0, 0, 256)'),
|
||
|
0 ignored issues
–
show
|
|||
| 250 | width = 3, |
||
|
0 ignored issues
–
show
|
|||
| 251 | dash = 'dash') |
||
|
0 ignored issues
–
show
|
|||
| 252 | ) |
||
|
0 ignored issues
–
show
|
|||
| 253 | trace4 = go.Scatter( |
||
| 254 | x = np.array(x_1[peak_i[1]]), |
||
|
0 ignored issues
–
show
|
|||
| 255 | y = np.array(y_1[peak_i[1]]), |
||
|
0 ignored issues
–
show
|
|||
| 256 | mode = 'markers', |
||
|
0 ignored issues
–
show
|
|||
| 257 | marker={
|
||
|
0 ignored issues
–
show
|
|||
| 258 | 'size': 35, |
||
| 259 | 'opacity': 0.5, |
||
| 260 | 'color' : '#000080' |
||
| 261 | }) |
||
| 262 | trace5 = go.Scatter( |
||
| 263 | x = np.array(x_2[peak_i[0]]), |
||
|
0 ignored issues
–
show
|
|||
| 264 | y = np.array(y_2[peak_i[0]]), |
||
|
0 ignored issues
–
show
|
|||
| 265 | mode = 'markers', |
||
|
0 ignored issues
–
show
|
|||
| 266 | marker={
|
||
|
0 ignored issues
–
show
|
|||
| 267 | 'size': 35, |
||
| 268 | 'opacity': 0.5, |
||
| 269 | 'color' : '#000080' |
||
| 270 | }) |
||
| 271 | data = [trace1, trace2, trace3, trace4, trace5] |
||
| 272 | |||
|
0 ignored issues
–
show
|
|||
| 273 | return {
|
||
| 274 | 'data': data, |
||
| 275 | #'layout' : {'Dash'}
|
||
| 276 | 'layout': go.Layout( |
||
| 277 | xaxis={'title': 'Voltage (V)'},
|
||
| 278 | yaxis={'title': 'Current (A)'},
|
||
| 279 | margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
|
||
| 280 | # #legend={'x': 0, 'y': 1},
|
||
|
0 ignored issues
–
show
|
|||
| 281 | showlegend = False, |
||
|
0 ignored issues
–
show
|
|||
| 282 | hovermode='closest', |
||
| 283 | ) |
||
| 284 | } |
||
| 285 | |||
| 286 | |||
| 287 | |||
| 288 | # return {
|
||
| 289 | # 'data': [ |
||
| 290 | # {'x': [x1[peak_index[1]]], 'y': [x1[peak_index[1]]], 'type': 'point'},
|
||
| 291 | # #{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
|
||
| 292 | # ], |
||
| 293 | # } |
||
| 294 | |||
| 295 | |||
| 296 | if __name__ == '__main__': |
||
| 297 | app.run_server(debug=True) |
||
| 298 |
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.