From b9d8f28834fc3146ad33458dd8f06e9778c14fba Mon Sep 17 00:00:00 2001 From: lfbsdev Date: Fri, 8 Apr 2022 19:22:52 -0300 Subject: [PATCH 1/4] add basic dash layout - add app.py with html components & web server - add assets/main.css for styling --- data_processing/app.py | 28 ++++++++++++++++++ data_processing/assets/main.css | 51 +++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 data_processing/app.py create mode 100644 data_processing/assets/main.css diff --git a/data_processing/app.py b/data_processing/app.py new file mode 100644 index 0000000..aaf8bf4 --- /dev/null +++ b/data_processing/app.py @@ -0,0 +1,28 @@ +# Run this app with `python app.py` and +# visit http://127.0.0.1:8050/ in your web browser. + +from dash import Dash, dcc, html +import plotly.express as px +import pandas as pd + +app = Dash(__name__) + +app.layout = html.Div(children=[ + + html.Main(children=[ + html.Div(children=[ + html.H1(children=['DirtViz']), + html.H3(children=['A soil-battery data dashboard made with Dash']) + ]), + html.Div(className="flex", children=[ + html.Div(id="graph1",className="flexItem"), + html.Div(id="graph2",className="flexItem"), + html.Div(id="graph3",className="flexItem"), + html.Div(id="graph4",className="flexItem"), + html.Div(id="graph5",className="flexItem"), + ]) + ]), +]) + +if __name__ == '__main__': + app.run_server(debug=True) diff --git a/data_processing/assets/main.css b/data_processing/assets/main.css new file mode 100644 index 0000000..039cc5e --- /dev/null +++ b/data_processing/assets/main.css @@ -0,0 +1,51 @@ +body{ + background-color: #635e55; + color:cornsilk; + font-family: 'Courier New', Courier, monospace; +} + +Main{ + margin: 3% 4%; + background-color: #403936; + border-radius: 10px; + padding: 0.4% 2%; +} + +.flex{ + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-items: flex-end; +} + +.flexItem{ + background-color: chocolate; + flex-basis: auto; + margin: 2% 2%; +} + +#graph1{ + width: 700px; + height: 400px; +} + +#graph2{ + width: 1000px; + height: 400px; +} + +#graph3{ + width: 700px; + height: 500px; +} + +#graph4{ + width: 400px; + height: 300px; +} + +#graph5{ + width: 200px; + height: 400px; +} \ No newline at end of file From e5c505d9ef48e079998efc3962a8688de9c7739d Mon Sep 17 00:00:00 2001 From: lfbsdev Date: Mon, 11 Apr 2022 12:35:37 -0300 Subject: [PATCH 2/4] style: small changes in main.css --- data_processing/assets/main.css | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/data_processing/assets/main.css b/data_processing/assets/main.css index 039cc5e..d14ffb4 100644 --- a/data_processing/assets/main.css +++ b/data_processing/assets/main.css @@ -1,14 +1,11 @@ body{ - background-color: #635e55; - color:cornsilk; font-family: 'Courier New', Courier, monospace; + background-color: #0d0c0c; + color:#FFFDE7; } Main{ - margin: 3% 4%; - background-color: #403936; - border-radius: 10px; - padding: 0.4% 2%; + margin: 1% 1%; } .flex{ @@ -20,9 +17,12 @@ Main{ } .flexItem{ - background-color: chocolate; + background-color: #121212; flex-basis: auto; - margin: 2% 2%; + margin: 0.7% 0.7%; + padding: 5px 5px; + box-shadow: 3px 3px 10px rgb(0 0 0 / 0.2); + border-radius: 10px; } #graph1{ @@ -46,6 +46,6 @@ Main{ } #graph5{ - width: 200px; - height: 400px; + width: 300px; + height: 500px; } \ No newline at end of file From 3e1d2a2d2ee7508186e55719fb55ccc018730a1b Mon Sep 17 00:00:00 2001 From: lfbsdev Date: Mon, 11 Apr 2022 12:36:22 -0300 Subject: [PATCH 3/4] feature: add c_impedance plot --- data_processing/app.py | 26 ++++---- data_processing/c_impedance.py | 107 ++++++++++++--------------------- 2 files changed, 50 insertions(+), 83 deletions(-) diff --git a/data_processing/app.py b/data_processing/app.py index aaf8bf4..94d8123 100644 --- a/data_processing/app.py +++ b/data_processing/app.py @@ -3,25 +3,23 @@ from dash import Dash, dcc, html import plotly.express as px +from c_impedance import c_impedance_plot import pandas as pd app = Dash(__name__) -app.layout = html.Div(children=[ - - html.Main(children=[ - html.Div(children=[ - html.H1(children=['DirtViz']), - html.H3(children=['A soil-battery data dashboard made with Dash']) - ]), - html.Div(className="flex", children=[ - html.Div(id="graph1",className="flexItem"), - html.Div(id="graph2",className="flexItem"), - html.Div(id="graph3",className="flexItem"), - html.Div(id="graph4",className="flexItem"), - html.Div(id="graph5",className="flexItem"), - ]) +app.layout = html.Main(children=[ + html.Div(children=[ + html.H1(children=['DirtViz']), + html.H3(children=['A soil-battery data dashboard made with Dash']) ]), + html.Div(className="flex", children=[ + html.Div(className="flexItem", children= [dcc.Graph(figure=c_impedance_plot())]), + html.Div(id="graph2",className="flexItem"), + html.Div(id="graph3",className="flexItem"), + html.Div(id="graph4",className="flexItem"), + html.Div(id="graph5",className="flexItem"), + ]) ]) if __name__ == '__main__': diff --git a/data_processing/c_impedance.py b/data_processing/c_impedance.py index 92d91fb..e166077 100755 --- a/data_processing/c_impedance.py +++ b/data_processing/c_impedance.py @@ -1,74 +1,43 @@ #!/usr/bin/env python3 -import matplotlib as mpl -mpl.use('Agg') -font= {'family': 'Arial', - 'size': 7} -mpl.rc('font', **font) -import matplotlib.pyplot as plt -import matplotlib.gridspec as gridspec -import matplotlib.dates as md -import numpy as np -from pytz import timezone -import pandas as pd -from glob import glob -import arrow -import os -from pandas.plotting import register_matplotlib_converters -register_matplotlib_converters() +import plotly.graph_objects as go +from plotly.subplots import make_subplots +import pandas as pd -avgdata = []; -avgdata.append({'mcurrent':2.2,'mvoltage':1.38,'mpower':0.003}) -avgdata.append({'mcurrent':3.2,'mvoltage':1.92,'mpower':0.006}) -avgdata.append({'mcurrent':12.3,'mvoltage':15.7,'mpower':0.19}) -avgdata.append({'mcurrent':14.8,'mvoltage':26.7,'mpower':0.4}) -avgdata.append({'mcurrent':16.3,'mvoltage':39.3,'mpower':0.64}) -avgdata.append({'mcurrent':17.1,'mvoltage':48,'mpower':0.82}) -avgdata.append({'mcurrent':17.7,'mvoltage':58.7,'mpower':0.84}) -avgdata.append({'mcurrent':18,'mvoltage':70,'mpower':1.06}) -avgdata.append({'mcurrent':19,'mvoltage':86,'mpower':1.33}) -avgdata.append({'mcurrent':20,'mvoltage':120,'mpower':2.4}) -avgdata.append({'mcurrent':20,'mvoltage':176,'mpower':3.52}) +avgdata = { + 'mcurrent':[2.2, 3.2, 12.3, 14.8, 16.3, 17.1, 17.7, 18, 19, 20, 20], + 'mvoltage':[1.38, 1.92, 15.7, 26.7, 39.3, 48, 58.7, 70, 86, 120, 176], + 'mpower':[0.003, 0.006, 0.19, 0.4, 0.64, 0.82, 0.84, 1.06, 1.33, 2.4, 3.52], + 'impedance':[68, 100, 1e3, 2e3, 3.3e3, 4.7e3, 6.8e3, 9.1e3, 15e3, 39e3, 82e3] + } avgdata = pd.DataFrame(avgdata) -print(avgdata) - -plt.close() - -fig, (ax1, ax3) = plt.subplots(2,figsize=(4,2), sharex=True) - -volt_color= 'tab:blue' -volt_style = 'solid' -amp_color = 'tab:red' -amp_style='dashed' -ax1.set_ylabel('Cell Voltage (mV)') -ax1.plot(avgdata.index, avgdata['mvoltage'], color=volt_color, ls=volt_style) -ax1.tick_params(axis='y', labelcolor=volt_color) -ax1.set_ylim(0, 200) - -ax2 = ax1.twinx() -ax2.set_ylabel('Harvesting Current (μA)') -ax2.plot(avgdata.index, avgdata['mcurrent'], color=amp_color, ls=amp_style) -ax2.tick_params(axis='y', labelcolor=amp_color) -ax2.set_ylim(0,25) - -ax1.tick_params(axis='x', which='both', length=0) -ax2.tick_params(axis='x', which='both', length=0) - -ax1.grid(True) -ax1.legend(['voltage'], loc='lower right') -ax2.legend(['current'], loc='upper left') - -ax3.set_ylabel("Power (uW)") -ax3.set_xlabel("Impedance ($\Omega$)") -ax3.grid(True) -ax3.set_ylim(0, 4) -ax3.plot(avgdata.index, avgdata['mpower']) -plt.xticks(np.arange(11), ['68', '100', '1k', '2k','3.3k','4.7k','6.8k','9.1k','15k','39k','82k']) - -plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=0.5) -plt.subplots_adjust(hspace=0.15) -plt.savefig('c_impedance.pdf') -plt.close() - - +def c_impedance_plot(): + fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, + specs=[[{"secondary_y": True}], [{"secondary_y":False}]] + ) + + fig.add_trace( + go.Scatter(x=avgdata['impedance'], y=avgdata['mvoltage'], mode='lines', name='voltage'), + row=1, col=1, + secondary_y=False + ) + fig.add_trace( + go.Scatter(x=avgdata['impedance'], y=avgdata['mcurrent'], mode='lines', name='current'), + row=1, col=1, + secondary_y=True + ) + fig.add_trace( + go.Scatter(x=avgdata['impedance'], y=avgdata['mpower'], mode='lines', showlegend=False), + row=2, col=1 + ) + + fig.update_xaxes(title={'text':"Impedance (Ω)"}, row=2, col=1) + fig.update_yaxes(title={'text':"Cell Voltage (mV)", 'standoff':5}, row=1,col=1, secondary_y=False) + fig.update_yaxes(title={'text':"Harvesting Current (μA)"}, row=1,col=1, secondary_y=True) + fig.update_yaxes(title={'text':"Power (uW)", 'standoff':20}, row=2, col=1) + fig.update_layout(height=500, width=700, title="Impedance Subplots",template='plotly_dark', + paper_bgcolor="#121212", plot_bgcolor="#121212" + ) + + return fig \ No newline at end of file From 9acefda1da1661ced2613faa13401129ccef13d1 Mon Sep 17 00:00:00 2001 From: lfbsdev Date: Mon, 11 Apr 2022 17:17:45 -0300 Subject: [PATCH 4/4] feat: add mudbat subplots --- data_processing/app.py | 3 +- data_processing/mudbat_plot.py | 85 ++++++++++++++-------------------- 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/data_processing/app.py b/data_processing/app.py index 94d8123..a4ad7d0 100644 --- a/data_processing/app.py +++ b/data_processing/app.py @@ -4,6 +4,7 @@ from dash import Dash, dcc, html import plotly.express as px from c_impedance import c_impedance_plot +from mudbat_plot import mudbat_plot import pandas as pd app = Dash(__name__) @@ -15,7 +16,7 @@ ]), html.Div(className="flex", children=[ html.Div(className="flexItem", children= [dcc.Graph(figure=c_impedance_plot())]), - html.Div(id="graph2",className="flexItem"), + html.Div(className="flexItem", children= [dcc.Graph(figure=mudbat_plot())]), html.Div(id="graph3",className="flexItem"), html.Div(id="graph4",className="flexItem"), html.Div(id="graph5",className="flexItem"), diff --git a/data_processing/mudbat_plot.py b/data_processing/mudbat_plot.py index 224afb3..f029c4a 100755 --- a/data_processing/mudbat_plot.py +++ b/data_processing/mudbat_plot.py @@ -15,12 +15,14 @@ import arrow import os +import plotly.graph_objects as go +from plotly.subplots import make_subplots + if not os.path.exists("mudbat_data.pkl"): fnames = glob("data/carbon-carbon/mudbat*.csv") mudbat_data = None for fname in sorted(fnames, key=lambda x: int(x.split('.')[0].split('_')[-1])): - print(fname) data = np.genfromtxt(fname, dtype=float, delimiter=',',skip_header=11) if '3' in fname: data = pd.DataFrame({'timestamp':pd.to_datetime(data[:,0], unit='s'), 'current':data[:,3]*-10E-12, 'voltage':data[:,4]*-10E-9}) @@ -30,8 +32,6 @@ if '3' in fname: start = data['timestamp'][0] data['power'] = np.abs(np.multiply(data['current'], data['voltage'])) - data.set_index('timestamp', inplace=True) - print(data) if mudbat_data is None: mudbat_data = data else: @@ -41,56 +41,39 @@ else: mudbat_data = pd.read_pickle("mudbat_data.pkl") -print(mudbat_data) - -mv = mudbat_data.rolling(5*60).mean() -plt.xlabel("Time") -fig, (ax1, ax3) = plt.subplots(2,figsize=(4,2), sharex=True) -fig.autofmt_xdate() - -ind = mv.index > start -mv = mv[ind] +mudbat_data.iloc[:, 1:4] = mudbat_data.iloc[:, 1:4].rolling(5*60).mean() -volt_color= 'tab:blue' -volt_style = 'solid' -amp_color = 'tab:red' -amp_style='dashed' -ax1.set_ylabel('Cell Voltage (V)') -ax1.plot(mv.index, mv['voltage'], color=volt_color, ls=volt_style) -ax1.tick_params(axis='y', labelcolor=volt_color) -ax1.set_ylim(0, .05) +ind = mudbat_data['timestamp'] > start +mudbat_data = mudbat_data[ind] -ax2 = ax1.twinx() -ax2.set_ylabel('Harvesting Current (μA)') -ax2.plot(mv.index, -1E6*mv['current'], color=amp_color, ls=amp_style) -ax2.tick_params(axis='y', labelcolor=amp_color) -ax2.set_ylim(0,50) -ax1.tick_params(axis='x', which='both', length=0) -ax2.tick_params(axis='x', which='both', length=0) -ax1.grid(True) -ax1.legend(['voltage'], loc='upper left' , prop={'size':6}) -ax2.legend(['current'], loc='lower right', prop={'size':6}) +def mudbat_plot(): + fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1, + specs=[[{"secondary_y": True}], [{"secondary_y":False}]], + ) -#ax3.fmt_xdata = md.DateFormatter('%d %h:%m') -ax3.xaxis.set_major_formatter(md.DateFormatter('%m-%d')) -ax3.set_ylabel("Power (uW)") -ax3.grid(True) -ax3.plot(mv.index, 1E6*mv['power']) -ax3.tick_params(axis='x', labelsize=6, rotation=0) -for label in ax3.get_xticklabels(): - label.set_horizontalalignment('center') -ax3.set_xlim(mv.index[0], datetime.date(2020,5,27)) -ax3.set_ylim(0,1) + fig.add_trace( + go.Scatter(x=mudbat_data['timestamp'], y=mudbat_data['voltage'], mode='lines', name='voltage'), + row=1, col=1, + secondary_y=False + ) + fig.add_trace( + go.Scatter(x=mudbat_data['timestamp'], y=mudbat_data['current'], mode='lines', name='current'), + row=1, col=1, + secondary_y=True + ) + fig.add_trace( + go.Scatter(x=mudbat_data['timestamp'], y=mudbat_data['power'], mode='lines', showlegend=False), + row=2, col=1 + ) -plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=0.5) -plt.subplots_adjust(hspace=0.15) -#plt.show() -plt.savefig('c-c_battery.pdf') -#plt.savefig('soil.png', dpi=180) -tot_energy = np.trapz(mudbat_data['power']) -print(tot_energy) -print(mudbat_data) -after_spike = mudbat_data['power'][60*60*24*5:] -print(np.average(after_spike), np.std(after_spike)) -print((mudbat_data.tail(1).index - mudbat_data.head(1).index).total_seconds()) + fig.update_xaxes(title={'text':"Impedance (Ω)"}, row=2, col=1) + fig.update_yaxes(title={'text':"Cell Voltage (mV)", 'standoff':5}, row=1,col=1, secondary_y=False) + fig.update_yaxes(title={'text':"Harvesting Current (μA)"}, row=1,col=1, secondary_y=True) + fig.update_yaxes(title={'text':"Power (uW)", 'standoff':5}, row=2, col=1) + fig.update_layout(height=500, width=700, title="Mudbat Subplots",template='plotly_dark', + paper_bgcolor="#121212", plot_bgcolor="#121212", + legend={'orientation':'h', 'xanchor':'right', 'yanchor': 'bottom', 'y':1.02, 'x':1} + ) + + return fig \ No newline at end of file