# -*- coding: utf-8 -*-
"""
Created on Thu Feb 20 15:00:14 2025
@author: win11
"""
import dash as dash
from dash import dcc, html, Input, Output, callback
#import plotly.express as px
import plotly.graph_objects as go
#from data.dataprep import data_prep,create_ym_revenue,data_prep_ai_data
import pandas as pd
import numpy as np
import dash_bootstrap_components as dbc
#import plotly.io as pio
dbc_css = "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates/dbc.min.css"
#df_money_order, df_money_orderdetail = data_prep()
#df_revenue_mom = pd.read_csv('orderdetails_money.csv')
#df_revenue_mom = data_prep_ai_data().reset_index()
df_revenue_mom = pd.read_csv('ym_revenue_ai.csv', index_col=False)
df_revenue_mom['Last_dayofmonth_Date'] = df_revenue_mom['Last_dayofmonth_Date'].apply(pd.to_datetime, format='%Y-%m-%d')
def create_bar_ac_py(df_revenue_mom):
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
offset = 0.1
colors = {'AC': 'rgba(64,64,64,1)','PY':'rgba(166,166,166,1)' }
fig = go.Figure()
fig.add_trace(go.Bar(
x=[x for x in range(0,12,1)],
y=df_revenue_mom['revenue_py'],
width=0.8,
marker=dict(color=colors.get('PY')),
name='PY'
))
fig.add_trace(go.Bar(
x=[x+offset for x in range(0,12,1)],
y=df_revenue_mom['revenue'],
width=0.8,
text=df_revenue_mom['revenue'],
texttemplate='%{y:,.3s}',
textposition='outside',
marker=dict(color=colors.get('AC')),
name='AC'
))
fig.update_xaxes(tickmode='array', tickvals=[x+offset for x in range(0,12,1)], ticktext=months)
fig.update_xaxes(showgrid=False, zeroline=False)
fig.update_yaxes(showgrid=False, zeroline=False)
fig.update_layout(yaxis_title=None)
fig.update_yaxes(showticklabels=False)
fig.update_layout(
margin=dict(l=0, r=0, t=0, b=0),
autosize=False,
width=800,
height=300,
hovermode=False,
showlegend=False
)
#background needs to be transparent
fig.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
'paper_bgcolor': 'rgba(0, 0, 0, 0)',
})
return dcc.Graph(figure = fig)
def create_delta_py(df_revenue_mom):
colors = {'AC': 'rgba(64,64,64,1)','PY':'rgba(166,166,166,1)', 'red': 'rgba(255,0,0,1)', 'green':'rgba(0,142,150,1)' }
figPY = go.Figure()
# First bar trace (shift left)
figPY.add_trace(go.Bar(
x=df_revenue_mom['Last_dayofmonth_Date'],
y=df_revenue_mom['delta_py'],
#width=0.5,
#marker_color=colors.get('PY'),
marker_color = df_revenue_mom['delta_py'].apply(lambda x: colors.get('red') if x < 0 else colors.get('green')) ,
name='PY',
text=df_revenue_mom['delta_py'],
texttemplate = df_revenue_mom['delta_py'].apply(lambda x: "%{y:,.3s}" if x < 0 else "+%{y:,.3s}")
))
#background needs to be transparent
figPY.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
'paper_bgcolor': 'rgba(0, 0, 0, 0)',
})
# Change the bar mode
figPY.update_layout(bargap=0.2)
#figPY.update_layout(yaxis_title="<span style='rotate: 90deg;'>ΔPY</span>")
figPY.update_layout(yaxis_title=None)
figPY.update_yaxes(showticklabels=False)
figPY.update_layout(xaxis_title=None)
figPY.update_xaxes(showticklabels=False)
figPY.update_layout(
margin=dict(l=0, r=0, t=0, b=0),
autosize=False,
width=800,
height=350,
hovermode=False
)
figPY.update_traces(textfont_size=12, textangle=0, textposition="outside", cliponaxis=False)
return dcc.Graph(figure = figPY)
def create_delta_py_perc(df_revenue_mom):
colors = {'AC': 'rgba(64,64,64,1)','PY':'rgba(166,166,166,1)', 'red': 'rgba(255,0,0,1)', 'green':'rgba(0,142,150,1)' }
figPY = go.Figure()
#adding y=0
#opacity + line_color make the lines appear nice on the white template as they are meant to be
figPY.add_hline(y=0, line_dash="solid", line_width=2, opacity=1, line_color="Black")
for x_val, y_val in zip(df_revenue_mom['Last_dayofmonth_Date'], df_revenue_mom['delta_perc_py']):
figPY.add_shape(
type="line",
x0=x_val, x1=x_val,
y0=0, y1=y_val, # From y=0 to marker y-value
line=dict(color=colors["red"] if y_val < 0 else colors["green"], # Red for negative, green for positive
width=2) # Adjust color and width as needed
)
figPY.add_trace(go.Scatter(
x=df_revenue_mom['Last_dayofmonth_Date'],
y=df_revenue_mom['delta_perc_py'],
marker = dict(color=colors['AC'],size=12),
mode="markers + text",
name="Percentage change with same month last year",
text=df_revenue_mom['delta_py'],
texttemplate = df_revenue_mom['delta_perc_py'].apply(lambda x: "%{y:.1%}" if x < 0 else "+%{y:.1%}") ,
textposition= df_revenue_mom['delta_perc_py'].apply(lambda x: "bottom center" if x < 0 else "top center")
))
#background needs to be transparent
figPY.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
'paper_bgcolor': 'rgba(0, 0, 0, 0)',
})
# Change the bar mode
figPY.update_layout(bargap=0.2)
#figPY.update_layout(yaxis_title="<span style='rotate: 90deg;'>ΔPY%</span>" )
figPY.update_layout(yaxis_title=None )
figPY.update_yaxes(showticklabels=False)
figPY.update_layout(xaxis_title=None)
figPY.update_xaxes(showticklabels=False)
figPY.update_layout(
margin=dict(l=0, r=0, t=0, b=0),
autosize=False,
width=800,
height=300,
hovermode=False
)
figPY.update_traces(textfont_size=12, textfont_style='italic')
return dcc.Graph(figure = figPY)
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.SANDSTONE,dbc_css])
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
html.P('Imaginary Traders'),
html.P('Revenue by year in K$'),
html.P( id='title'),
], className='header col-md-4'),
dbc.Col([
dbc.Select(
id="select_year",
options=[
{"label": "2024", "value": 2024},
{"label": "2023", "value": 2023}
], value = 2024
)
], className='col-md-2'),
dbc.Col([ html.H2('IBCS Experiment no.2', style={'textAlign':'right'})])
], className='col-md-12'),
dbc.Row([
dbc.Col([
html.Div([
html.Div("ΔPY%", className='title-border'),
html.Div(id='revenue_percentage')
], className='minigrid'),
html.Div([
html.Div("ΔPY ", className='title-border'),
html.Div(id='revenue_money')
], className='minigrid'),
html.Div([
html.Div([html.P('AC ', style={'fontWeight':'bold'}),
html.P('PY ')], className='title-border'),
html.Div(id='total_revenue')
], className='minigrid'),
]),
]),
dbc.Row([
dbc.Col(html.P('dash(2.18.2), dash-bootstrap-components(1.7.1), dash-bootstrap-templates 2.1.0', style={'fontSize':'9px','marginTop':'2rem'})
),
]),
],style={'marginTop': '3rem', 'marginBottom': '2rem'}, fluid=False)
@app.callback( Output('revenue_percentage', 'children'),
Output('revenue_money', 'children'),
Output('total_revenue', 'children'),
Output('title', 'children'),
Input(component_id='select_year', component_property='value')
)
def update_all(value):
#the incoming dataframe has all total, delta pm and delta pm% for each month,
#filter it on the selected value (=year-month), drop=True to remove the extra
#created useless index column
if not value:
data = df_revenue_mom[df_revenue_mom['Last_dayofmonth_Date'].dt.year == 2024]
else:
data = df_revenue_mom[df_revenue_mom['Last_dayofmonth_Date'].dt.year == int(value)]
title = f"{value}, AC and PY by month"
#update all visuals with the updated data
return create_delta_py_perc(data),\
create_delta_py(data),\
create_bar_ac_py(data),\
title
app.run(debug=True)