{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "#### New to Plotly?\n", "Plotly's Python library is free and open source! [Get started](https://plotly.com/python/getting-started/) by downloading the client and [reading the primer](https://plotly.com/python/getting-started/).\n", "
You can set up Plotly to work in [online](https://plotly.com/python/getting-started/#initialization-for-online-plotting) or [offline](https://plotly.com/python/getting-started/#initialization-for-offline-plotting) mode, or in [jupyter notebooks](https://plotly.com/python/getting-started/#start-plotting-online).\n", "
We also have a quick-reference [cheatsheet](https://images.plot.ly/plotly-documentation/images/python_cheat_sheet.pdf) (new!) to help you get started!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Version Check\n", "Note: Animations are available in version 1.12.10+\n", "Run `pip install plotly --upgrade` to update your Plotly version." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'2.0.15'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import plotly\n", "plotly.__version__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Import Data\n", "This tutorial walks you through how to make an example using the [Gapminder dataset](http://www.gapminder.org/world/) to present the GDP per Capita vs Life Expectancy across the years 1952 to 2007 in an animated Bubble Chart, in which the bubbles represent countries and their sizes represent the population.\n", "\n", "First import the Gapminder data that we will be using for the example and store in a dataframe:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import plotly.plotly as py\n", "import plotly.figure_factory as ff \n", "from plotly.grid_objs import Grid, Column\n", "\n", "import pandas as pd\n", "import time\n", "\n", "url = 'https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv'\n", "dataset = pd.read_csv(url)\n", "\n", "table = ff.create_table(dataset.head(10))\n", "py.iplot(table, filename='animations-gapminder-data-preview')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Make the Grid\n", "Since we are using the v2 api for animations in Plotly, we need to first make a `grid`. You can learn more in the [introduction to animation doc](https://plotly.com/python/animations/).\n", "\n", "We will first define a list of _string_ years which will represent the values that our `slider` will take on. Going through the dataset, we will take out all the unique continents from the column `continent` and store them as well. Finally, we make a grid with each column representing a slice of the dataframe by _year_, _continent_ and _column name_, making sure to name each column uniquly by these variables: " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "u'https://plotly.com/~chelsea_lyn/16226/'" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "years_from_col = set(dataset['year'])\n", "years_ints = sorted(list(years_from_col))\n", "years = [str(year) for year in years_ints]\n", "years.remove('1957')\n", "\n", "# make list of continents\n", "continents = []\n", "for continent in dataset['continent']:\n", " if continent not in continents: \n", " continents.append(continent)\n", "\n", "columns = []\n", "# make grid\n", "for year in years:\n", " for continent in continents:\n", " dataset_by_year = dataset[dataset['year'] == int(year)]\n", " dataset_by_year_and_cont = dataset_by_year[dataset_by_year['continent'] == continent]\n", " for col_name in dataset_by_year_and_cont:\n", " # each column name is unique\n", " column_name = '{year}_{continent}_{header}_gapminder_grid'.format(\n", " year=year, continent=continent, header=col_name\n", " )\n", " a_column = Column(list(dataset_by_year_and_cont[col_name]), column_name)\n", " columns.append(a_column)\n", "\n", "# upload grid\n", "grid = Grid(columns)\n", "url = py.grid_ops.upload(grid, 'gapminder_grid'+str(time.time()), auto_open=False)\n", "url" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Make the Figure" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "figure = {\n", " 'data': [],\n", " 'layout': {},\n", " 'frames': [],\n", " 'config': {'scrollzoom': True}\n", "}\n", "\n", "# fill in most of layout\n", "figure['layout']['xaxis'] = {'range': [30, 85], 'title': 'Life Expectancy', 'gridcolor': '#FFFFFF'}\n", "figure['layout']['yaxis'] = {'title': 'GDP per Capita', 'type': 'log', 'gridcolor': '#FFFFFF'}\n", "figure['layout']['hovermode'] = 'closest'\n", "figure['layout']['plot_bgcolor'] = 'rgb(223, 232, 243)'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Add Slider\n", "For the slider to appear, we need to adda `sliders` dictionary to `layout`. The `sliders` dictionary is set in the following way:\n", "\n", "```\n", "figure['layout']['sliders] = {\n", " 'active': 0,\n", " 'yanchor': 'top',\n", " 'xanchor': 'left',\n", " 'currentvalue': {\n", " 'font': {'size': 20},\n", " 'prefix': 'text-before-value-on-display',\n", " 'visible': True,\n", " 'xanchor': 'right'\n", " },\n", " 'transition': {'duration': 300, 'easing': 'cubic-in-out'},\n", " 'pad': {'b': 10, 't': 50},\n", " 'len': 0.9,\n", " 'x': 0.1,\n", " 'y': 0,\n", " 'steps': [...]\n", "}\n", "```\n", "\n", "- `yanchor` determines whether the slider is on the _top_ or _bottom_ of the chart page\n", "- `xanchor` is similar, only with _left_ and _right_ as possible values\n", "- `currentvalue` sets the display of the current value that the slider is hovering on. It contains args such as `prefix`, which sets the text that appears before the value.\n", "- `steps` is a list of dictionaries each of which corresponds to a frame in the figure. They should be ordered in the sequence in which the frames occur in the animation.\n", "\n", "Each dictionary in `steps` has the following form:\n", "\n", "```\n", "{\n", " 'method': 'animate',\n", " 'label': 'label-for-frame',\n", " 'value': 'value-for-frame(defaults to label)',\n", " 'args': [{'frame': {'duration': 300, 'redraw': False},\n", " 'mode': 'immediate'}\n", " ],\n", "}\n", "```\n", "- the first item in the list `args` is a list containing the slider-value of that frame\n", "- `label` is the text that appears next to the `prefix` arg mentioned in the `slider` section (eg. _Year: 1952_)\n", "\n", "For more information, check out the [documentation](https://plotly.com/python/reference/#layout-sliders)." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "sliders_dict = {\n", " 'active': 0,\n", " 'yanchor': 'top',\n", " 'xanchor': 'left',\n", " 'currentvalue': {\n", " 'font': {'size': 20},\n", " 'prefix': 'Year:',\n", " 'visible': True,\n", " 'xanchor': 'right'\n", " },\n", " 'transition': {'duration': 300, 'easing': 'cubic-in-out'},\n", " 'pad': {'b': 10, 't': 50},\n", " 'len': 0.9,\n", " 'x': 0.1,\n", " 'y': 0,\n", " 'steps': []\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Add Play and Pause Buttons" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "figure['layout']['updatemenus'] = [\n", " {\n", " 'buttons': [\n", " {\n", " 'args': [None, {'frame': {'duration': 500, 'redraw': False},\n", " 'fromcurrent': True, 'transition': {'duration': 300, 'easing': 'quadratic-in-out'}}],\n", " 'label': 'Play',\n", " 'method': 'animate'\n", " },\n", " {\n", " 'args': [[None], {'frame': {'duration': 0, 'redraw': False}, 'mode': 'immediate',\n", " 'transition': {'duration': 0}}],\n", " 'label': 'Pause',\n", " 'method': 'animate'\n", " }\n", " ],\n", " 'direction': 'left',\n", " 'pad': {'r': 10, 't': 87},\n", " 'showactive': False,\n", " 'type': 'buttons',\n", " 'x': 0.1,\n", " 'xanchor': 'right',\n", " 'y': 0,\n", " 'yanchor': 'top'\n", " }\n", "]\n", "\n", "custom_colors = {\n", " 'Asia': 'rgb(171, 99, 250)',\n", " 'Europe': 'rgb(230, 99, 250)',\n", " 'Africa': 'rgb(99, 110, 250)',\n", " 'Americas': 'rgb(25, 211, 243)',\n", " 'Oceania': 'rgb(50, 170, 255)'\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Fill in Figure with Data and Frames\n", "Now we can put the data from our grid into the figure. Since we are using referenced data from the grid, we use the `.get_column_reference()` method on the grid and supply the name of the column we want via a looping through all the years and continents. First we \n", "\n", "Note: If you are using referenced data for a particular parameter, you `MUST` change the parameter name from `name` to `namesrc` to indicate that you are using referenced data from a grid. For instance, `x` becomes `xsrc`, `text` becomes `textsrc`, etc." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "col_name_template = '{year}_{continent}_{header}_gapminder_grid'\n", "year = 1952\n", "for continent in continents:\n", " data_dict = {\n", " 'xsrc': grid.get_column_reference(col_name_template.format(\n", " year=year, continent=continent, header='lifeExp'\n", " )),\n", " 'ysrc': grid.get_column_reference(col_name_template.format(\n", " year=year, continent=continent, header='gdpPercap'\n", " )),\n", " 'mode': 'markers',\n", " 'textsrc': grid.get_column_reference(col_name_template.format(\n", " year=year, continent=continent, header='country'\n", " )),\n", " 'marker': {\n", " 'sizemode': 'area',\n", " 'sizeref': 200000,\n", " 'sizesrc': grid.get_column_reference(col_name_template.format(\n", " year=year, continent=continent, header='pop'\n", " )),\n", " 'color': custom_colors[continent]\n", " },\n", " 'name': continent\n", " }\n", " figure['data'].append(data_dict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Create Frames\n", "Finally we make our `frames`. Here we are running again through the years and continents, but for each combination we instantiate a frame dictionary of the form:\n", "\n", "```\n", "frame = {'data': [], 'name': value-name}\n", "```\n", "We add a dictionary of data to this list and at the end of each loop, we ensure to add the `steps` dictionary to the steps list. At the end, we attatch the `sliders` dictionary to the figure via:\n", "\n", "```\n", "figure['layout']['sliders'] = [sliders_dict]\n", "```\n", "\n", "and then we plot! Enjoy the Gapminder example!" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "for year in years:\n", " frame = {'data': [], 'name': str(year)}\n", " for continent in continents:\n", " data_dict = {\n", " 'xsrc': grid.get_column_reference(col_name_template.format(\n", " year=year, continent=continent, header='lifeExp'\n", " )),\n", " 'ysrc': grid.get_column_reference(col_name_template.format(\n", " year=year, continent=continent, header='gdpPercap'\n", " )),\n", " 'mode': 'markers',\n", " 'textsrc': grid.get_column_reference(col_name_template.format(\n", " year=year, continent=continent, header='country'\n", " )),\n", " 'marker': {\n", " 'sizemode': 'area',\n", " 'sizeref': 200000,\n", " 'sizesrc': grid.get_column_reference(col_name_template.format(\n", " year=year, continent=continent, header='pop'\n", " )),\n", " 'color': custom_colors[continent]\n", " },\n", " 'name': continent\n", " }\n", " frame['data'].append(data_dict)\n", "\n", " figure['frames'].append(frame)\n", " slider_step = {'args': [\n", " [year],\n", " {'frame': {'duration': 300, 'redraw': False},\n", " 'mode': 'immediate',\n", " 'transition': {'duration': 300}}\n", " ],\n", " 'label': year,\n", " 'method': 'animate'}\n", " sliders_dict['steps'].append(slider_step)\n", "\n", "figure['layout']['sliders'] = [sliders_dict]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plot Animation" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "py.icreate_animations(figure, 'gapminder_example'+str(time.time()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Reference\n", "For additional information and attributes for creating bubble charts in Plotly see: https://plotly.com/python/bubble-charts/.\n", "For more documentation on creating animations with Plotly, see https://plotly.com/python/#animations." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting git+https://github.com/plotly/publisher.git\n", " Cloning https://github.com/plotly/publisher.git to /private/var/folders/k_/zf24qrfn2kg710j9pdrxzrz40000gn/T/pip-zIDP9d-build\n", "Installing collected packages: publisher\n", " Found existing installation: publisher 0.10\n", " Uninstalling publisher-0.10:\n", " Successfully uninstalled publisher-0.10\n", " Running setup.py install for publisher ... \u001b[?25ldone\n", "\u001b[?25hSuccessfully installed publisher-0.10\n" ] } ], "source": [ "from IPython.display import display, HTML\n", "\n", "display(HTML(''))\n", "display(HTML(''))\n", "\n", "!pip install git+https://github.com/plotly/publisher.git --upgrade\n", "import publisher\n", "publisher.publish(\n", " 'gapminder-example.ipynb', 'python/gapminder-example/', 'Adding Sliders to Animations | plotly',\n", " 'How to make the classic Gapminder Animation using sliders and buttons in Python.',\n", " title='Adding Sliders to Animations | plotly',\n", " name='Adding Sliders to Animations',\n", " language='python',\n", " page_type='example_index', has_thumbnail='true', thumbnail='thumbnail/gapminder_animation.gif',\n", " display_as='animations', ipynb= '~notebook_demo/129', order=2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.10" } }, "nbformat": 4, "nbformat_minor": 1 }