Related
I've got an interactive bar chart that displays counts from days of the week. I'm trying to set the color map so each day of the week maintains the same color. At the moment, if I remove any days, the color changes.
Separately, is it possible to keep the same dropdown values for days of the week and map the same color sequence but plot DATES instead of days of the week?
from dash import dcc
from dash import html
import dash_bootstrap_components as dbc
import dash
from dash.dependencies import Input, Output, State
from datetime import datetime
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
from datetime import datetime as dt
df = pd.DataFrame({
'Type': ['A','B','B','B','C','C','D','E','E','E','E','F','F','F'],
})
N = 30
df = pd.concat([df] * N, ignore_index=True)
df['TIMESTAMP'] = pd.date_range(start='2022/01/01 07:30', end='2022/01/30 08:30', periods=len(df))
df['TIMESTAMP'] = pd.to_datetime(df['TIMESTAMP'], dayfirst = True).sort_values()
df['TIMESTAMP'] = df['TIMESTAMP'].dt.floor('1min')
df['DATE'], df['TIME'] = zip(*[(d.date(), d.time()) for d in df['TIMESTAMP']])
df['DATE'] = pd.to_datetime(df['DATE'])
df['YEAR'] = df['DATE'].dt.year
df = df.sort_values(by = 'DATE')
df['DOW'] = df['DATE'].dt.weekday
df = df.sort_values('DOW').reset_index(drop=True)
df['DOW'] = df['DATE'].dt.day_name()
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets = external_stylesheets)
filter_box = html.Div(children=[
################### Filter box ######################
html.Div(children=[
html.Label('Day of the week:', style={'paddingTop': '2rem'}),
dcc.Dropdown(
id='DOW',
options=[
{'label': x, 'value': x} for x in df['DOW'].unique()
],
value=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday'],
multi=True
),
], className="four columns",
style={'padding':'2rem', 'margin':'1rem'} )
])
app.layout = dbc.Container([
dbc.Row([
dbc.Col(html.Div(filter_box, className="bg-secondary h-100"), width=2),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
dbc.Row([
dbc.Col(dcc.Graph(id = 'date-bar-chart'), style={
"padding-bottom": "10px",
},),
]),
dbc.Row([
]),
], width=5),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
], width=5),
])
], fluid=True)
#app.callback(
Output('date-bar-chart', 'figure'),
[Input("DOW", "value"),
])
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
dff['Color'] = dff['DOW'].map(dict(zip(dff['DOW'].unique(),
px.colors.qualitative.Plotly[:len(dff['DOW'].unique())])))
Color = dff['Color'].unique()
Category = dff['DOW'].unique()
cats = dict(zip(Color, Category))
data = px.bar(x = count.index,
y = count.values,
color = count.index,
color_discrete_map = cats,
)
layout = go.Layout(title = 'Date')
fig = go.Figure(data = data, layout = layout)
return fig
if __name__ == '__main__':
app.run_server(debug=True, port = 8051)
The accepted answer is too complicated and doesn't answer the second question.
For the first question on the color_discrete_map parameter, you should define a proper dictionary with keys as week day names and values as colors like this. You don't need df['Color'], Color, Category, etc.
import pandas as pd
...
color_map = {
pd.Timestamp(2023, 2, 13+i).day_name(): # 2-13 was monday.
px.colors.qualitative.Plotly[i]
for i in range(7)
}
...
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
data = px.bar(x = count.index,
y = count.values,
color = count.index,
color_discrete_map = color_map,
)
...
For the second question, you need a logic to choose one of the rows matching a given week day. The following is one example which chooses the first one.(This uses the group_by(), so the value_counts() is not necessary.)
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
g = dff.groupby('DOW', as_index=False)
g_df = g.head(1).merge(g.size())
data = px.bar(x = g_df['DATE'],
y = g_df['size'],
color = g_df['DOW'],
color_discrete_map = color_map,
)
...
Because you are setting cats in your callback so each time your dff change based on filter, your dict will be changed. So that I think you should define your color_discrete_map with df, not dff. And I think you should change your cats to cats = dict(zip(Category,Color))
from dash import dcc
from dash import html
import dash_bootstrap_components as dbc
import dash
from dash.dependencies import Input, Output, State
from datetime import datetime
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
from datetime import datetime as dt
df = pd.DataFrame({
'Type': ['A','B','B','B','C','C','D','E','E','E','E','F','F','F'],
})
N = 30
df = pd.concat([df] * N, ignore_index=True)
df['TIMESTAMP'] = pd.date_range(start='2022/01/01 07:30', end='2022/01/30 08:30', periods=len(df))
df['TIMESTAMP'] = pd.to_datetime(df['TIMESTAMP'], dayfirst = True).sort_values()
df['TIMESTAMP'] = df['TIMESTAMP'].dt.floor('1min')
df['DATE'], df['TIME'] = zip(*[(d.date(), d.time()) for d in df['TIMESTAMP']])
df['DATE'] = pd.to_datetime(df['DATE'])
df['YEAR'] = df['DATE'].dt.year
df = df.sort_values(by = 'DATE')
df['DOW'] = df['DATE'].dt.weekday
df = df.sort_values('DOW').reset_index(drop=True)
df['DOW'] = df['DATE'].dt.day_name()
df['Color'] = df['DOW'].map(dict(zip(df['DOW'].unique(),
px.colors.qualitative.Plotly[:len(df['DOW'].unique())])))
Color = df['Color'].unique()
Category = df['DOW'].unique()
cats = dict(zip(Category,Color))
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets = external_stylesheets)
filter_box = html.Div(children=[
################### Filter box ######################
html.Div(children=[
html.Label('Day of the week:', style={'paddingTop': '2rem'}),
dcc.Dropdown(
id='DOW',
options=[
{'label': x, 'value': x} for x in df['DOW'].unique()
],
value=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday'],
multi=True
),
], className="four columns",
style={'padding':'2rem', 'margin':'1rem'} )
])
app.layout = dbc.Container([
dbc.Row([
dbc.Col(html.Div(filter_box, className="bg-secondary h-100"), width=2),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
dbc.Row([
dbc.Col(dcc.Graph(id = 'date-bar-chart'), style={
"padding-bottom": "10px",
},),
]),
dbc.Row([
]),
], width=5),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
], width=5),
])
], fluid=True)
#app.callback(
Output('date-bar-chart', 'figure'),
[Input("DOW", "value"),
])
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
data = px.bar(x = count.index,
y = count.values,
color = count.index,
color_discrete_map = cats,
)
return data
if __name__ == '__main__':
app.run_server(debug=False, port = 8051)
I would like to add a range slider along with my dropdown, and make the range slider the 'Wallclock' datetime along with an interaction that allows the range slider to chose the datetime for that capsules based on the dropdown value. I managed to find several ways that other people have done this but none seems to work for my situation especially the callback and the update of the graph. Thank you!
Data looks like this.
Dash looks like this.
Code looks like this.
import pandas as pd
import plotly.express as px # (version 4.7.0)
import plotly.graph_objects as go
import numpy as np
import openpyxl
import dash # (version 1.12.0) pip install dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
app = dash.Dash(__name__)
server = app.server
df = pd.read_excel("tcd vs rh 2.xlsx")
print(df)
capsuleID = df['Capsule_ID'].unique()
print(capsuleID)
capsuleID_names = sorted(list(capsuleID))
print(capsuleID_names)
capsuleID_names_1 = [{'label': k, 'value': k} for k in sorted(capsuleID)]
capsuleID_names_2 = [{'label': '(Select All)', 'value': 'All'}]
capsuleID_names_all = capsuleID_names_1 + capsuleID_names_2
app.layout = html.Div([
html.H1("Relative Humidity vs TCD", style={'text-align': 'center'}),
dcc.Dropdown(id="capsule_select",
options=capsuleID_names_all,
optionHeight=25,
multi=True,
searchable=True,
placeholder='Please select...',
clearable=True,
value=['All'],
style={'width': "100%"}
),
dcc.RangeSlider(id='slider',
min=df['Wallclock'].min(),
max=df['Wallclock'].max(),
value=[df.iloc[-101]['Wallclock'].timestamp(), df.iloc[-1]['Wallclock'].timestamp()]
),
html.Div([
dcc.Graph(id="the_graph"),
]),
])
# -----------------------------------------------------------
#app.callback(
Output('the_graph', 'figure'),
Output('capsule_select', 'value'),
Input('capsule_select', 'value'),
Input('slider', 'value'),
)
def update_graph(capsule_chosen):
lBound = pd.to_datetime(value[0], unit='s')
uBound = pd.to_datetime(value[1], unit='s')
filteredData = df.loc[(df['date'] >= lBound) & (df['date'] <= uBound)]
dropdown_values = capsule_chosen
if "All" in capsule_chosen:
dropdown_values = capsuleID_names
dff = df
else:
dff = df[df['Capsule_ID'].isin(capsule_chosen)] # filter all rows where capsule ID is the capsule ID selected
scatterplot = px.scatter(
data_frame=dff,
x="tcd",
y="humidity",
hover_name="Wallclock",
)
scatterplot.update_traces(textposition='top center')
return scatterplot, dropdown_values
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app.run_server(debug=True)
obviously I don't have access to your Excel spreadsheet so generated a data frame with same shape
taken approach of using a second figure with a rangeslider for slider capability
updated callback to use this figure as input for date range
used jupyter dash inline, this can be changed back to your setup (commented lines)
generate some sample data
import pandas as pd
import numpy as np
df = pd.DataFrame(
{
"Wallclock": pd.date_range(
"22-dec-2020 00:01:36", freq="5min", periods=2000
),
"tcd": np.linspace(3434, 3505, 2000) *np.random.uniform(.9,1.1, 2000),
"humidity": np.linspace(63, 96, 2000),
}
).pipe(lambda d: d.assign(Capsule_ID=(d.index // (len(d)//16))+2100015))
slider is a figure with a rangeslider
import pandas as pd
import plotly.express as px # (version 4.7.0)
import plotly.graph_objects as go
import numpy as np
import openpyxl
import dash # (version 1.12.0) pip install dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
from jupyter_dash import JupyterDash
# app = dash.Dash(__name__)
# server = app.server
app = JupyterDash(__name__)
# df = pd.read_excel("tcd vs rh 2.xlsx")
# print(df)
capsuleID = df["Capsule_ID"].unique()
# print(capsuleID)
capsuleID_names = sorted(list(capsuleID))
# print(capsuleID_names)
capsuleID_names_1 = [{"label": k, "value": k} for k in sorted(capsuleID)]
capsuleID_names_2 = [{"label": "(Select All)", "value": "All"}]
capsuleID_names_all = capsuleID_names_1 + capsuleID_names_2
def slider_fig(df):
return px.scatter(
df.groupby("Wallclock", as_index=False).size(), x="Wallclock", y="size"
).update_layout(
xaxis={"rangeslider": {"visible": True}, "title":None},
height=125,
yaxis={"tickmode": "array", "tickvals": [], "title": None},
margin={"l": 0, "r": 0, "t": 0, "b": 0},
)
app.layout = html.Div(
[
html.H1("Relative Humidity vs TCD", style={"text-align": "center"}),
dcc.Dropdown(
id="capsule_select",
options=capsuleID_names_all,
optionHeight=25,
multi=True,
searchable=True,
placeholder="Please select...",
clearable=True,
value=["All"],
style={"width": "100%"},
),
dcc.Graph(
id="slider",
figure=slider_fig(df),
),
html.Div(
[
dcc.Graph(id="the_graph"),
]
),
]
)
# -----------------------------------------------------------
#app.callback(
Output("the_graph", "figure"),
Output("capsule_select", "value"),
Output("slider", "figure"),
Input("capsule_select", "value"),
Input('slider', 'relayoutData'),
State("slider", "figure")
)
def update_graph(capsule_chosen, slider, sfig):
dropdown_values = capsule_chosen
if "All" in capsule_chosen:
dropdown_values = capsuleID_names
dff = df
else:
dff = df[
df["Capsule_ID"].isin(capsule_chosen)
] # filter all rows where capsule ID is the capsule ID selected
if slider and "xaxis.range" in slider.keys():
dff = dff.loc[dff["Wallclock"].between(*slider["xaxis.range"])]
else:
# update slider based on selected capsules
sfig = slider_fig(dff)
scatterplot = px.scatter(
data_frame=dff,
x="tcd",
y="humidity",
hover_name="Wallclock",
)
scatterplot.update_traces(textposition="top center")
return scatterplot, dropdown_values, sfig
# ------------------------------------------------------------------------------
if __name__ == "__main__":
# app.run_server(debug=True)
app.run_server(mode="inline")
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.
I'm trying to hide time gaps in the stock market. My problem is that I don't know how to use rangebreaks correctly in dash. https://plotly.com/python/reference/#layout-xaxis-rangebreaks
https://plotly.com/python/time-series/
app = dash.Dash()
app.layout = html.Div([
dcc.Graph(id='graph'),
dcc.Dropdown(id='chooser',options=companies_options,value='CDPROJEKT')
])
#app.callback(Output('graph', 'figure'),
[Input('chooser', 'value')])
def update_figure(selected_company):
df_by_company = df_full[df_full['Nazwa'] == selected_company]
df_by_company= df_by_company[(df_by_company['date'].dt.hour<17) & (df_by_company['date'].dt.hour>8)]
traces = []
print(df_by_company['date'].unique())
traces.append(go.Scatter(
x=df_by_company['date'],
y=df_by_company['Kurs'],
text=df_by_company['Nazwa'],
mode='markers',
opacity=0.7,
#marker={'size': 15},
name=selected_company
))
return {
'data': traces,
'layout': go.Layout(
xaxis= dict(title= 'Time',rangebreaks=[dict(bounds=[17, 8])]),
yaxis={'title': 'Price' },
hovermode='closest'
)
}
if __name__ == '__main__':
app.run_server()
This is my output graph.
https://prnt.sc/rttbkk
Edit:
When I simplified the code I found a solution for my problem.
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
df= pd.read_csv('cdr.csv')
app = dash.Dash()
app.layout = html.Div([dcc.Graph(id='scatterplot',
figure = {'data':[
go.Scatter(
x=df['date'],
y=df['price'],
mode='markers')],
'layout':go.Layout(title='My Scatterplot',
xaxis= dict(title= 'Time', rangebreaks=[{ 'pattern': 'hour', 'bounds': [17.5, 8.5] } ]) )}
)])
if __name__ == '__main__':
app.run_server()
My csv file looks like that:
date,number,price
2020-04-03 17:04:15,8838,297.0
https://prnt.sc/ruyob3
Is it possible to have a dash app within a Jupyter Notebook, rather than served up and viewed in a browser?
My intention is to link graphs within a Jupyter notebook so that hovering over one graph generates the input required for another graph.
(Disclaimer, I help maintain Dash)
See https://github.com/plotly/jupyterlab-dash. This is a JupyterLab extension that embeds Dash within Jupyter.
Also see alternative solutions in the Dash Community Forum like the Can I run dash app in jupyter topic.
There's already a great answer to this question, but this contribution will focus directly on:
1. How to use Dash within Jupyterlab, and
2. how to select graphing input by hovering over another graph
Following these steps will unleash Plotly Dash directly in JupyterLab:
1. Install the latest Plotly version
2. Installl JupyterLab Dash with conda install -c plotly jupyterlab-dash
3. Using the snippet provided a bit further down launch a Dash app that contains an animation built on a pandas dataframe that expands every second.
Screenshot of the Dash in JupyterLab (code in snippet below)
This image shows Dash literally fired up inside JupyterLab. The four highlighted sections are:
1 - Cell. A cell in a .ipynb that you're already probably very familiar with
2 - Dash. A "live" dash app that expands all three traces with a random number and shows the updated figure every second.
3 - Console. An console where you can inspect available elements in your script using, for example, fig.show
4 - mode. This shows where some true magic resides:
app.run_server(mode='jupyterlab', port = 8090, dev_tools_ui=True, #debug=True,
dev_tools_hot_reload =True, threaded=True)
You can choose to fire up the dash app in:
Jupyterlab, like in the screenshot with mode='jupyterlab',
or in a cell, using mode='inline':
or in your default browser using mode='external'
Code 1:
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
# code and plot setup
# settings
pd.options.plotting.backend = "plotly"
# sample dataframe of a wide format
np.random.seed(4); cols = list('abc')
X = np.random.randn(50,len(cols))
df=pd.DataFrame(X, columns=cols)
df.iloc[0]=0;
# plotly figure
fig = df.plot(template = 'plotly_dark')
app = JupyterDash(__name__)
app.layout = html.Div([
html.H1("Random datastream"),
dcc.Interval(
id='interval-component',
interval=1*1000, # in milliseconds
n_intervals=0
),
dcc.Graph(id='graph'),
])
# Define callback to update graph
#app.callback(
Output('graph', 'figure'),
[Input('interval-component', "n_intervals")]
)
def streamFig(value):
global df
Y = np.random.randn(1,len(cols))
df2 = pd.DataFrame(Y, columns = cols)
df = df.append(df2, ignore_index=True)#.reset_index()
df.tail()
df3=df.copy()
df3 = df3.cumsum()
fig = df3.plot(template = 'plotly_dark')
#fig.show()
return(fig)
app.run_server(mode='jupyterlab', port = 8090, dev_tools_ui=True, #debug=True,
dev_tools_hot_reload =True, threaded=True)
But the good news does not end there, regarding:
My intention is to link graphs within a Jupyter notebook so that
hovering over one graph generates the input required for another
graph.
There's a perfect example on dash.plotly.com that will do exactly that for you under the paragraph Update Graphs on Hover:
I've made the few necessary changes in the original setup to make it possible to run it in JupyterLab.
Code snippet 2 - Select graph source by hovering:
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash.dependencies
# code and plot setup
# settings
pd.options.plotting.backend = "plotly"
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
df = pd.read_csv('https://plotly.github.io/datasets/country_indicators.csv')
available_indicators = df['Indicator Name'].unique()
app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(
id='crossfilter-xaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Fertility rate, total (births per woman)'
),
dcc.RadioItems(
id='crossfilter-xaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block'}
)
],
style={'width': '49%', 'display': 'inline-block'}),
html.Div([
dcc.Dropdown(
id='crossfilter-yaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Life expectancy at birth, total (years)'
),
dcc.RadioItems(
id='crossfilter-yaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block'}
)
], style={'width': '49%', 'float': 'right', 'display': 'inline-block'})
], style={
'borderBottom': 'thin lightgrey solid',
'backgroundColor': 'rgb(250, 250, 250)',
'padding': '10px 5px'
}),
html.Div([
dcc.Graph(
id='crossfilter-indicator-scatter',
hoverData={'points': [{'customdata': 'Japan'}]}
)
], style={'width': '49%', 'display': 'inline-block', 'padding': '0 20'}),
html.Div([
dcc.Graph(id='x-time-series'),
dcc.Graph(id='y-time-series'),
], style={'display': 'inline-block', 'width': '49%'}),
html.Div(dcc.Slider(
id='crossfilter-year--slider',
min=df['Year'].min(),
max=df['Year'].max(),
value=df['Year'].max(),
marks={str(year): str(year) for year in df['Year'].unique()},
step=None
), style={'width': '49%', 'padding': '0px 20px 20px 20px'})
])
#app.callback(
dash.dependencies.Output('crossfilter-indicator-scatter', 'figure'),
[dash.dependencies.Input('crossfilter-xaxis-column', 'value'),
dash.dependencies.Input('crossfilter-yaxis-column', 'value'),
dash.dependencies.Input('crossfilter-xaxis-type', 'value'),
dash.dependencies.Input('crossfilter-yaxis-type', 'value'),
dash.dependencies.Input('crossfilter-year--slider', 'value')])
def update_graph(xaxis_column_name, yaxis_column_name,
xaxis_type, yaxis_type,
year_value):
dff = df[df['Year'] == year_value]
fig = px.scatter(x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
hover_name=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name']
)
fig.update_traces(customdata=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'])
fig.update_xaxes(title=xaxis_column_name, type='linear' if xaxis_type == 'Linear' else 'log')
fig.update_yaxes(title=yaxis_column_name, type='linear' if yaxis_type == 'Linear' else 'log')
fig.update_layout(margin={'l': 40, 'b': 40, 't': 10, 'r': 0}, hovermode='closest')
return fig
def create_time_series(dff, axis_type, title):
fig = px.scatter(dff, x='Year', y='Value')
fig.update_traces(mode='lines+markers')
fig.update_xaxes(showgrid=False)
fig.update_yaxes(type='linear' if axis_type == 'Linear' else 'log')
fig.add_annotation(x=0, y=0.85, xanchor='left', yanchor='bottom',
xref='paper', yref='paper', showarrow=False, align='left',
bgcolor='rgba(255, 255, 255, 0.5)', text=title)
fig.update_layout(height=225, margin={'l': 20, 'b': 30, 'r': 10, 't': 10})
return fig
#app.callback(
dash.dependencies.Output('x-time-series', 'figure'),
[dash.dependencies.Input('crossfilter-indicator-scatter', 'hoverData'),
dash.dependencies.Input('crossfilter-xaxis-column', 'value'),
dash.dependencies.Input('crossfilter-xaxis-type', 'value')])
def update_y_timeseries(hoverData, xaxis_column_name, axis_type):
country_name = hoverData['points'][0]['customdata']
dff = df[df['Country Name'] == country_name]
dff = dff[dff['Indicator Name'] == xaxis_column_name]
title = '<b>{}</b><br>{}'.format(country_name, xaxis_column_name)
return create_time_series(dff, axis_type, title)
#app.callback(
dash.dependencies.Output('y-time-series', 'figure'),
[dash.dependencies.Input('crossfilter-indicator-scatter', 'hoverData'),
dash.dependencies.Input('crossfilter-yaxis-column', 'value'),
dash.dependencies.Input('crossfilter-yaxis-type', 'value')])
def update_x_timeseries(hoverData, yaxis_column_name, axis_type):
dff = df[df['Country Name'] == hoverData['points'][0]['customdata']]
dff = dff[dff['Indicator Name'] == yaxis_column_name]
return create_time_series(dff, axis_type, yaxis_column_name)
app.run_server(mode='jupyterlab', port = 8090, dev_tools_ui=True, #debug=True,
dev_tools_hot_reload =True, threaded=True)
I am not sure dash apps can be displayed within a Jupyter notebook. But if what you're looking for is using sliders, combo boxes and other buttons, you may be interested in ipywidgets that come from Jupyter directly.
These may be used with plotly, as shown here.
EDIT
Eventually it seems that there are solutions to embed dash apps inside Jupyter by using an iframe and IPython.display.display_html().
See this function and this GitHub repo for details.
See https://medium.com/plotly/introducing-jupyterdash-811f1f57c02e
$ pip install jupyter-dash
from jupyter_dash import JupyterDash
app = JupyterDash(__name__)
<your code>
app.run_server(mode='inline')
Look for plotly offline.
Say you have a figure (e.g. fig = {'data': data, 'layout':layout} )
Then,
inside a jupyter notebook cell,
from plotly.offline import iplot, init_notebook_mode
init_notebook_mode()
# plot it
iplot(fig)
This will plot the plotly inside your jupyter. You dont even have to run the flask server.