enable access to control tab when no data & improve style

This commit is contained in:
Florian Bezannier
2021-04-21 17:23:43 +02:00
parent 2959c1046d
commit b077ef4ae5
2 changed files with 117 additions and 116 deletions
+33 -41
View File
@@ -46,15 +46,17 @@ def get_marks_from_start_end(start, end):
# pylint: disable=invalid-name
consumption_fig = None
consumption_df = None
trips_map = None
consumption_fig_by_speed = None
consumption_graph_by_temp = None
table_fig = None
ERROR_DIV = dbc.Alert("No data to show, there is probably no trips recorded yet", color="danger")
PADDING_TOP = {"padding-top": "1em"}
consumption_fig = ERROR_DIV
consumption_df = ERROR_DIV
trips_map = ERROR_DIV
consumption_fig_by_speed = ERROR_DIV
consumption_graph_by_temp = ERROR_DIV
table_fig = ERROR_DIV
pandas_options.display.float_format = '${:.2f}'.format
info = ""
battery_info = dbc.Alert("No data to show", color="danger")
battery_info = ERROR_DIV
battery_table = None
@@ -130,42 +132,32 @@ def get_figures(trips: Trips, charging: List[dict]):
html.Tr(
[
html.Td('Average emission:', rowSpan=2),
html.Td("{:.1f} g/km".format(co2_per_km)),
]
),
html.Td("{:.1f} g/km".format(co2_per_km))]),
html.Tr(
[
"{:.1f} g/kWh".format(co2_per_kw),
]
),
html.Tr(
[
html.Td("Average charge speed:"),
html.Td("{:.3f} kW".format(charge_speed))
]
),
html.Tr(
[
html.Td('Average Price:', rowSpan=2),
html.Td("{:.2f} {}/100km".format(price_kw * kw_per_km, ElecPrice.currency)),
]
),
html.Tr(
[
"{:.2f} {}/kWh".format(price_kw, ElecPrice.currency),
]
),
html.Tr(
[
html.Td('Electricity consumption:', rowSpan=2),
html.Td("{:.0f} kWh".format(total_elec)),
]
),
html.Tr(
[
"{:.0f} {}".format(total_elec*price_kw, ElecPrice.currency),
]
),
html.Tr([
html.Td("Average charge speed:", style=PADDING_TOP),
html.Td("{:.3f} kW".format(charge_speed))
]),
html.Tr(html.Td(" ", colSpan=2)),
html.Tr([
html.Td('Average Price:', rowSpan=2, style=PADDING_TOP),
html.Td("{:.2f} {}/100km".format(price_kw * kw_per_km, ElecPrice.currency)),
]),
html.Tr([
"{:.2f} {}/kWh".format(price_kw, ElecPrice.currency),
]),
html.Tr(html.Td(" ", colSpan=2)),
html.Tr([
html.Td('Electricity consumption:', rowSpan=2, style=PADDING_TOP),
html.Td("{:.0f} kWh".format(total_elec)),
]),
html.Tr([
"{:.0f} {}".format(total_elec * price_kw, ElecPrice.currency),
]),
])
battery_table = dash_table.DataTable(
@@ -181,9 +173,9 @@ def get_figures(trips: Trips, charging: List[dict]):
{'id': 'kw', 'name': 'consumption', 'type': 'numeric',
'format': deepcopy(nb_format).symbol_suffix(" kWh").precision(2)},
{'id': 'price', 'name': 'price', 'type': 'numeric',
'format': deepcopy(nb_format).symbol_suffix(" " + ElecPrice.currency).precision(2)}],
data=charging,
editable=True
'format': deepcopy(nb_format).symbol_suffix(" " + ElecPrice.currency).precision(2), 'editable': True}
],
data=charging
)
consumption_by_temp_df = consumption_df[consumption_df["consumption_by_temp"].notnull()]
if len(consumption_by_temp_df) > 0:
+84 -75
View File
@@ -27,8 +27,8 @@ from web.db import set_chargings_price, get_db, set_db_callback
RESPONSE = "-response"
EMPTY_DIV = "empty-div"
ABRP_SWITCH = 'abrp-switch'
CALLBACK_CREATED = False
ERROR_DIV = dbc.Alert("No data to show, there is probably no trips recorded yet", color="danger")
trips: Trips
chargings: List[dict]
min_date = max_date = min_millis = max_millis = step = marks = cached_layout = None
@@ -57,50 +57,56 @@ def diff_dashtable(data, data_previous, row_id_name="row_id"):
return changes
@dash_app.callback(Output('trips_map', 'figure'),
Output('consumption_fig', 'figure'),
Output('consumption_fig_by_speed', 'figure'),
Output('consumption_graph_by_temp', 'children'),
Output('consumption', 'children'),
Output('tab_trips', 'children'),
Output('tab_battery', 'children'),
Output('tab_charge', 'children'),
Output('date-slider', 'max'),
Output('date-slider', 'step'),
Output('date-slider', 'marks'),
Input('date-slider', 'value'))
def display_value(value):
mini = datetime.fromtimestamp(value[0], tz=timezone.utc)
maxi = datetime.fromtimestamp(value[1], tz=timezone.utc)
filtered_trips = Trips()
for trip in trips:
if mini <= trip.start_at <= maxi:
filtered_trips.append(trip)
filtered_chargings = Charging.get_chargings(mini, maxi)
figures.get_figures(filtered_trips, filtered_chargings)
consumption = "Average consumption: {:.1f} kWh/100km".format(float(figures.consumption_df["consumption_km"].mean()))
return figures.trips_map, figures.consumption_fig, figures.consumption_fig_by_speed, \
figures.consumption_graph_by_temp, consumption, figures.table_fig, figures.battery_info, \
figures.battery_table, max_millis, step, marks
def create_callback():
global CALLBACK_CREATED
if not CALLBACK_CREATED:
# pylint: disable=unused-variable
@dash_app.callback(Output('trips_map', 'figure'),
Output('consumption_fig', 'figure'),
Output('consumption_fig_by_speed', 'figure'),
Output('consumption_graph_by_temp', 'children'),
Output('consumption', 'children'),
Output('tab_trips', 'children'),
Output('tab_battery', 'children'),
Output('tab_charge', 'children'),
Output('date-slider', 'max'),
Output('date-slider', 'step'),
Output('date-slider', 'marks'),
Input('date-slider', 'value'))
def display_value(value):
mini = datetime.fromtimestamp(value[0], tz=timezone.utc)
maxi = datetime.fromtimestamp(value[1], tz=timezone.utc)
filtered_trips = Trips()
for trip in trips:
if mini <= trip.start_at <= maxi:
filtered_trips.append(trip)
filtered_chargings = Charging.get_chargings(mini, maxi)
figures.get_figures(filtered_trips, filtered_chargings)
consumption = "Average consumption: {:.1f} kWh/100km".format(
float(figures.consumption_df["consumption_km"].mean()))
return figures.trips_map, figures.consumption_fig, figures.consumption_fig_by_speed, \
figures.consumption_graph_by_temp, consumption, figures.table_fig, figures.battery_info, \
figures.battery_table, max_millis, step, marks
@dash_app.callback(
Output(EMPTY_DIV, "children"),
[Input("battery-table", "data_timestamp")],
[
State("battery-table", "data"),
State("battery-table", "data_previous"),
],
)
def capture_diffs(timestamp, data, data_previous):
if timestamp is None:
raise PreventUpdate
diff_data = diff_dashtable(data, data_previous, "start_at")
for changed_line in diff_data:
if changed_line['column_name'] == 'price':
if not set_chargings_price(get_db(), changed_line['start_at'], changed_line['current_value']):
logger.error("Can't find line to update in the database")
return ""
@dash_app.callback(
Output(EMPTY_DIV, "children"),
[Input("battery-table", "data_timestamp")],
[
State("battery-table", "data"),
State("battery-table", "data_previous"),
],
)
def capture_diffs(timestamp, data, data_previous):
if timestamp is None:
raise PreventUpdate
diff_data = diff_dashtable(data, data_previous, "start_at")
for changed_line in diff_data:
if changed_line['column_name'] == 'price':
if not set_chargings_price(get_db(), changed_line['start_at'], changed_line['current_value']):
logger.error("Can't find line to update in the database")
return ""
CALLBACK_CREATED = True
@dash_app.callback(Output({'role': ABRP_SWITCH + RESPONSE, 'vin': MATCH}, 'children'),
@@ -267,41 +273,44 @@ def serve_layout():
logger.debug("Create new layout")
try:
figures.get_figures(trips, chargings)
data_div = html.Div([
dcc.RangeSlider(
id='date-slider',
min=min_millis,
max=max_millis,
step=step,
marks=marks,
value=[min_millis, max_millis],
),
html.Div([
dbc.Tabs([
dbc.Tab(label="Summary", tab_id="summary",
children=[
html.H2(id="consumption",
children=figures.info),
dcc.Graph(figure=figures.consumption_fig, id="consumption_fig"),
dcc.Graph(figure=figures.consumption_fig_by_speed, id="consumption_fig_by_speed"),
figures.consumption_graph_by_temp
]),
dbc.Tab(label="Trips", tab_id="trips", id="tab_trips", children=[figures.table_fig]),
dbc.Tab(label="Battery", tab_id="battery", id="tab_battery", children=[figures.battery_info]),
dbc.Tab(label="Charge", tab_id="charge", id="tab_charge", children=[figures.battery_table]),
dbc.Tab(label="Map", tab_id="map", children=[
dcc.Graph(figure=figures.trips_map, id="trips_map", style={"height": '90vh'})]),
dbc.Tab(label="Control", tab_id="control", children=dbc.Tabs(id="control-tabs",
children=__get_control_tabs()))
],
id="tabs",
active_tab="summary"),
html.Div(id=EMPTY_DIV),
])])
summary_tab = [html.H2(id="consumption",
children=figures.info),
dcc.Graph(figure=figures.consumption_fig, id="consumption_fig"),
dcc.Graph(figure=figures.consumption_fig_by_speed, id="consumption_fig_by_speed"),
figures.consumption_graph_by_temp]
maps = dcc.Graph(figure=figures.trips_map, id="trips_map", style={"height": '90vh'})
create_callback()
range_slider = dcc.RangeSlider(
id='date-slider',
min=min_millis,
max=max_millis,
step=step,
marks=marks,
value=[min_millis, max_millis],
)
except (IndexError, TypeError, NameError):
summary_tab = figures.ERROR_DIV
maps = figures.ERROR_DIV
logger.warning("Failed to generate figure, there is probably not enough data yet")
logger.debug(traceback.format_exc())
data_div = ERROR_DIV
range_slider = html.Div()
data_div = html.Div([
range_slider,
html.Div([
dbc.Tabs([
dbc.Tab(label="Summary", tab_id="summary", children=summary_tab),
dbc.Tab(label="Trips", tab_id="trips", id="tab_trips", children=[figures.table_fig]),
dbc.Tab(label="Battery", tab_id="battery", id="tab_battery", children=[figures.battery_info]),
dbc.Tab(label="Charge", tab_id="charge", id="tab_charge", children=[figures.battery_table]),
dbc.Tab(label="Map", tab_id="map", children=[maps]),
dbc.Tab(label="Control", tab_id="control", children=dbc.Tabs(id="control-tabs",
children=__get_control_tabs()))
],
id="tabs",
active_tab="summary",
persistence=True),
html.Div(id=EMPTY_DIV),
])])
cached_layout = dbc.Container(fluid=True, children=[html.H1('My car info'), data_div])
return cached_layout