demo-kpi / utils /_charts.py
li-nguyen's picture
Add last changes
cd1f702
raw
history blame
6.55 kB
"""Contains custom components and charts used inside the dashboard."""
from typing import List, Literal, Optional
import pandas as pd
import plotly.graph_objects as go
import vizro.models as vm
import vizro.plotly.express as px
from dash import html
from vizro.models.types import capture
# CUSTOM COMPONENTS -------------------------------------------------------------
class FlexContainer(vm.Container):
"""Custom flex `Container`."""
type: Literal["flex_container"] = "flex_container"
title: str = None # Title exists in vm.Container but we don't want to use it here.
classname: str = "d-flex"
def build(self):
"""Returns a flex container."""
return html.Div(
id=self.id, children=[component.build() for component in self.components], className=self.classname
)
# CUSTOM CHARTS ----------------------------------------------------------------
@capture("graph")
def bar(
x: str,
y: str,
data_frame: pd.DataFrame,
top_n: int = 15,
custom_data: Optional[List[str]] = None,
):
"""Custom bar chart implementation.
Based on [px.bar](https://plotly.com/python-api-reference/generated/plotly.express.bar).
"""
df_agg = data_frame.groupby(y).agg({x: "count"}).sort_values(by=x, ascending=False).reset_index()
fig = px.bar(
data_frame=df_agg.head(top_n),
x=x,
y=y,
orientation="h",
text=x,
color_discrete_sequence=["#1A85FF"],
custom_data=custom_data,
)
fig.update_layout(xaxis_title="# of Complaints", yaxis={"title": "", "autorange": "reversed"})
return fig
@capture("graph")
def area(x: str, y: str, data_frame: pd.DataFrame):
"""Custom chart to create unstacked area chart.
Based on [go.Scatter](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Scatter.html).
"""
df_agg = data_frame.groupby(["Year", "Month"]).agg({y: "count"}).reset_index()
df_agg_2019 = df_agg[df_agg["Year"] == "2018"]
df_agg_2020 = df_agg[df_agg["Year"] == "2019"]
fig = go.Figure()
fig.add_trace(
go.Scatter(x=df_agg_2020[x], y=df_agg_2020[y], fill="tozeroy", name="2019", marker={"color": "#1a85ff"})
)
fig.add_trace(go.Scatter(x=df_agg_2019[x], y=df_agg_2019[y], fill="tonexty", name="2018", marker={"color": "grey"}))
fig.update_layout(
title="Complaints over time",
xaxis_title="Date Received",
yaxis_title="# of Complaints",
title_pad_t=4,
xaxis={
"showgrid": False,
"tickmode": "array",
"tickvals": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"ticktext": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
},
)
return fig
@capture("graph")
def pie(
names: str,
values: str,
data_frame: pd.DataFrame = None,
title: Optional[str] = None,
):
"""Custom pie chart implementation.
Based on [px.pie](https://plotly.com/python-api-reference/generated/plotly.express.pie).
"""
df_agg = data_frame.groupby(names).agg({values: "count"}).reset_index()
fig = px.pie(
data_frame=df_agg,
names=names,
values=values,
color=names,
color_discrete_map={
"Closed with explanation": "#1a85ff",
"Closed with monetary relief": "#d41159",
"Closed with non-monetary relief": "#adbedc",
"Closed without relief": "#7ea1ee",
"Closed with relief": "#df658c",
"Closed": "#1a85ff",
},
title=title,
hole=0.4,
)
fig.update_layout(legend_x=1, legend_y=1, title_pad_t=2, margin={"l": 0, "r": 0, "t": 60, "b": 0})
return fig
@capture("graph")
def choropleth(
locations: str,
color: str,
data_frame: pd.DataFrame = None,
title: Optional[str] = None,
custom_data: Optional[List[str]] = None,
):
"""Custom choropleth implementation.
Based on [px.choropleth](https://plotly.com/python-api-reference/generated/plotly.express.choropleth).
"""
df_agg = data_frame.groupby(locations).agg({color: "count"}).reset_index()
fig = px.choropleth(
data_frame=df_agg,
locations=locations,
color=color,
color_continuous_scale=[
"#ded6d8",
"#f3bdcb",
"#f7a9be",
"#f894b1",
"#f780a3",
"#f46b94",
"#ee517f",
"#e94777",
"#e43d70",
"#df3168",
"#d92460",
"#d41159",
],
scope="usa",
locationmode="USA-states",
title=title,
custom_data=custom_data,
)
fig.update_coloraxes(colorbar={"thickness": 10, "title": {"side": "bottom"}, "orientation": "h", "x": 0.5, "y": 0})
return fig
# TABLE CONFIGURATIONS ---------------------------------------------------------
CELL_STYLE = {
"styleConditions": [
{
"condition": "params.value == 'Closed with explanation'",
"style": {"backgroundColor": "#1a85ff"},
},
{
"condition": "params.value == 'Closed with monetary relief'",
"style": {"backgroundColor": "#d41159"},
},
{
"condition": "params.value == 'Closed with non-monetary relief'",
"style": {"backgroundColor": "#adbedc"},
},
{
"condition": "params.value == 'Closed without relief'",
"style": {"backgroundColor": "#7ea1ee"},
},
{
"condition": "params.value == 'Closed with relief'",
"style": {"backgroundColor": "#df658c"},
},
{
"condition": "params.value == 'Closed'",
"style": {"backgroundColor": "#1a85ff"},
},
]
}
COLUMN_DEFS = [
{"field": "Complaint ID", "cellDataType": "text", "headerName": "ID", "flex": 3},
{"field": "Date Received", "cellDataType": "text", "headerName": "Date", "flex": 3},
{"field": "Channel", "cellDataType": "text", "flex": 3},
{"field": "State", "cellDataType": "text", "flex": 2},
{"field": "Product", "cellDataType": "text", "flex": 5},
{"field": "Issue", "cellDataType": "text", "flex": 5},
{
"field": "Company response - detailed",
"cellDataType": "text",
"cellStyle": CELL_STYLE,
"headerName": "Company response",
"flex": 6,
},
{"field": "Timely response?", "cellRenderer": "markdown", "headerName": "On time?", "flex": 3},
]