Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Commit c3967e7

Browse files
committed
Add example notebook
1 parent 7b74d1c commit c3967e7

File tree

1 file changed

+333
-0
lines changed

1 file changed

+333
-0
lines changed

notebooks/getting_started.ipynb

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# JupyterDash\n",
8+
"The `jupyter-dash` package makes it easy to develop Plotly Dash apps from the Jupyter Notebook and JupyterLab.\n",
9+
"\n",
10+
"Just replace the standard `dash.Dash` class with the `jupyter_dash.JupyterDash` subclass."
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": 25,
16+
"metadata": {},
17+
"outputs": [],
18+
"source": [
19+
"from jupyter_dash import JupyterDash"
20+
]
21+
},
22+
{
23+
"cell_type": "code",
24+
"execution_count": 26,
25+
"metadata": {},
26+
"outputs": [],
27+
"source": [
28+
"import dash\n",
29+
"import dash_core_components as dcc\n",
30+
"import dash_html_components as html\n",
31+
"import pandas as pd"
32+
]
33+
},
34+
{
35+
"cell_type": "markdown",
36+
"metadata": {},
37+
"source": [
38+
"When running in JupyterHub or Binder, call the `infer_jupyter_config` function to detect the proxy configuration."
39+
]
40+
},
41+
{
42+
"cell_type": "code",
43+
"execution_count": 28,
44+
"metadata": {},
45+
"outputs": [],
46+
"source": [
47+
"JupyterDash.infer_jupyter_config()"
48+
]
49+
},
50+
{
51+
"cell_type": "markdown",
52+
"metadata": {},
53+
"source": [
54+
"Load and preprocess data"
55+
]
56+
},
57+
{
58+
"cell_type": "code",
59+
"execution_count": 29,
60+
"metadata": {},
61+
"outputs": [],
62+
"source": [
63+
"df = pd.read_csv('https://plotly.github.io/datasets/country_indicators.csv')\n",
64+
"available_indicators = df['Indicator Name'].unique()"
65+
]
66+
},
67+
{
68+
"cell_type": "markdown",
69+
"metadata": {},
70+
"source": [
71+
"Construct the app and callbacks"
72+
]
73+
},
74+
{
75+
"cell_type": "code",
76+
"execution_count": 30,
77+
"metadata": {},
78+
"outputs": [],
79+
"source": [
80+
"external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']\n",
81+
"\n",
82+
"app = JupyterDash(__name__, external_stylesheets=external_stylesheets)\n",
83+
"\n",
84+
"app.layout = html.Div([\n",
85+
" html.Div([\n",
86+
"\n",
87+
" html.Div([\n",
88+
" dcc.Dropdown(\n",
89+
" id='crossfilter-xaxis-column',\n",
90+
" options=[{'label': i, 'value': i} for i in available_indicators],\n",
91+
" value='Fertility rate, total (births per woman)'\n",
92+
" ),\n",
93+
" dcc.RadioItems(\n",
94+
" id='crossfilter-xaxis-type',\n",
95+
" options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],\n",
96+
" value='Linear',\n",
97+
" labelStyle={'display': 'inline-block'}\n",
98+
" )\n",
99+
" ],\n",
100+
" style={'width': '49%', 'display': 'inline-block'}),\n",
101+
"\n",
102+
" html.Div([\n",
103+
" dcc.Dropdown(\n",
104+
" id='crossfilter-yaxis-column',\n",
105+
" options=[{'label': i, 'value': i} for i in available_indicators],\n",
106+
" value='Life expectancy at birth, total (years)'\n",
107+
" ),\n",
108+
" dcc.RadioItems(\n",
109+
" id='crossfilter-yaxis-type',\n",
110+
" options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],\n",
111+
" value='Linear',\n",
112+
" labelStyle={'display': 'inline-block'}\n",
113+
" )\n",
114+
" ], style={'width': '49%', 'float': 'right', 'display': 'inline-block'})\n",
115+
" ], style={\n",
116+
" 'borderBottom': 'thin lightgrey solid',\n",
117+
" 'backgroundColor': 'rgb(250, 250, 250)',\n",
118+
" 'padding': '10px 5px'\n",
119+
" }),\n",
120+
"\n",
121+
" html.Div([\n",
122+
" dcc.Graph(\n",
123+
" id='crossfilter-indicator-scatter',\n",
124+
" hoverData={'points': [{'customdata': 'Japan'}]}\n",
125+
" )\n",
126+
" ], style={'width': '49%', 'display': 'inline-block', 'padding': '0 20'}),\n",
127+
" html.Div([\n",
128+
" dcc.Graph(id='x-time-series'),\n",
129+
" dcc.Graph(id='y-time-series'),\n",
130+
" ], style={'display': 'inline-block', 'width': '49%'}),\n",
131+
"\n",
132+
" html.Div(dcc.Slider(\n",
133+
" id='crossfilter-year--slider',\n",
134+
" min=df['Year'].min(),\n",
135+
" max=df['Year'].max(),\n",
136+
" value=df['Year'].max(),\n",
137+
" marks={str(year): str(year) for year in df['Year'].unique()},\n",
138+
" step=None\n",
139+
" ), style={'width': '49%', 'padding': '0px 20px 20px 20px'})\n",
140+
"])\n",
141+
"\n",
142+
"\n",
143+
"@app.callback(\n",
144+
" dash.dependencies.Output('crossfilter-indicator-scatter', 'figure'),\n",
145+
" [dash.dependencies.Input('crossfilter-xaxis-column', 'value'),\n",
146+
" dash.dependencies.Input('crossfilter-yaxis-column', 'value'),\n",
147+
" dash.dependencies.Input('crossfilter-xaxis-type', 'value'),\n",
148+
" dash.dependencies.Input('crossfilter-yaxis-type', 'value'),\n",
149+
" dash.dependencies.Input('crossfilter-year--slider', 'value')])\n",
150+
"def update_graph(xaxis_column_name, yaxis_column_name,\n",
151+
" xaxis_type, yaxis_type,\n",
152+
" year_value):\n",
153+
" dff = df[df['Year'] == year_value]\n",
154+
"\n",
155+
" return {\n",
156+
" 'data': [dict(\n",
157+
" x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],\n",
158+
" y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],\n",
159+
" text=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'],\n",
160+
" customdata=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'],\n",
161+
" mode='markers',\n",
162+
" marker={\n",
163+
" 'size': 25,\n",
164+
" 'opacity': 0.5,\n",
165+
" 'line': {'width': 2, 'color': 'purple'}\n",
166+
" }\n",
167+
" )],\n",
168+
" 'layout': dict(\n",
169+
" xaxis={\n",
170+
" 'title': xaxis_column_name,\n",
171+
" 'type': 'linear' if xaxis_type == 'Linear' else 'log'\n",
172+
" },\n",
173+
" yaxis={\n",
174+
" 'title': yaxis_column_name,\n",
175+
" 'type': 'linear' if yaxis_type == 'Linear' else 'log'\n",
176+
" },\n",
177+
" margin={'l': 40, 'b': 30, 't': 10, 'r': 0},\n",
178+
" height=450,\n",
179+
" hovermode='closest'\n",
180+
" )\n",
181+
" }\n",
182+
"\n",
183+
"\n",
184+
"def create_time_series(dff, axis_type, title):\n",
185+
" return {\n",
186+
" 'data': [dict(\n",
187+
" x=dff['Year'],\n",
188+
" y=dff['Value'],\n",
189+
" mode='lines+markers'\n",
190+
" )],\n",
191+
" 'layout': {\n",
192+
" 'height': 225,\n",
193+
" 'margin': {'l': 20, 'b': 30, 'r': 10, 't': 10},\n",
194+
" 'annotations': [{\n",
195+
" 'x': 0, 'y': 0.85, 'xanchor': 'left', 'yanchor': 'bottom',\n",
196+
" 'xref': 'paper', 'yref': 'paper', 'showarrow': False,\n",
197+
" 'align': 'left', 'bgcolor': 'rgba(255, 255, 255, 0.5)',\n",
198+
" 'text': title\n",
199+
" }],\n",
200+
" 'yaxis': {'type': 'linear' if axis_type == 'Linear' else 'log'},\n",
201+
" 'xaxis': {'showgrid': False}\n",
202+
" }\n",
203+
" }\n",
204+
"\n",
205+
"\n",
206+
"@app.callback(\n",
207+
" dash.dependencies.Output('x-time-series', 'figure'),\n",
208+
" [dash.dependencies.Input('crossfilter-indicator-scatter', 'hoverData'),\n",
209+
" dash.dependencies.Input('crossfilter-xaxis-column', 'value'),\n",
210+
" dash.dependencies.Input('crossfilter-xaxis-type', 'value')])\n",
211+
"def update_y_timeseries(hoverData, xaxis_column_name, axis_type):\n",
212+
" country_name = hoverData['points'][0]['customdata']\n",
213+
" dff = df[df['Country Name'] == country_name]\n",
214+
" dff = dff[dff['Indicator Name'] == xaxis_column_name]\n",
215+
" title = '<b>{}</b><br>{}'.format(country_name, xaxis_column_name)\n",
216+
" return create_time_series(dff, axis_type, title)\n",
217+
"\n",
218+
"\n",
219+
"@app.callback(\n",
220+
" dash.dependencies.Output('y-time-series', 'figure'),\n",
221+
" [dash.dependencies.Input('crossfilter-indicator-scatter', 'hoverData'),\n",
222+
" dash.dependencies.Input('crossfilter-yaxis-column', 'value'),\n",
223+
" dash.dependencies.Input('crossfilter-yaxis-type', 'value')])\n",
224+
"def update_x_timeseries(hoverData, yaxis_column_name, axis_type):\n",
225+
" dff = df[df['Country Name'] == hoverData['points'][0]['customdata']]\n",
226+
" dff = dff[dff['Indicator Name'] == yaxis_column_name]\n",
227+
" return create_time_series(dff, axis_type, yaxis_column_name)"
228+
]
229+
},
230+
{
231+
"cell_type": "markdown",
232+
"metadata": {},
233+
"source": [
234+
"Serve the app using `run_server`. Unlike the standard `Dash.run_server` method, the `JupyterDash.run_server` method doesn't block execution of the notebook. It serves the app in a background thread, making it possible to run other notebook calculations while the app is running.\n",
235+
"\n",
236+
"This makes it possible to iterativly update the app without rerunning the potentially expensive data processing steps."
237+
]
238+
},
239+
{
240+
"cell_type": "code",
241+
"execution_count": 32,
242+
"metadata": {},
243+
"outputs": [
244+
{
245+
"name": "stdout",
246+
"output_type": "stream",
247+
"text": [
248+
"Dash app running on http://127.0.0.1:8889/proxy/8050/\n"
249+
]
250+
}
251+
],
252+
"source": [
253+
"app.run_server()"
254+
]
255+
},
256+
{
257+
"cell_type": "markdown",
258+
"metadata": {},
259+
"source": [
260+
"By default, `run_server` displays a URL that you can click on to open the app in a browser tab. The `mode` argument to `run_server` can be used to change this behavior. Setting `mode=\"inline\"` will display the app directly in the notebook output cell."
261+
]
262+
},
263+
{
264+
"cell_type": "code",
265+
"execution_count": 33,
266+
"metadata": {},
267+
"outputs": [
268+
{
269+
"data": {
270+
"text/html": [
271+
"\n",
272+
" <iframe\n",
273+
" width=\"800\"\n",
274+
" height=\"650\"\n",
275+
" src=\"http://127.0.0.1:8889/proxy/8050/\"\n",
276+
" frameborder=\"0\"\n",
277+
" allowfullscreen\n",
278+
" ></iframe>\n",
279+
" "
280+
],
281+
"text/plain": [
282+
"<IPython.lib.display.IFrame at 0x7f71ccd63fd0>"
283+
]
284+
},
285+
"metadata": {},
286+
"output_type": "display_data"
287+
}
288+
],
289+
"source": [
290+
"app.run_server(mode=\"inline\")"
291+
]
292+
},
293+
{
294+
"cell_type": "markdown",
295+
"metadata": {},
296+
"source": [
297+
"When running in JupyterLab, with the `jupyterlab-dash` extension, setting `mode=\"jupyterlab\"` will open the app in a tab in JupyterLab.\n",
298+
"\n",
299+
"```python\n",
300+
"app.run_server(mode=\"jupyterlab\")\n",
301+
"```"
302+
]
303+
},
304+
{
305+
"cell_type": "code",
306+
"execution_count": null,
307+
"metadata": {},
308+
"outputs": [],
309+
"source": []
310+
}
311+
],
312+
"metadata": {
313+
"kernelspec": {
314+
"display_name": "Python 3",
315+
"language": "python",
316+
"name": "python3"
317+
},
318+
"language_info": {
319+
"codemirror_mode": {
320+
"name": "ipython",
321+
"version": 3
322+
},
323+
"file_extension": ".py",
324+
"mimetype": "text/x-python",
325+
"name": "python",
326+
"nbconvert_exporter": "python",
327+
"pygments_lexer": "ipython3",
328+
"version": "3.7.6"
329+
}
330+
},
331+
"nbformat": 4,
332+
"nbformat_minor": 4
333+
}

0 commit comments

Comments
 (0)