Related
For my dash app, in order to update some graphs dynamically, I have to use a function that I named update_graphs inside a for loop. Some of the graphs contain several traces while some others only have one. The update_graphs function is called inside a callback and returns a dict and an int to update the extendData property of the graph object. However, since I am using a return statement inside a for loop, I only get the first trace.
I am not familiar with the generators and the yield keyword, maybe this is an option. But I haven't been able to make it work.
I have also tried to store the results of the update_graphs inside a list but it is not working.
Any help is appreciated!
Here is the code for the app:
import dash
from dash.dependencies import Output, Input, State, MATCH, ALL
from dash import dcc, html, ctx
import plotly
import plotly.express as px
import random
import plotly.graph_objs as go
import pandas as pd
# Initializing the data with the correct format
init_store = {}
n=3
init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int'), 'c':pd.Series(dtype='int'), 'd':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store['0'] = init_df
for i in range(n):
init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store[f'{i+1}'] = init_df
# Function to update the dataframes with the new observations
def get_data(json_data):
df = pd.read_json(json_data)
compteur = df['a'][len(df['a'])-1]
if len(df.columns) > 2:
new_row = {'a':compteur + 1, 'b':random.randint(13,26), 'c':random.randint(13,26), 'd':random.randint(13,26)}
else:
new_row = {'a':compteur + 1, 'b':random.randint(13,26)}
df = df.shift(periods=-1)
df.iloc[len(df)-1] = new_row
return(df.to_json())
# Function to update the graphs based on the dataframes
def update_graphs(json_data, column, index=0):
df = pd.read_json(json_data)
nb_obs = df.shape[0]
x_new = df['a'][len(df)-1]
y_new = df[column][nb_obs-1]
return dict(x=[[x_new]], y=[[y_new]]), index
colors = px.colors.qualitative.G10
def generate_graph_containers(index, json_data):
dataframe = pd.read_json(json_data)
X = dataframe['a']
Y = dataframe.loc[:, dataframe.columns != 'a']
graph_id = {'type': 'graph-', 'index': index}
return(
html.Div(
html.Div(
dcc.Graph(
id=graph_id,
style={"height": "8rem"},
config={
"staticPlot": False,
"editable": False,
"displayModeBar": False,
},
figure=go.Figure(
{
"data": [
{
"x": list(X),
"y": list(Y[Y.columns[i]]),
"mode": "lines",
"name": Y.columns[i],
"line": {"color": colors[i+2]},
}
for i in range(len(Y.columns))
],
"layout": {
"uirevision": True,
"margin": dict(l=0, r=0, t=4, b=4, pad=0),
"xaxis": dict(
showline=False,
showgrid=False,
zeroline=False,
showticklabels=False,
),
"yaxis": dict(
showline=False,
showgrid=False,
zeroline=False,
showticklabels=False,
),
"paper_bgcolor": "rgba(0,0,0,0)",
"plot_bgcolor": "rgba(0,0,0,0)",
}
}
)
)
)
)
)
app = dash.Dash(__name__)
store = [dcc.Store(id={'type':'store-', 'index':i}, data=init_store[str(i)].to_json()) for i in range(n)]
def make_layout():
return(
html.Div(
[
html.Div(
store
),
dcc.Interval(
id = 'interval',
interval = 1000,
n_intervals = 0
),
html.Div(
[
generate_graph_containers(str(i), store[i].data) for i in range(n)
]
)
]
)
)
app.layout = make_layout
#app.callback(
Output(component_id={'type':'store-', 'index':MATCH}, component_property='data'),
[
Input('interval', 'n_intervals'),
State(component_id={'type':'store-', 'index':MATCH}, component_property='data')
]
)
def update_data(time, data):
return(get_data(data))
#app.callback(
Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
)
def update_graphs_callback(data):
triggered_id = ctx.triggered_id
print(triggered_id['index'])
columns = ['b', 'c', 'd']
if triggered_id['index'] == 0:
for i in range(len(columns)):
return(update_graphs(data, columns[i], i))
else:
return(update_graphs(data, 'b'))
if __name__ == '__main__':
app.run_server(debug=True)
I figured it out. The trick is in the format expected to update the extendData property of a figure. When trying to update several traces, the format should be a dictionary with a key for the x values and one for the y values. The values associated should be an array for each key, containing an array per trace. Don't forget to add the trace indices after the dictionary. So for example, in the case of 3 distinct traces, the function should return something like:
dict(x=[[x_0], [x_1], [x_2]], y=[[y_0], [y_1], [y_2]]), [0, 1, 2]
Therefore the update_graphs function should be:
def update_graphs(json_data):
df = pd.read_json(json_data)
nb_obs = df.shape[0]
x_new = []
y_new = []
trace_index = []
for i in range(len(df.columns)-1):
x_new.append([df['a'][len(df)-1]])
y_new.append([df[df.columns[i+1]][nb_obs-1]])
trace_index.append(i)
return(dict(x=x_new, y=y_new), trace_index)
And the callback to update the graphs should be changed to:
#app.callback(
Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
)
def update_graphs_callback(data):
return(update_graphs(data))
I am working on a selection menu where the user can select the number of experiments they want to compare/see. Depending on this number I would like to adapt the number of columns that appear, being one for each experiment. In the image below an example of the menu with one experiment can be seen. However, I would like these dropdowns to duplicate if the user selects two experiments having them in side-to-side columns.
Here is an example of one column and one experiment:
The code I have so far is the following:
# Load Data
df = px.data.tips()
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
# Build App
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
# first row - selecting the number of experiments
html.Div([
html.I("Select the number of experiments you want to compare (min - 2 and max - 10):"),
html.Br(),
# input box for the number of experiments
dcc.Input(id="num_exp" , type='number', min = 2, max = 10, placeholder="No of experiments"),
html.Div(id="output")
], style = {'width': '100%'}
),
# second row - where the experiments are organized in columns
html.Div([
html.Label([
html.I("X axis "),
dcc.Dropdown(
id = 'dd_axis',
clearable = False,
placeholder = 'Select property x-axis',
options=[
{'label': i, 'value': i}
for i in properties
],
style={
'width': '100%'
})
]),
html.Label([
html.I("Y Axis "),
dcc.Dropdown(
id = 'dd_yaxis',
clearable = False,
placeholder = 'Select property y-axis',
options=[ ],
disabled = False)
])
], style = {'display': 'inline-block', 'vertical-align': 'top', 'margin-left': '3vw', 'margin-top': '3vw', 'width': '50%'})
])
#app.callback(
Output("output", "children"),
# number of experiments input
Input("num_exp", "value"),
)
def update_output(test_type):
in_testtype = test_type
return u'{} experiments'.format(test_type)
def cb_render(*vals):
return " | ".join((str(val) for val in vals if val))
Can you help me adding more dropdown menus to the side and dividing the second row in columns based in the user selection?
Thank you!
You can do this by using dbc.Col and dbc.Row.
In your layout, have a Div and within it an empty dbc.Row that will be used to populate its children attribute with columns.
Then, in the callback that is triggered by the input box value, have a loop that returns the number of columns you want, with the relevant code for the dbc.Col and what you'd like to display in it.
Here's a worked-up example of your original code:
import dash
from dash import dcc, html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
properties = ["a", "b", "c"]
app.layout = html.Div([
# first row - selecting the number of experiments
html.Div([
html.I(
"Select the number of experiments you want to compare (min - 2 and max - 10):"),
html.Br(),
# input box for the number of experiments
dcc.Input(id="num_exp", value=2, type='number', min=2,
max=10, placeholder="No of experiments"),
html.Div([
dbc.Row([], id="output")
])
], style={'width': '100%'}
),
])
#app.callback(
Output("output", "children"),
# number of experiments input
Input("num_exp", "value"),
)
def update_output(test_type):
columns_list = []
letters = "xyzabcdefg"
for i in range(test_type):
columns_list.append(
dbc.Col([
html.Label([
html.I(f"{letters[i].upper()} axis "),
dcc.Dropdown(
id=f'{letters[i]}_axis',
clearable=False,
placeholder=f'Select property {letters[i]}-axis',
options=[
{'label': i, 'value': i}
for i in properties
],
style={
'width': '100%'
})
])
])
)
return columns_list
if __name__ == "__main__":
app.run_server(debug=True)
I have a sidebar and a date-picker in my dashboard built with Dash. However, I am unable to load the graph correctly based on the date range selected. The data source can be found in the link below, however, I changed the column "Year" values to dates in this format "YYYY-MM-DD".
Data Source
Help is much appreciated.
Output errors:
FileNotFoundError: [Errno 2] No such file or directory: 'iranian_students.csv'
ID not found in layout
Attempting to connect a callback Input item to component:
"date-range"
but no components with that id exist in the layout.
If you are assigning callbacks to components that are
generated by other callbacks (and therefore not in the
initial layout), you can suppress this exception by setting
`suppress_callback_exceptions=True`.
This ID was used in the callback(s) for Output(s):
students.figure
students.figure
ID not found in layout
Attempting to connect a callback Output item to component:
"students"
but no components with that id exist in the layout.
If you are assigning callbacks to components that are
generated by other callbacks (and therefore not in the
initial layout), you can suppress this exception by setting
`suppress_callback_exceptions=True`.
This ID was used in the callback(s) for Output(s):
students.figure
My code:
# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from flask import Flask
import pandas as pd
from pandas import DataFrame
from pandas import json_normalize
import pymongo
from pymongo import MongoClient
import plotly.graph_objs as go
import plotly.offline as pyo
import plotly.express as px
import numpy as np
import pytz, time
from datetime import datetime, tzinfo, timezone, timedelta, date
import dash_bootstrap_components as dbc
import random
from sqlalchemy import create_engine
from plotly.subplots import make_subplots
# %%
# constants
df = pd.read_csv('Bootstrap\Side-Bar\iranian_students.csv')
localTimezone = pytz.timezone('Africa/Cairo')
datetimeNow = datetime.now(localTimezone)
# %%
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.FLATLY],
meta_tags=[{'name': 'viewport',
'content': 'width=device-width, initial-scale=1.0'}]
)
# %%
def serve_layoutOnReload():
# styling the sidebar
SIDEBAR_STYLE = {
"position": "fixed",
"top": 0,
"left": 0,
"bottom": 0,
"width": "16rem",
"padding": "2rem 1rem",
"background-color": "#f8f9fa",
}
# padding for the page content
CONTENT_STYLE = {
"margin-left": "18rem",
"margin-right": "2rem",
"padding": "2rem 1rem",
}
sidebar = html.Div(
[
html.H2("Sidebar", className="display-4"),
html.Hr(),
html.P(
"Number of students per education level", className="lead"
),
dbc.Nav(
[
dbc.NavLink("Home", href="/", active="exact"),
dbc.NavLink("Page 1", href="/page-1", active="exact"),
dbc.NavLink("Page 2", href="/page-2", active="exact"),
],
vertical=True,
pills=True,
),
],
style=SIDEBAR_STYLE,
)
content = html.Div(id="page-content", children=[], style=CONTENT_STYLE)
web_layout = html.Div([
dcc.Location(id="url"),
sidebar,
content
])
return web_layout
app.layout = serve_layoutOnReload
# app.layout = html.Div([
# dcc.Location(id="url"),
# sidebar,
# content
# ])
# %%
#app.callback(
Output("page-content", "children"),
[Input("url", "pathname")]
)
def render_page_content(pathname):
if pathname == "/":
return [
html.H1('Kindergarten',
style={'textAlign':'center'}),
dbc.Container([
dbc.Row([
dbc.Col([
html.P("Date picker:", className='text-right font-weight-bold mb-4'),
],xs=12, sm=12, md=12, lg=5, xl=5),
dbc.Col([
dcc.DatePickerRange(id='date-range',
min_date_allowed=date(2020, 6, 1),
max_date_allowed=datetimeNow.date(),
start_date=datetimeNow.date() - timedelta(days=7),
end_date=datetimeNow.date(), ),
],xs=12, sm=12, md=12, lg=5, xl=5),], no_gutters=True, justify='center'),
dbc.Row(
dbc.Col(html.H2(" ", className='text-center text-primary mb-4'), width=12)
),
dbc.Row([
dbc.Col([
dcc.Graph(id="students", figure={}),
], xs=12, sm=12, md=12, lg=5, xl=5),], justify='center')
], fluid=True)
]
elif pathname == "/page-1":
return [
html.H1('Grad School',
style={'textAlign':'center'}),
dcc.Graph(id='bargraph',
figure=px.bar(df, barmode='group', x='Date',
y=['Girls Grade School', 'Boys Grade School']))
]
elif pathname == "/page-2":
return [
html.H1('High School',
style={'textAlign':'center'}),
dcc.Graph(id='bargraph',
figure=px.bar(df, barmode='group', x='Date',
y=['Girls High School', 'Boys High School']))
]
# If the user tries to reach a different page, return a 404 message
return dbc.Jumbotron(
[
html.H1("404: Not found", className="text-danger"),
html.Hr(),
html.P(f"The pathname {pathname} was not recognised..."),
]
)
# %%
#app.callback([Output("students", "figure")],
[Input("date-range", "start_date"),
Input("date-range", "end_date")])
def update_charts(start_date, end_date):
# read data upon refresh browser
df = pd.read_csv('iranian_students.csv')
# masks
mask1 = (
(df.Date >= pd.to_datetime(start_date))
& (df.Date <= pd.to_datetime(end_date))
)# daily sgym signups
# filtered dataframes
filtered_data1 = df.loc[mask1, :].reset_index(drop=True)
# plots
# daily sgym signups
trace = []
trace.append(go.Bar(
x = filtered_data1['Date'],
y = filtered_data1['Girls Kindergarten'],
name = 'Count of students'
))
# add moving average
filtered_data1['Moving Avg'] = filtered_data1['Girls Kindergarten'].rolling(window=7, min_periods=1).mean()
trace.append(go.Scatter(x=filtered_data1['Date'], y=filtered_data1['Moving Avg'], name = 'Rolling Mean=7'))
students_fig = {'data': trace,
'layout': go.Layout(
{"title": {"text": "Student Count\n"
'('+str(start_date)+' to '+str(end_date)+')',
"x": 0.05, "xanchor": "left"},
"xaxis": {"fixedrange": False, 'title':'Date',
'tickmode':'linear', 'automargin':True},
"yaxis": {"fixedrange": False, 'title':'Count of Signups'},
'xaxis_tickformat':'%d %b',
'title_font_size': 14,
'hovermode':'closest',
'legend_title_text':'Gym',
'hovermode':'closest',
},) }
return students_fig
# %%
if __name__=='__main__':
app.run_server(debug=True, port=3000)
The first error is telling you exactly where the problems start. The problem is in the file path that you define when updating the graph.
instead of this:
def update_charts(start_date, end_date):
# read data upon refresh browser
df = pd.read_csv('iranian_students.csv')
You need to do this:
def update_charts(start_date, end_date):
# read data upon refresh browser
df = pd.read_csv('Bootstrap\Side-Bar\iranian_students.csv')
the second problem is that you
call function serve_layoutOnReload without the brackets?
app.layout = serve_layoutOnReload
instead of
app.layout = serve_layoutOnReload()
The third problem is in how you define your layout. See this discussion for reference.This discussion from January is using the same code/database that you have and they are facing the same issues.
I would try defining the layout directly like this:
app.layout = html.Div([])
I just started to use Plotly and Dash. I try to connect my interactive graph with calendar (DatePickerRange). Both off them display correctly, but not together. My figure doesn’t see the start and end dates.
My variable date is “session_date”. I don’t know how to use the start and end variable with session_date. The range from session_date.
I have started to put start_date and end_date to call-back, byt that didn't display correctly.
Could someone help me?
With regards
Dorota
# -----------------------------------
# Connect to database OR data source here
# -----------------------------------
...
# -----------------------------------
# Retrieve data from database
# -----------------------------------
curs = db.cursor()
testy = """SELECT o.ticker, o.issuer, o.session_date, o.open, o.close, o.min
FROM olhc AS o;"""
curs.execute(testy)
data = []
for x in curs:
data.append(x)
df = pd.DataFrame(data, columns=['ticker', 'issuer', 'session_date', 'open', 'close', 'min'])
# convert the 'Session_date' column to datetime format
df['session_date']= pd.to_datetime(df['session_date'])
# -----------------------------------
# Initialize the app
# -----------------------------------
# This application is using a custom
# CSS stylesheet to modify the default
# styles of the elements.
# -----------------------------------
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
colors = dict(background='#3333',
text='#21617A',
font='#21617A')
# -----------------------------------
# Define app layout
# -----------------------------------
app.layout = html.Div(children=[
html.H1(children='Close & Open prices for company',
style={'textAlign': 'center', 'color': colors['text']}
),
html.Div(children=[
html.Div(style={
'textAlign': 'center', 'color': colors['font']
},
children='''Financial Dashboard for FellowshipPL
'''),
dcc.DatePickerRange(
id='my-date-picker-range',
calendar_orientation='horizontal',
day_size=30,
first_day_of_week=1, # 0 Sunday
clearable=False,
with_portal=False, # True on the page
min_date_allowed=date(2010, 1, 1),
max_date_allowed=date(2021, 12, 31),
initial_visible_month=date(2020, 1, 1),
start_date=date(2020, 1, 1),
end_date=date(2021, 12, 31),
display_format='MMM Do, YYYY', # lots possibilities
updatemode='singledate'
),
html.Div(id='output-container-date-picker-range'),
# -----------------------------------
# Define Dropdown
# -----------------------------------
dcc.Dropdown(style={
'textAlign': 'left',
'color': colors['text']
},
id='issuer_selection',
options=[
{'label': i, 'value': i} for i in df.issuer.unique()
], multi=False,
placeholder='Filter by name of company ...'),
html.H3(id='text'),
dcc.Graph(id='indicators')])
])
# -----------------------------------
# Define first callback
# -----------------------------------
#app.callback(
Output('output-container-date-picker-range', 'children'),
[Input('my-date-picker-range', 'start_date'),
Input('my-date-picker-range', 'end_date')])
def update_output(start_date, end_date):
string_prefix = 'You have selected: '
if start_date is not None:
start_date_object = date.fromisoformat(start_date)
start_date_string = start_date_object.strftime('%B %d, %Y')
string_prefix = string_prefix + 'Start Date: ' + start_date_string + ' | '
if end_date is not None:
end_date_object = date.fromisoformat(end_date)
end_date_string = end_date_object.strftime('%B %d, %Y')
string_prefix = string_prefix + 'End Date: ' + end_date_string
if len(string_prefix) == len('You have selected: '):
return 'Select a date to see it displayed here'
else:
return string_prefix
# #app.callback(
# Output('indicators', 'figure'),
# [Input('issuer_selection', 'value'),
# Input('my-date-picker-range', 'start_date'),
# Input('my-date-picker-range', 'end_date')])
#app.callback(
Output('indicators', 'figure'),
[Input('issuer_selection', 'value')])
def retrieve_plots(issuer):
filtered_df = df[df['issuer'] == issuer]
# dff = df.loc[start_date:end_date]
# Creating trace1
trace1 = go.Scatter(x=(filtered_df['session_date']),
y=filtered_df['close'],
mode="markers",
name="Close price",
marker=dict(color='#21617A', size=4),
text=filtered_df['session_date'])
# Creating trace2
trace2 = go.Scatter(x=(filtered_df['session_date']),
y=filtered_df['open'],
mode="markers",
name="Open price",
marker=dict(color='#C22E4C', size=3),
text=filtered_df.session_date)
# Creating trace3
trace3 = go.Scatter(x=(filtered_df['session_date']),
y=filtered_df['min'],
mode="markers",
name="Min price",
marker=dict(color='#7FD13A', size=2),
text=filtered_df.session_date)
data = [trace1, trace2, trace3]
layout = dict(yaxis=dict(title='Prices', ticklen=5, zeroline=False),
xaxis=dict(title='Date', ticklen=5, zeroline=False),
hovermode="x unified",
style={'textAlign': 'center',
'color': colors['text']
},
)
datapoints = {'data': data, 'layout': layout}
return datapoints
# -----------------------------------
# Run the app
# -----------------------------------
if __name__ == '__main__':
app.run_server(debug=True)
Using Python/Plotly, I'm trying to create a figure that has a map and a slider to choose the year. Depeding on the year that is selected in the slider, the map should render different results.
Evertyhing is working fine with exception for one thing - I cannot set the initial load state of the map to be the same as the initial step as defined in
sliders = [dict(active=0, pad={"t": 1}, steps=steps)]
When the first render is done, and the slider has not yet been used, the data displayed seems to be accordingly to the last state of the data_slider list, ie. it shows the last values that were loaded in the list (I'm not totally sure about this conclusion).
Is there a way to set the first data display accordingly to the step that is pre-defined? Or in alternative, a way to force the first load to be something like data_slider[0].
Below is the code I'm using.
import pandas as pd
import os
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go
import numpy as np
import random
ds = 'https://archive.org/download/globalterrorismdb_0718dist/globalterrorismdb_0718dist.csv'
# ds = os.getcwd() + '\globalterrorismdb_0718dist.csv'
fields = ['eventid', 'iyear', 'country', 'country_txt', 'region_txt', 'city', 'latitude', 'longitude', 'nkill']
df = pd.read_csv(ds, encoding='ISO-8859-1', usecols=fields)
df = df.loc[df['iyear'] >= 2000]
df['nkill'].fillna(0, inplace=True)
df = df.groupby(['country_txt', 'iyear'])['nkill'].sum().reset_index()
df = df.loc[df['nkill'] > 0]
data_slider = []
for year in df.iyear.unique():
df_year = df[(df['iyear'] == year)]
data_year = dict(
type='choropleth',
name='',
colorscale='amp',
locations=df_year['country_txt'],
z=df_year['nkill'],
zmax=15000,
zmin=0,
locationmode='country names',
colorbar=dict(
len=0.5,
thickness=10,
title=dict(
text='Number of fatalities',
font=dict(
family='Arial',
size=14,
),
side='right'
),
tickfont=dict(
family='Arial',
size=12),
)
)
data_slider.append(data_year)
steps = []
for i in range(len(data_slider)):
step = dict(
method='restyle',
args=['visible', [False] * len(data_slider)],
label=(format(i + 2000))
)
step['args'][1][i] = True
steps.append(step)
sliders = [dict(active=0, pad={"t": 1}, steps=steps)]
layout = dict(
geo=dict(
scope='world',
showcountries=True,
projection=dict(
type='equirectangular'
),
showland=True,
landcolor='rgb(255, 255, 255)',
showlakes=False,
showrivers=False,
showocean=True,
oceancolor='white',
),
sliders=sliders
)
fig = go.Figure(data=data_slider, layout=layout)
fig.update_layout(
font=dict(family='Arial', size=12),
autosize=False,
width=1250,
height=750,
margin=dict(
l=25,
r=0,
b=100,
t=50,
pad=0,
)
)
app = dash.Dash(__name__)
server = app.server
app.layout = html.Div(children=[
# html.H1(children='Test2'),
# html.Div(children='''
# Example of html Container
# '''),
dcc.Graph(
id='fig',
figure=fig
)
])
if __name__ == '__main__':
app.run_server(debug=True)
The problem here is not on sliders but on the traces you are defining in data_slider. You need to play with the visible parameter in order to have the first plot properly rendered. The following trick should work.
data_slider = []
for i, year in enumerate(df.iyear.unique()):
df_year = df[(df['iyear'] == year)]
data_year = dict(
type='choropleth',
name='',
colorscale='amp',
locations=df_year['country_txt'],
z=df_year['nkill'],
zmax=15000,
zmin=0,
locationmode='country names',
visible= True if i==0 else False,
colorbar=dict(
len=0.5,
thickness=10,
title=dict(
text='Number of fatalities',
font=dict(
family='Arial',
size=14,
),
side='right'
),
tickfont=dict(
family='Arial',
size=12),
)
)
data_slider.append(data_year)
Extra
Given that you are generating all the plots outside the app you could actually avoid to use dash.