{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Getting Started With `plotly` and `dash` in Python\n", "\n", "\"Creative\n", "This tutorial is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.\n", "\n", "## Acknowledgements\n", "\n", "The author consulted the following resources when writing this tutorial:\n", "- [`plotly` documentation and tutorials](https://plotly.com/python/)\n", "- [`dash` documentation and tutorials](https://dash.plotly.com/)\n", "\n", "# Table of Contents\n", "\n", "- [Overview](#overview)\n", " * [Basic `dash` Syntax](#basic-dash-syntax)\n", " * [Customizing `dash` Layout with `dash_html_components`](#customizing-dash-layout-with-dash-html-components)\n", " * [Customizing `dash` Layout with `dash_core_components`](#customizing-dash-layout-with-dash-core-components)\n", " * [Setting Up Callbacks](#setting-up-callbacks)\n", " * [Additional Resources](#additional-resources)\n", " * [Publishing a `dash` App](#publishing-a-dash-app)\n", "\n", "# Overview\n", "\n", "1. We may want to create an interactive web application featuring a `plotly` figure.\n", "\n", "2. We see this kind of interactivity in dashboard-style interfaces, like the [Johns Hopkins University COVID-19 Dashboard](https://coronavirus.jhu.edu/map.html).\n", "\n", "3. We can use the `dash` web application framework in combination with `plotly` to \"publish\" a figure as an interactive web application.\n", "\n", "4. `dash` was developed by the Plotly team and released in 2017.\n", "\n", "5. In addition to a limited free open-source version, Plotly also offers paid enterprise versions of `dash`.\n", "\n", "6. What exactly is `dash`?\n", "\n", "7. \"Dash is a productive Python framework for building web analytic applications. Written on top of Flask, Plotly.js, and React.js, Dash is ideal for building data visualization apps with highly custom user interfaces in pure Python. It's particularly suited for anyone who works with data in Python. Through a couple of simple patterns, Dash abstracts away all of the technologies and protocols that are required to build an interactive web-based application. Dash is simple enough that you can bind a user interface around your Python code in an afternoon. Dash apps are rendered in the web browser. You can deploy your apps to servers and then share them through URLs. Since Dash apps are viewed in the web browser, Dash is inherently cross-platform and mobile ready\" (`plotly`, [Introduction to Dash](https://dash.plotly.com/introduction)).\n", "\n", "8. For those familiar with RStudio's [Shiny package](v) (designed to build interactive web applications from within the R/RStudio programming environment), `dash` was originally pitched as the equivalent package for Python.\n", "\n", "9. Though originally built exclusively for `Python`, `dash` has since released versions for R/RStudio and Julia.\n", "\n", "10. For more background on `dash`:\n", "- plotly, [\"Introducing Dash\"](https://medium.com/plotly/introducing-dash-5ecf7191b503) *Medium* (21 June 2017)\n", "- Plotly, [\"PLOTCON 2016: Chris Parmer, Dash: Shiny for Python\"](https://youtu.be/5BAthiN0htc) *YouTube* (1 December 2016)\n", "- `plotly`, [Dash Enterprise App Gallery](https://dash-gallery.plotly.host/Portal/)\n", "- [Plotly, Dash GitHub repository](https://github.com/plotly/dash)\n", "\n", "11. To install `dash`:\n", "- using `pip`: `pip install dash`\n", "- in Jupyter notebook using `pip`: `pip install jupyter-dash`\n", "- in Jupyter notebook using `conda`: `conda install -c conda-forge -c plotly jupyter-dash`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys\n", "!{sys.executable} -m pip install jupyter-dash" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "12. The remainder of this tutorial focuses on `dash` outside the Jupyter notebook environment.\n", "\n", "13. For more on using `dash` in a notebook environment: plotly, [Jupyter-Dash Github Repository](https://github.com/plotly/jupyter-dash)\n", "\n", "## Basic `dash` Syntax\n", "\n", "14. `dash` apps include two main components.\n", "\n", "15. The app ***layout*** describes what the application looks like.\n", "\n", "16. The app ***interactivity*** describes the application's interactivity.\n", "\n", "17. `dash` uses pre-built Python classes for all visual components of the application (which can be customized if needed using JavaScript and React.js).\n", "\n", "18. The basic syntax for creating an application using `dash`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# at this point the figure has already been created and updated/configured/customized as needed\n", "\n", "# import dash components\n", "import dash\n", "import dash_core_components as dcc\n", "import dash_html_components as html\n", "\n", "# create app\n", "app = dash.Dash()\n", "\n", "# set app layout\n", "app.layout = html.Div([\n", " dcc.Graph(figure=fig)\n", "])\n", "\n", "# run app\n", "app.run_server(debug=True, use_reloader=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "19. Let's create an app using our tile-based choropleth map." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import urllib\n", "from urllib.request import urlopen\n", "\n", "# import json\n", "import json\n", "\n", "# load geojson data\n", "with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:\n", " counties = json.load(response)\n", "\n", "# import pandas\n", "import pandas as pd\n", "\n", "# load attribute data as dataframe\n", "df = pd.read_csv(\"https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv\",\n", " dtype={\"fips\": str})\n", "\n", "# import plotly\n", "import plotly.express as px\n", "\n", "# create figure\n", "fig = px.choropleth_mapbox(df, geojson=counties, locations='fips', color='unemp',\n", " color_continuous_scale=\"Viridis\",\n", " range_color=(0, 12),\n", " mapbox_style=\"carto-positron\",\n", " zoom=3, center = {\"lat\": 37.0902, \"lon\": -95.7129},\n", " opacity=0.5,\n", " labels={'unemp':'unemployment rate'}\n", " )\n", "\n", "# update figure layout\n", "fig.update_layout(margin={\"r\":0,\"t\":0,\"l\":0,\"b\":0})\n", "\n", "# show figure\n", "fig.show()\n", "\n", "# import dash components\n", "import dash\n", "import dash_core_components as dcc\n", "import dash_html_components as html\n", "\n", "# create app\n", "app = dash.Dash()\n", "\n", "# set app layout\n", "app.layout = html.Div([\n", " dcc.Graph(figure=fig)\n", "])\n", "\n", "# run app\n", "app.run_server(debug=True, use_reloader=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "20. At the bottom of each documentation page for a `plotly` figure type will be a \"What About Dash?\" section that provides a brief overview of how to publish that figure in a `dash` application.\n", "\n", "21. For example, [link to the \"What About Dash?\"](https://plotly.com/python/scattermapbox/#what-about-dash) section of the \"Scatter Plots on Mapbox in Python\" page.\n", "\n", "## Customizing `dash` Layout with `dash_html_components`\n", "\n", "22. This example makes very few modifications to `app.layout`.\n", "\n", "23. We can start to customize a `dash` app by using an external style sheet.\n", "\n", "24. Similar to how we use CSS in combination with HTML, external style sheets can also be loaded and applied in `dash`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# load style sheet; this example uses URL; could also use local .css file\n", "external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']\n", "\n", "# call style sheet when starting app\n", "app = dash.Dash(APP_NAME, external_stylesheets=external_stylesheets)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "25. We can also start to modify components of the application by declaring HTML tags.\n", "\n", "26. Remember in HTML, tags like `

`, `

`, etc. are used for styling and formatting.\n", "\n", "27. The `dash_html_components` library has a component for every HTML tag.\n", "\n", "28. We can create declarations for those elements to govern how they are formatted or styled in the `dash` application.\n", "\n", "29. This is similar to how we create declarations in an external style sheet.\n", "\n", "30. Let's modify our app layout to include a `H1` title, a `div` subtitle, and a `Graph` object." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# omitted code creates and customizes figure\n", "\n", "# import dash components\n", "import dash\n", "import dash_core_components as dcc\n", "import dash_html_components as html\n", "\n", "# load style sheet; this example uses URL; could also use local .css file\n", "external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']\n", "\n", "# call style sheet when starting app\n", "app = dash.Dash(Test_App, external_stylesheets=external_stylesheets)\n", "\n", "# set app layout\n", "app.layout = html.Div(children=[\n", " html.H1(children='Hello Dash'),\n", "\n", " html.Div(children='''\n", " Dash: A web application framework for Python.\n", " '''),\n", "\n", " dcc.Graph(\n", " id='example-graph',\n", " figure=fig\n", " )\n", "])\n", "\n", "# run app\n", "app.run_server(debug=True, use_reloader=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "32. We see the component declarations nested under `app.layout`.\n", "\n", "33. `dash` generates an HTML element for each of these components.\n", "\n", "34. For example, `dash` takes `html.H1(children='Hello Dash')` and generates `

Hello Dash

`.\n", "\n", "35. `dash` can also take keyword arguments as part of these component declarations.\n", "\n", "36. Let's say we want to override the external style sheet or set formatting for an element not convered in the style sheet." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash components\n", "import dash\n", "import dash_core_components as dcc\n", "import dash_html_components as html\n", "\n", "# load style sheet; this example uses URL; could also use local .css file\n", "external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']\n", "\n", "# call style sheet when starting app\n", "app = dash.Dash(Test_App, external_stylesheets=external_stylesheets)\n", "\n", "# color declaration \n", "colors = {'background': '#111111', 'text': '#7FDBFF'}\n", "\n", "# omitted code creates figure\n", "\n", "# update figure layout using colors dictionary keys\n", "fig.update_layout(plot_bgcolor=colors['background'], paper_bgcolor=colors['background'], font_color=colors['text'])\n", "\n", "# set app layout\n", "app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[\n", " html.H1(\n", " children='Hello Dash',\n", " style={\n", " 'textAlign': 'center',\n", " 'color': colors['text']\n", " }\n", " ),\n", "\n", " html.Div(children='Dash: A web application framework for Python.', style={\n", " 'textAlign': 'center',\n", " 'color': colors['text']\n", " }),\n", "\n", " dcc.Graph(\n", " id='example-graph-2',\n", " figure=fig\n", " )\n", "])\n", "\n", "# run app\n", "if Test_App == '__main__':\n", " app.run_server(debug=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "37. We create the `colors` dictionary with `background` and `text` keys and color values.\n", "\n", "38. We apply those custom colors to the figure using `fig.update_layout`.\n", "\n", "39. We apply those custom colors as keyword arguments for the `app.layout` components.\n", "\n", "40. For more on the `dash-html-components` library: [`plotly`, Dash HTML Components](https://dash.plotly.com/dash-html-components)\n", "\n", "41. For more on the `dash` layout options: [`plotly`, Dash Layout](https://dash.plotly.com/layout)\n", "\n", "## Customizing `dash` Layout Using `dash_core_components`\n", "\n", "42. Where `dash` really shines (and has functionality that compares with RStudio Shiny) is in the higher-level core components.\n", "\n", "43. These core components include things like:\n", "- Dropdown input menu\n", "- Slider\n", "- Range slider\n", "- Input box\n", "- Input text area\n", "- Checkboxes\n", "- Radio buttons\n", "- Buttons\n", "- Single date picker\n", "- Date range picker\n", "- File upload\n", "- Multi-tab disply\n", "\n", "44. These core components are generated through a combination of JavaScript, HTML, and CSS in combination with the React.js library.\n", "\n", "45. The syntax for `dash-core-components` is similar to the HTML element declarations in the previous sections.\n", "\n", "46. A few examples are provided below.\n", "\n", "### Dropdown" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash core components\n", "import dash_core_components as dcc\n", "\n", "# sample code for a dropdown menu\n", "dcc.Dropdown(\n", " options=[\n", " {'label': 'New York City', 'value': 'NYC'},\n", " {'label': 'Montréal', 'value': 'MTL'},\n", " {'label': 'San Francisco', 'value': 'SF'}\n", " ],\n", " value='MTL'\n", ")\n", "\n", "# this example takes a list of dictionaries as the label and value pairs for the dropdown; value sets the default dropdown valu\n", "\n", "# sample code for multi-select dropdown\n", "dcc.Dropdown(\n", " options=[\n", " {'label': 'New York City', 'value': 'NYC'},\n", " {'label': 'Montréal', 'value': 'MTL'},\n", " {'label': 'San Francisco', 'value': 'SF'}\n", " ],\n", " multi=True,\n", " value=\"MTL\"\n", ") \n", "\n", "# setting multi to True allows for multi-select\n", "\n", "# for more on dropdown components: https://dash.plotly.com/dash-core-components/dropdown" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slider" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash core components\n", "import dash_core_components as dcc\n", "\n", "# sample code for a slider\n", "dcc.Slider(\n", " min=-5,\n", " max=10,\n", " step=0.5,\n", " value=-3\n", ") \n", "\n", "# this example sets the min and max value for the slider, as well as the step increments and default value\n", "\n", "# another example that includes slider labels\n", "dcc.Slider(\n", " min=0,\n", " max=9,\n", " marks={i: 'Label {}'.format(i) for i in range(10)},\n", " value=5,\n", ")\n", "\n", "# this example sets marks for each slider value\n", "\n", "# for more on slider components: https://dash.plotly.com/dash-core-components/slider" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### RangeSlider" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash core components\n", "import dash_core_components as dcc\n", "\n", "# sample code for a range slider\n", "dcc.RangeSlider(\n", " count=1,\n", " min=-5,\n", " max=10,\n", " step=0.5,\n", " value=[-3, 7]\n", ") \n", "\n", "# example specifies min and max values, default positions, and step increment\n", "\n", "# another range slider example with labels\n", "dcc.RangeSlider(\n", " marks={i: 'Label {}'.format(i) for i in range(-5, 7)},\n", " min=-5,\n", " max=6,\n", " value=[-3, 4]\n", ")\n", "\n", "# again marks is used to set the mark position and label text\n", "\n", "# for more on range sliders: https://dash.plotly.com/dash-core-components/rangeslider" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Input" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash core components\n", "import dash_core_components as dcc\n", "\n", "# sample code for an input box\n", "dcc.Input(\n", " placeholder='Enter a value...',\n", " type='text',\n", " value=''\n", ") \n", "\n", "# placeholder sets the placeholder text; type sets the input type; value sets the default value\n", "\n", "# for more on input: https://dash.plotly.com/dash-core-components/input" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### TextArea" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash core components\n", "import dash_core_components as dcc\n", "\n", "# sample code for a text area box\n", "dcc.Textarea(\n", " placeholder='Enter a value...',\n", " value='This is a TextArea component',\n", " style={'width': '100%'}\n", ")\n", "\n", "# placeholder sets the placeholder value, value sets the default value, and style sets the box width\n", "\n", "# for more on Textarea: https://dash.plotly.com/dash-core-components/textarea " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Checkboxes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash core components\n", "import dash_core_components as dcc\n", "\n", "# sample code for vertical list of checkboxes (default includes multi-select)\n", "dcc.Checklist(\n", " options=[\n", " {'label': 'New York City', 'value': 'NYC'},\n", " {'label': 'Montréal', 'value': 'MTL'},\n", " {'label': 'San Francisco', 'value': 'SF'}\n", " ],\n", " value=['MTL', 'SF']\n", ") \n", "\n", "# options set the label and value for each check box, and value sets the default values\n", "\n", "# another example with a horizontal or inline list of checkboxes\n", "dcc.Checklist(\n", " options=[\n", " {'label': 'New York City', 'value': 'NYC'},\n", " {'label': 'Montréal', 'value': 'MTL'},\n", " {'label': 'San Francisco', 'value': 'SF'}\n", " ],\n", " value=['MTL', 'SF'],\n", " labelStyle={'display': 'inline-block'}\n", ")\n", "\n", "# modifying labelStyle changes the layout\n", "\n", "# for more on Checklist: https://dash.plotly.com/dash-core-components/checklist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Other Core Component Types\n", "\n", "47. You're starting to get the picture.\n", "\n", "48. For more examples and documentation:\n", "- [`dcc.RadioItems()`](https://dash.plotly.com/dash-core-components/radioitems)\n", "- [`html.Button()`](https://dash.plotly.com/dash-html-components/button)\n", "- [`dcc.DatePickerSingle()`](https://dash.plotly.com/dash-core-components/datepickersingle)\n", "- [`dcc.DatePickerRange()`](https://dash.plotly.com/dash-core-components/datepickerrange)\n", "- [`dcc.Upload()`](https://dash.plotly.com/dash-core-components/upload)\n", "- [`dcc.Tabs()`](https://dash.plotly.com/dash-core-components/tabs)\n", "- [`dcc.Graph()`](https://dash.plotly.com/dash-core-components/graph)\n", "\n", "\n", "49. For more on the `dash_core_components` library: [`plotly`, Dash Core Components](https://dash.plotly.com/dash-core-components)\n", "\n", "50. For more on the `dash_html_components` library: [`plotly`, Dash HTML Components](https://dash.plotly.com/dash-html-components)\n", "\n", "## Setting Up Callbacks\n", "\n", "51. At this point, these layout components are interactive in the sense that you can interact with them.\n", "\n", "52. But the components are not response, in the sense that interacting with them does not change the app's behavior.\n", "\n", "53. We need to make the layout components responsive and interactive.\n", "\n", "54. We can do this in `dash` using callback functions.\n", "\n", "55. In `dash` syntax, callback functions are Python functions called by `dash` whenever an input component's property changes.\n", "\n", "56. An example that uses a responsive input box." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash components\n", "import dash\n", "import dash_core_components as dcc\n", "import dash_html_components as html\n", "from dash.dependencies import Input, Output\n", "\n", "# set external style sheet\n", "external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']\n", "\n", "# initialize app\n", "app = dash.Dash(__name__, external_stylesheets=external_stylesheets)\n", "\n", "# configure app layout\n", "app.layout = html.Div([\n", " html.H6(\"Change the value in the text box to see callbacks in action!\"),\n", " html.Div([\"Input: \",\n", " dcc.Input(id='my-input', value='initial value', type='text')]),\n", " html.Br(),\n", " html.Div(id='my-output'),\n", "\n", "])\n", "\n", "# decorator that tells dash to call named function when input value changes so output components reflect that change\n", "@app.callback(\n", " Output(component_id='my-output', component_property='children'),\n", " Input(component_id='my-input', component_property='value')\n", ")\n", "\n", "# name output function\n", "def update_output_div(input_value):\n", " return 'Output: {}'.format(input_value)\n", "\n", "\n", "# initialize app\n", "if __name__ == '__main__':\n", " app.run_server(debug=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "57. Let's walk through what happens in this example.\n", "\n", "58. The application inputs and outputs are described using the `@app.callback` decorator, similar to the layout and component declarations covered previously.\n", "\n", "59. The decorator instructs `dash` to call this function whenever the input value changes, so the output components are updated accordingly.\n", "\n", "60. What you name the function arguments is up to you, as long as the names in the function definition match the names in the callback.\n", "\n", "61. The `@app.callback` decorator references components described in `app.layout`.\n", "\n", "62. Thus the component names in `@app.callback` need to reflect the component names used with `app.layout`.\n", "\n", "63. In this example, those component names are `my-input` and `my-output`.\n", "\n", "64. We see those names set using the `id` parameter with `app.layout`, and reflected in the callback.\n", "\n", "65. The `@app.callback` decorator should always come immediately before the `def` function definition.\n", "\n", "66. For more on function decorators in Python: [`python`, PEP 318 -- Decorators for Functions and Methods](https://www.python.org/dev/peps/pep-0318/)\n", "\n", "67. In `dash` syntax, application inputs and outputs are treated as component properties. \n", "\n", "68. In this example, the `my-input` component is set to take the input as its `value`, and `my-output` is set to reflect the `my-input` value.\n", "\n", "69. Whenever an input property changes (in this example characters in the input box change), the callback function is automatically called.\n", "\n", "70. `dash` provides the function with the new input value and updates the output component property.\n", "\n", "71. Note that we had to import `from dash.dependencies import Input, Output`, which is different than `dash_core_components.Input`.\n", "\n", "72. Taken together, this functionality is called ***reactive programming***.\n", "\n", "73. The keyword arguments used to describe each component become incredibly important when setting up callback functions.\n", "\n", "74. Let's look at another application that uses callbacks.\n", "\n", "75. In this example, global population data is plotted as a bubble chart.\n", "\n", "76. Points are colored by continent, sized by population, and a slider is used to mark each year of available data." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import dash components and plotly\n", "import dash\n", "import dash_core_components as dcc\n", "import dash_html_components as html\n", "from dash.dependencies import Input, Output\n", "import plotly.express as px\n", "\n", "# import pandas\n", "import pandas as pd\n", "\n", "# load dataframe\n", "df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')\n", "\n", "# load external stylesheet\n", "external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']\n", "\n", "# initialize app\n", "app = dash.Dash(__name__, external_stylesheets=external_stylesheets)\n", "\n", "# set app layout with graph and slider components\n", "app.layout = html.Div([\n", " dcc.Graph(id='graph-with-slider'),\n", " dcc.Slider(\n", " id='year-slider',\n", " min=df['year'].min(),\n", " max=df['year'].max(),\n", " value=df['year'].min(),\n", " marks={str(year): str(year) for year in df['year'].unique()},\n", " step=None\n", " )\n", "])\n", "\n", "\n", "# set callback for slider and graph; note the slider is the input and the graph is the output\n", "@app.callback(\n", " Output('graph-with-slider', 'figure'),\n", " Input('year-slider', 'value'))\n", "\n", "# function definition for slider\n", "def update_figure(selected_year):\n", " filtered_df = df[df.year == selected_year]\n", "\n", " fig = px.scatter(filtered_df, x=\"gdpPercap\", y=\"lifeExp\",\n", " size=\"pop\", color=\"continent\", hover_name=\"country\",\n", " log_x=True, size_max=55)\n", "\n", " fig.update_layout(transition_duration=500)\n", "\n", " return fig\n", "\n", "\n", "# launch application\n", "if __name__ == '__main__':\n", " app.run_server(debug=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "77. This example loads as `pandas` dataframe using `pd.read_csv()`.\n", "\n", "78. Loading the data outside of the callback functions means that the data loading operation is only done once, rather than each time the function is called.\n", "\n", "79. The callback does not modify the original data--it works with `pandas` filters to to create copies of the `dataframe`.\n", "\n", "80. NOTE: callback functions should NEVER alter the underlying `dataframe`.\n", "\n", "81. We also set the layout transition time using `fig.update_layout()` in combination with `transition_duration`. \n", "\n", "82. This parameter gives the resulting figure smooth transitions between slider year values.\n", "\n", "83. For more on `dash` callbacks:\n", "- [`plotly`, Basic Dash Callbacks](https://dash.plotly.com/basic-callbacks)\n", "- [`plotly`, Advanced Callbacks](https://dash.plotly.com/advanced-callbacks)\n", "\n", "## Additional resources\n", "\n", "84. We're just scratching the surface of what you can do using `dash`.\n", "\n", "85. Callback functions can include multiple inputs and outputs, as well as chained callback functions.\n", "- [`plotly`, Basic Callbacks](https://dash.plotly.com/basic-callbacks)\n", "\n", "86. `dash` also allows for interactive visualizations that change based on how the user is interacting with the visualization.\n", "- [`plotly`, Interactive Visualizations](https://dash.plotly.com/interactive-graphing)\n", "\n", "87. To learn more, consult the [Dash User Guide](https://dash.plotly.com/).\n", "\n", "88. The [Dash Enterprise App Gallery](https://dash-gallery.plotly.host/Portal/) includes sample apps with the back-end `dash` code.\n", "\n", "89. See also: Daniel Barker, [\"A short Python tutorial using the open-source Plotly \"Dash\" library\"](https://towardsdatascience.com/a-short-python-tutorial-using-the-open-source-plotly-dash-library-part-i-e59fb1f1a457) *Towards Data Science* (24 April 2018).\n", "\n", "## Publishing a `dash` App\n", "\n", "90. In these examples, we are still working in your local environment.\n", "\n", "91. The `dash` app may run in a web browser, but it uses your computer as a local host (`localhost`).\n", "\n", "92. For a `dash` app to be available via the World Wide Web, you need to deploy it to a server.\n", "\n", "93. A few free server options that support public Flask applications (the framework `dash` is built on) include Heroku and Reclaim Hosting.\n", " - *ND Students: Alternatively you could take Prof. Walden's \"Minimal Computing\" class and build your own LAMP stack server.*\n", "\n", "94. More information on deplying a `dash` app using Heroku (free): [`plotly`, Heroku for Sharing Public Dash apps for Free](https://dash.plotly.com/deployment).\n", "\n", "95. See also: Elsa Scola, [\"The Easiest Way to Deploy Your Dash App for Free\"](https://towardsdatascience.com/the-easiest-way-to-deploy-your-dash-app-for-free-f92c575bb69e) *Towards Data Science* (2 May 2020).\n", "\n", "96. Another option for acquiring a domain and web hosting is Reclaim Hosting.\n", "\n", "97. \"Founded in 2013, Reclaim Hosting provides educators and institutions with an easy way to offer their students domains and web hosting that they own and control. Our goal is to make the process of offering a flexible web space and domain name to your students as easy as possible and giving you the support you need to make it all happen\" ([About Reclaim Hosting](https://reclaimhosting.com/about/)).\n", "\n", "98. At the time this tutorial was written (December 2020), [Reclaim Hosting's personal plan](https://reclaimhosting.com/shared-hosting/) is $30 annually and includes 2 GB of storage.\n", "\n", "99. For more information in deploying a Flask app using Reclaim Hosting (or another cPanel provider):\n", "- [`python`, Flask: Deploy an App](https://python-adv-web-apps.readthedocs.io/en/latest/flask_deploy.html)\n", "- Tony Hirst, [\"Creating a Simple Python Flash App via cPanel on Reclaim Hosting\"](https://blog.ouseful.info/2016/09/17/creating-a-simple-python-flask-app-running-on-reclaim-hosting/) *OUseful.Info* (17 September 2016)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }