Add export functionality, color adjustments

This commit is contained in:
stevoh6
2023-01-13 08:57:38 +01:00
parent a18700b100
commit 0e73405bed
4 changed files with 137 additions and 13 deletions
@@ -14,6 +14,8 @@ logger = logging.getLogger(__name__)
DEFAULT_CONFIG = """[General]
currency = €
# define format for data export, can be csv or xlsx
export_format = csv
# minimum trip length in km so it's added to stats and map in website
minimum trip length =
# for future use
@@ -83,6 +85,7 @@ class GeneralConfig(BaseModel):
currency: str = ""
length_unit: str = "km"
minimum_trip_length: float = 10
export_format = "csv"
class ElectricityPriceConfig(BaseModel):
@@ -0,0 +1,13 @@
#battery-table button.export,
#trips-table button.export {
display: none;
}
div.export-load-anim div.dash-sk-circle {
width: 20px;
height: 20px;
}
.dash-table-container .dash-spreadsheet-container .dash-spreadsheet-inner tr:hover > td:not(.focused) {
background-image: linear-gradient(#ffeb3b75 0 0);
}
+49 -11
View File
@@ -5,7 +5,7 @@ from dash import html
from dash.dash_table import DataTable
import plotly.express as px
import plotly.graph_objects as go
from dash.dash_table.Format import Scheme, Symbol, Format
from dash.dash_table.Format import Scheme, Symbol, Group, Format
from dash.dcc import Graph
from psa_car_controller.psacc.application.charging import Charging
@@ -35,6 +35,7 @@ ELEC_CONSUM_PRICE = "elec_consum_price"
AVG_CONSUM_KW = "avg_consum_kw"
AVG_CONSUM_PRICE = "avg_consum_price"
CURRENCY = ""
EXPORT_FORMAT = "csv"
SUMMARY_CARDS = {"Average consumption": {"text": [card_value_div(AVG_CONSUM_KW, "kWh/100km"),
card_value_div(AVG_CONSUM_PRICE, f"{CURRENCY}/100km")],
@@ -62,7 +63,7 @@ def get_figures(car: Car):
lon=[lons[0]], lat=[lats[0]],
showlegend=False, name="Last Position"))
# table
nb_format = Format(precision=2, scheme=Scheme.fixed, symbol=Symbol.yes) # pylint: disable=no-member
nb_format = Format(precision=2, scheme=Scheme.fixed, symbol=Symbol.yes, group=Group.yes)
style_cell_conditional = []
if car.is_electric():
style_cell_conditional.append({'if': {'column_id': 'consumption_fuel_km', }, 'display': 'None', })
@@ -70,15 +71,22 @@ def get_figures(car: Car):
style_cell_conditional.append({'if': {'column_id': 'consumption_km', }, 'display': 'None', })
table_fig = DataTable(
id='trips-table',
export_format=EXPORT_FORMAT,
sort_action='custom',
sort_by=[{'column_id': 'id', 'direction': 'desc'}],
style_data={
'width': '10%',
'maxWidth': '10%',
'minWidth': '10%',
'color': 'gray'
},
columns=[{'id': 'id', 'name': '#', 'type': 'numeric'},
{'id': 'start_at_str', 'name': 'start at', 'type': 'datetime'},
{'id': 'duration', 'name': 'duration', 'type': 'numeric',
'format': deepcopy(nb_format).symbol_suffix(" min").precision(0)},
{'id': 'speed_average', 'name': 'average speed', 'type': 'numeric',
{'id': 'speed_average', 'name': 'avg. speed', 'type': 'numeric',
'format': deepcopy(nb_format).symbol_suffix(" km/h").precision(0)},
{'id': 'consumption_km', 'name': 'average consumption', 'type': 'numeric',
{'id': 'consumption_km', 'name': 'avg. consumption', 'type': 'numeric',
'format': deepcopy(nb_format).symbol_suffix(" kWh/100km")},
{'id': 'consumption_fuel_km', 'name': 'average consumption fuel', 'type': 'numeric',
'format': deepcopy(nb_format).symbol_suffix(" L/100km")},
@@ -86,14 +94,17 @@ def get_figures(car: Car):
'format': nb_format.symbol_suffix(" km").precision(1)},
{'id': 'mileage', 'name': 'mileage', 'type': 'numeric',
'format': nb_format},
{'id': 'altitude_diff', 'name': 'Altitude diff', 'type': 'numeric',
{'id': 'altitude_diff', 'name': 'altitude diff', 'type': 'numeric',
'format': deepcopy(nb_format).symbol_suffix(" m").precision(0)}
],
style_data_conditional=[
{
'if': {'column_id': ['id']},
'width': '5%'
},
{
'if': {'column_id': ['altitude_diff']},
'color': 'dodgerblue',
"text-decoration": "underline"
'color': 'black'
}
],
style_cell_conditional=style_cell_conditional,
@@ -113,11 +124,17 @@ def get_figures(car: Car):
consumption_fig_by_speed.add_trace(go.Scatter(mode="markers", x=[0],
y=[0], name="Trips"))
consumption_fig_by_speed.update_layout(xaxis_title="average Speed km/h", yaxis_title="Consumption kWh/100Km")
# battery_table
battery_table = DataTable(
id='battery-table',
export_format=EXPORT_FORMAT,
sort_action='custom',
style_data={
'width': '10%',
'maxWidth': '10%',
'minWidth': '10%',
'color': 'gray'
},
sort_by=[{'column_id': 'start_at_str', 'direction': 'desc'}],
columns=[{'id': 'start_at_str', 'name': 'start at', 'type': 'datetime'},
{'id': 'stop_at_str', 'name': 'stop at', 'type': 'datetime'},
@@ -133,15 +150,36 @@ def get_figures(car: Car):
{'id': 'mileage', 'name': 'mileage', 'type': 'numeric', 'format': nb_format},
],
data=[],
page_size=50,
style_data_conditional=[
{
'if': {'column_id': ['start_level', "end_level"]},
'color': 'dodgerblue',
"text-decoration": "underline"
'color': 'black'
},
{
'if': {
'filter_query': '{start_level} < 15',
'column_id': 'start_level'
},
'color': 'red'
},
{
'if': {
'filter_query': '{end_level} > 85',
'column_id': 'end_level'
},
'color': 'green'
},
{
'if': {
'filter_query': '{charging_mode} = "Quick"'
},
'backgroundColor': 'ivory'
},
{
'if': {'column_id': 'price'},
'backgroundColor': '#ABE2FB'
'color': 'dodgerblue',
'font-weihgt': 'bold'
}
],
)
+72 -2
View File
@@ -7,6 +7,7 @@ from dash import dcc, html
from dash.dependencies import Output, Input, State
from dash.exceptions import PreventUpdate
from flask import jsonify, request, Response as FlaskResponse
import time
from psa_car_controller.common.mylogger import CustomLogger
from psa_car_controller.psacc.application.car_controller import PSACarController
@@ -125,7 +126,39 @@ def create_callback(): # noqa: MC0001
return figures.get_altitude_fig(trips[active_cell["row_id"] - 1]), True
return "", False
@dash_app.callback(Output("loading-output-trips", "children"), Input("export-trips-table", "n_clicks"))
def export_trips_loading_animation(n_clicks): # pylint: disable=unused-argument
time.sleep(3)
@dash_app.callback(Output("loading-output-battery", "children"), Input("export-battery-table", "n_clicks"))
def export_batt_loading_animation(n_clicks): # pylint: disable=unused-argument
time.sleep(3)
# Emulate click on original Export datatables button, since original button is hard to modify
dash_app.clientside_callback(
"""
function(n_clicks) {
if (n_clicks > 0)
document.querySelector("#trips-table button.export").click()
return ""
}
""",
Output("trips-table", "data-dummy"),
[Input("export-trips-table", "n_clicks")]
)
dash_app.clientside_callback(
"""
function(n_clicks) {
if (n_clicks > 0)
document.querySelector("#battery-table button.export").click()
return ""
}
""",
Output("battery-table", "data-dummy"),
[Input("export-battery-table", "n_clicks")]
)
figures.CURRENCY = APP.config.General.currency
figures.EXPORT_FORMAT = APP.config.General.export_format
CALLBACK_CREATED = True
@@ -343,7 +376,25 @@ def serve_layout():
dbc.Tabs([
dbc.Tab(label="Summary", tab_id="summary", children=summary_tab),
dbc.Tab(label="Trips", tab_id="trips", id="tab_trips",
children=[html.Div(id="tab_trips_fig", children=figures.table_fig),
children=[dbc.Row(
dbc.Col([
dcc.Loading(
id="loading-div-trips",
children=[html.Div([html.Div(id="loading-output-trips")])],
type="circle",
className="export-load-anim"
),
dbc.Button("Export trips data",
id="export-trips-table",
n_clicks=0,
size="sm",
color="light",
className="m-1 w-200"
)],
className="d-grid gap-2 d-md-flex justify-content-md-end"
)
),
html.Div(id="tab_trips_fig", children=figures.table_fig),
dbc.Modal(
[
dbc.ModalHeader("Altitude"),
@@ -360,7 +411,25 @@ def serve_layout():
)
]),
dbc.Tab(label="Charge", tab_id="charge", id="tab_charge",
children=[figures.battery_table,
children=[dbc.Row(
dbc.Col([
dcc.Loading(
id="loading-div-battery",
children=[html.Div([html.Div(id="loading-output-battery")])],
type="circle",
className="export-load-anim"
),
dbc.Button("Export charging data",
id="export-battery-table",
n_clicks=0,
size="sm",
color="light",
className="m-1 w-200"
)],
className="d-grid gap-2 d-md-flex justify-content-md-end"
)
),
figures.battery_table,
dbc.Modal(
[
dbc.ModalHeader(
@@ -399,6 +468,7 @@ try:
Charging.set_default_price(APP.myp.vehicles_list)
Database.set_db_callback(update_trips)
figures.CURRENCY = APP.config.General.currency
figures.EXPORT_FORMAT = APP.config.General.export_format
update_trips()
except (IndexError, TypeError):
logger.debug("Failed to get trips, there is probably not enough data yet:", exc_info=True)