Thank you for your answer. The global variables actual_btn
and actual_name_button
were defined to apply a condition to the buttons in order to call a different function for each button. Is there a more intelligent way to do that?
Here, Iām including a simplified version of the code with the data for the plot. My objective is to print in the terminal the coordinates of the mouse click on the bar plot. These coordinates are shown when I pass the mouse over any bar. The difficulty I have is that the bar plot is defined when clicking on a specific button. Thank you again for your help in using this incredible tool (Plotly).
import dash
import json
import pyarrow.parquet as pq
from dash import Dash, dcc, html, Input, Output, State, ALL, callback, ctx
import plotly.graph_objs as go
from plotly.subplots import make_subplots
def plot_mapas_indiretos_entrada(data):
fig = make_subplots(rows=2, cols=2, shared_xaxes=False, shared_yaxes=False,
horizontal_spacing=0.05, # Increase space between columns
vertical_spacing=0.3, # Increase space between rows
subplot_titles=('Totais Documentos / MĆŖs',
'Totais Tributos / MĆŖs',
'Totais Entrada / CFOP',
'Totais Entrada / Fornecedor (TOP 10 FORNECEDORES)'
)
)
# Add traces for each subplot
x_values, y_values = list(data['line_total_doc'].keys()), list(data['line_total_doc'].values())
fig.add_trace(go.Scatter(x=x_values, y=y_values, mode='lines+markers',
marker=dict(color='blue', size=6), # Adjust marker size
line=dict(color='blue', width=2), # Adjust line width
name='vlmerc (sum)'), # Change the label of the trace
row=1, col=1)
cores = {'VlPis': 'blue', 'VlCofins': 'green', 'VlIcms': 'orange', 'VlIpi': 'purple'}
for i, col in enumerate(['VlPis', 'VlCofins', 'VlIcms', 'VlIpi'], start=2):
x_values, y_values = list(data['line_tributos'][col].keys()), list(data['line_tributos'][col].values())
fig.add_trace(go.Scatter(x=x_values, y=y_values, mode='lines+markers',
marker=dict(color=cores[col], size=6), # Adjust marker size
line=dict(color=cores[col], width=2), # Adjust line width
name=col), # Change the label of the trace
row=1, col=2)
x_values, y_values = list(data['Bar'].keys()), list(data['Bar'].values())
fig.add_trace(go.Bar(x=x_values, y=y_values, marker_color='blue', name='vlitem (sum)'), row=2, col=2)
fig.update_layout(
font=dict(family="Arial", size=12, color="black"),
plot_bgcolor="lightgrey",
legend=dict(
title="Legend Title",
x=1.03,
y=0.99,
bgcolor="white",
bordercolor="black",
borderwidth=1
)
)
return fig
parquet_file_path = 'Data/EFDICMSIPI-Entrada.parquet'
data = pq.read_table(parquet_file_path).to_pandas()
json_mapas_indiretos_entrada = {
"Bar": {
"46242558000184": 114834911.26,
"04626152000155": 75191209.77,
"04626152000589": 57807574.57,
"04626152000236": 14394927.23,
"13480185000120": 9273451.45,
"04626152000740": 6972599.2,
"04626152000660": 6211330.86,
"76104397000123": 1432445.4,
"04626152000821": 1135383.55
},
"line_total_doc": {
"2018-08-01T00:00:00": 25091993.65,
"2018-09-01T00:00:00": 24824468.95,
"2018-10-01T00:00:00": 30867122.27,
"2018-11-01T00:00:00": 18662724.79,
"2018-12-01T00:00:00": 25790976.32,
"2019-01-01T00:00:00": 45915510.78,
"2019-02-01T00:00:00": 219332207.14,
"2019-03-01T00:00:00": 521535869.79,
"2019-04-01T00:00:00": 298304478.08,
"2019-05-01T00:00:00": 286302709.15
},
"line_tributos": {
"VlPis": {
"2018-08-01": 66825.34,
"2018-09-01": 61348.68,
"2018-10-01": 79969.39,
"2018-11-01": 76221.52,
"2018-12-01": 27777.04,
"2019-01-01": 64381.92,
"2019-02-01": 101723.6,
"2019-03-01": 130789.09,
"2019-04-01": 132020.68,
"2019-05-01": 151876.72
},
"VlCofins": {
"2018-08-01": 307801.79,
"2018-09-01": 282575.81,
"2018-10-01": 368343.83,
"2018-11-01": 351079.99,
"2018-12-01": 127942.21,
"2019-01-01": 296547.08,
"2019-02-01": 468331.07,
"2019-03-01": 602052.05,
"2019-04-01": 607417.3,
"2019-05-01": 698913.18
},
"VlIcms": {
"2018-08-01": 579616.07,
"2018-09-01": 603905.48,
"2018-10-01": 658627.97,
"2018-11-01": 675782.1,
"2018-12-01": 187434.27,
"2019-01-01": 587657.91,
"2019-02-01": 1010860.64,
"2019-03-01": 1216810.4,
"2019-04-01": 1068793.41,
"2019-05-01": 1205247.28
},
"VlIpi": {
"2018-08-01": 50606.06,
"2018-09-01": 62963.93,
"2018-10-01": 74667.45,
"2018-11-01": 68879.68,
"2018-12-01": 16503.87,
"2019-01-01": 80179.81,
"2019-02-01": 779303.66,
"2019-03-01": 958982.24,
"2019-04-01": 971285.35,
"2019-05-01": 1289644.83
}
}
}
file_path = 'dashboard_input.json'
with open(file_path, "r") as json_file:
dashboard = json.load(json_file)
app = Dash(__name__)
server = app.server
actual_btn = 0
actual_name_button = ''
actual_name_options = []
buttons = [html.Button('btn1', id={"type": 'btn_plot', "index": 1}),
html.Button('Mapas Indiretos', id={"type": 'btn_plot', "index": 2})]
app.layout = html.Div([
html.Div([
html.Center([
*buttons,
html.Div(id='additional_btn_container'),
html.Div(id='plot_output')
]),
])
])
# Callback to change button colors when clicked
@app.callback(
Output({'type': 'btn_plot', 'index': ALL}, 'style'),
[Input({'type': 'btn_plot', 'index': ALL}, 'n_clicks')],
prevent_initial_call=True
)
def change_button_color(n_clicks_list):
styles = []
for i, _ in enumerate(n_clicks_list):
if i+1 == ctx.triggered_id.index:
styles.append({'background-color': '#00FF00'}) # Change color of clicked button
else:
styles.append({'background-color': '#CCCCCC'}) # Reset color of other buttons
return styles
# ================================
@callback(
Output("additional_btn_container", "children"),
Input({"type": "btn_plot", "index": ALL}, "n_clicks")
)
def add_buttons(_):
print(ctx.triggered_id)
if ctx.triggered_id:
global actual_btn, actual_name_button, actual_name_options
actual_btn = ctx.triggered_id.index
btn_index = ctx.triggered_id.index * 10
if ctx.triggered_id.index == 2:
actual_name_button = 'Mapas Indiretos'
actual_name_options = ['Option 1', 'Entradas - EFD ICMS IPI']
additional_btns = [
html.Button(f'Option {btn_index}', id={"type": 'btn_option', "index": btn_index}),
html.Button(f'Entradas - EFD ICMS IPI', id={"type": 'btn_option', "index": btn_index + 1}),
]
else:
additional_btns = [
html.Button(f'Option {btn_index}', id={"type": 'btn_option', "index": btn_index}),
html.Button(f'Option {btn_index + 1}', id={"type": 'btn_option', "index": btn_index + 1}),
html.Button(f'Option {btn_index + 2}', id={"type": 'btn_option', "index": btn_index + 2}),
]
return html.Center(additional_btns)
return dash.no_update
# Callback to change button colors when clicked
@app.callback(
Output({'type': 'btn_option', 'index': ALL}, 'style'),
[Input({'type': 'btn_option', 'index': ALL}, 'n_clicks')],
prevent_initial_call=True
)
def change_button_color(n_clicks_list):
styles = []
for i, _ in enumerate(n_clicks_list):
index_btn = actual_btn * 10 + i
if index_btn == ctx.triggered_id.index:
styles.append({'background-color': '#00FF00'}) # Change color of clicked button
else:
styles.append({'background-color': '#CCCCCC'}) # Reset color of other buttons
return styles
# ================================
# ================================
# plot the dashboard
@callback(
Output("plot_output", "children"),
Input({"type": "btn_option", "index": ALL}, "n_clicks")
)
def display_plots(_):
if ctx.triggered_id:
# ====== Mapas Indiretos - Entradas - EFD ICMS IPI ======
if actual_name_button == 'Mapas Indiretos':
index_option = ctx.triggered_id.index - actual_btn * 10
if actual_name_options[index_option] == 'Entradas - EFD ICMS IPI':
initial_figure = plot_mapas_indiretos_entrada(json_mapas_indiretos_entrada)
return [
dcc.Graph(id='bar-plot', figure=initial_figure,
style={'width': '90%', 'height': '80vh', 'position': 'absolute', 'top': '170px',
'left': '50px', 'z-index': '1'}
),
]
return f"Button Option: {ctx.triggered_id.index}"
return
if __name__ == "__main__":
app.run_server(debug=True, port=5010)