├── .gitignore ├── README.md ├── LICENSE ├── 01_level0_seaborn.ipynb ├── 03_level1_pivot.ipynb ├── 05_level2_seaborn.ipynb ├── 02_level1_plotly.ipynb ├── requirements.txt ├── 06_level3_holoviews.ipynb ├── 07_level3_altair.ipynb ├── 04_level2_plotly.ipynb └── 08_level3_plotly.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | *html 3 | Untitled* 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Why *Interactive* Data Visualization Matters for Data Science in Python 2 | ### a [talk at PyData Global 2021](https://pydata.org/global2021/schedule/presentation/118/why-interactive-data-visualization-matters-for-data-science-in-python/) by [Nicolas Kruchten](https://nicolas.kruchten.com/) 3 | 4 | [Google Presentation link](https://docs.google.com/presentation/d/e/2PACX-1vRkGX1fmO9gVWCrOa4YEEPMMPlOj6xJeJDTCD8ADVJ3ZaOS8-pAOSi0Tha7eTDAy2QcQQpVJ_XkK5F1/pub?start=false&loop=false&delayms=3000) 5 | 6 | Everything in this repo that is not already covered by some other license by virtue of being copied from some other library's documentation (see attribution links) is made available under an [MIT License](https://github.com/nicolaskruchten/pydata_global_2021/blob/main/LICENSE). 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Nicolas Kruchten 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /01_level0_seaborn.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "2ef0ead9-dd7b-4e86-962e-8ba5b6b8c17a", 6 | "metadata": {}, 7 | "source": [ 8 | "From https://seaborn.pydata.org/generated/seaborn.scatterplot.html and https://seaborn.pydata.org/generated/seaborn.lmplot.html" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "c9ec77e3-3246-4895-a74b-800deeab2ec5", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import seaborn as sns\n", 19 | "%config InlineBackend.figure_format = 'retina'\n", 20 | "sns.set(rc={'figure.figsize':(11.7,8.27)})\n", 21 | "\n", 22 | "tips = sns.load_dataset(\"tips\")\n" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "id": "79103571-6829-46fa-8a68-c1e2b3d74355", 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "sns.scatterplot(data=tips, x=\"total_bill\", y=\"tip\")" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "id": "e2cdd75c-35ef-4157-b392-3e800f66506c", 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [] 42 | } 43 | ], 44 | "metadata": { 45 | "kernelspec": { 46 | "display_name": "Python 3 (ipykernel)", 47 | "language": "python", 48 | "name": "python3" 49 | }, 50 | "language_info": { 51 | "codemirror_mode": { 52 | "name": "ipython", 53 | "version": 3 54 | }, 55 | "file_extension": ".py", 56 | "mimetype": "text/x-python", 57 | "name": "python", 58 | "nbconvert_exporter": "python", 59 | "pygments_lexer": "ipython3", 60 | "version": "3.9.7" 61 | } 62 | }, 63 | "nbformat": 4, 64 | "nbformat_minor": 5 65 | } 66 | -------------------------------------------------------------------------------- /03_level1_pivot.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "7f172270-ee41-4c21-9339-1a4685db6b5b", 6 | "metadata": {}, 7 | "source": [ 8 | "From https://github.com/nicolaskruchten/jupyter_pivottablejs" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "1e0b14b2-ae91-47b4-9d56-eab23b0871ab", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "from plotly.data import tips\n", 19 | "from pivottablejs import pivot_ui\n", 20 | "\n", 21 | "df = tips()\n", 22 | "pivot_ui(df)" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "id": "06fe8205-d08f-43bd-81f7-bba8cf1a04f8", 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "pivot_ui(df, cols=[\"day\", \"time\"], rows=[\"sex\", \"smoker\"], rendererName=\"Heatmap\",\n", 33 | " aggregatorName=\"Sum over Sum\", vals=[\"tip\", \"total_bill\"],\n", 34 | " outfile_path=\"preloaded.html\")" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "id": "4593fd10-a4f5-4f3c-b7be-07d1abb03740", 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [] 44 | } 45 | ], 46 | "metadata": { 47 | "kernelspec": { 48 | "display_name": "Python 3 (ipykernel)", 49 | "language": "python", 50 | "name": "python3" 51 | }, 52 | "language_info": { 53 | "codemirror_mode": { 54 | "name": "ipython", 55 | "version": 3 56 | }, 57 | "file_extension": ".py", 58 | "mimetype": "text/x-python", 59 | "name": "python", 60 | "nbconvert_exporter": "python", 61 | "pygments_lexer": "ipython3", 62 | "version": "3.9.7" 63 | } 64 | }, 65 | "nbformat": 4, 66 | "nbformat_minor": 5 67 | } 68 | -------------------------------------------------------------------------------- /05_level2_seaborn.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "eeef6f0b-7e42-4193-9b89-721fd3f06ac5", 6 | "metadata": {}, 7 | "source": [ 8 | "From https://towardsdatascience.com/tooltips-with-pythons-matplotlib-dcd8db758846" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "233af177-7175-4e2c-a486-f3aebf7940fe", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "%matplotlib widget" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "id": "635c8457-cba9-4e20-b225-aa9e9d7afb1a", 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "import matplotlib.pyplot as plt\n", 29 | "import mplcursors\n", 30 | "import seaborn as sns\n", 31 | "tips = sns.load_dataset(\"tips\")\n", 32 | "\n", 33 | "fig, ax = plt.subplots()\n", 34 | "sns.scatterplot(data=tips, x=\"total_bill\", y=\"tip\", hue=\"smoker\")\n", 35 | "\n", 36 | "@mplcursors.cursor(ax, hover=True).connect(\"add\")\n", 37 | "def on_add(sel):\n", 38 | " sel.annotation.set(text=tips.sex[sel.target.index])\n", 39 | " \n", 40 | "plt.show()" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "id": "b101c777-00ea-41f5-a76c-ff69973cd276", 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [] 50 | } 51 | ], 52 | "metadata": { 53 | "kernelspec": { 54 | "display_name": "Python 3 (ipykernel)", 55 | "language": "python", 56 | "name": "python3" 57 | }, 58 | "language_info": { 59 | "codemirror_mode": { 60 | "name": "ipython", 61 | "version": 3 62 | }, 63 | "file_extension": ".py", 64 | "mimetype": "text/x-python", 65 | "name": "python", 66 | "nbconvert_exporter": "python", 67 | "pygments_lexer": "ipython3", 68 | "version": "3.9.7" 69 | } 70 | }, 71 | "nbformat": 4, 72 | "nbformat_minor": 5 73 | } 74 | -------------------------------------------------------------------------------- /02_level1_plotly.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "818c2266-f931-4337-9b39-56753e339283", 6 | "metadata": {}, 7 | "source": [ 8 | "From https://ipywidgets.readthedocs.io/en/latest/examples/Using%20Interact.html" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "4cf734f0-5f87-40f3-959c-3719750de2d3", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import plotly.express as px\n", 19 | "\n", 20 | "df = px.data.stocks(datetimes=True, indexed=True)" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "id": "2e0368dc-7faa-4bc2-a782-77aafcb0efbb", 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "px.scatter(df, trendline=\"rolling\", trendline_options=dict(window=5), height=600)" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "id": "062524c1-778e-493f-bbcf-e12ceb396f0e", 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "from ipywidgets import interact\n", 41 | "\n", 42 | "@interact\n", 43 | "def make_fig(window=5):\n", 44 | " return px.scatter(df, trendline=\"rolling\", trendline_options=dict(window=window), height=600)" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "id": "60eec1b6-dbd4-4709-94a9-99f2cf6bbca2", 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "from ipywidgets import interact\n", 55 | "\n", 56 | "df2 = px.data.tips()\n", 57 | "\n", 58 | "@interact\n", 59 | "def make_fig(x=df2.columns, y=df2.columns, c=df2.columns):\n", 60 | " return px.scatter(df2, x=x, y=y, color=c, height=600)" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "id": "38e9f504-cfe2-4d05-8d9d-f5ed092a4ddb", 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [] 70 | } 71 | ], 72 | "metadata": { 73 | "kernelspec": { 74 | "display_name": "Python 3 (ipykernel)", 75 | "language": "python", 76 | "name": "python3" 77 | }, 78 | "language_info": { 79 | "codemirror_mode": { 80 | "name": "ipython", 81 | "version": 3 82 | }, 83 | "file_extension": ".py", 84 | "mimetype": "text/x-python", 85 | "name": "python", 86 | "nbconvert_exporter": "python", 87 | "pygments_lexer": "ipython3", 88 | "version": "3.9.7" 89 | } 90 | }, 91 | "nbformat": 4, 92 | "nbformat_minor": 5 93 | } 94 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | altair==4.1.0 2 | anyio==3.3.4 3 | appnope==0.1.2 4 | argon2-cffi==21.1.0 5 | attrs==21.2.0 6 | Babel==2.9.1 7 | backcall==0.2.0 8 | bleach==4.1.0 9 | bokeh==2.4.1 10 | Brotli==1.0.9 11 | certifi==2021.10.8 12 | cffi==1.15.0 13 | charset-normalizer==2.0.7 14 | click==8.0.3 15 | colorcet==2.0.6 16 | cycler==0.10.0 17 | dash==2.0.0 18 | dash-core-components==2.0.0 19 | dash-html-components==2.0.0 20 | dash-table==5.0.0 21 | debugpy==1.5.1 22 | decorator==5.1.0 23 | defusedxml==0.7.1 24 | entrypoints==0.3 25 | Flask==2.0.2 26 | Flask-Compress==1.10.1 27 | fonttools==4.27.1 28 | holoviews==1.14.6 29 | hvplot==0.7.3 30 | idna==3.3 31 | install==1.3.4 32 | ipykernel==6.4.2 33 | ipympl==0.8.2 34 | ipython==7.28.0 35 | ipython-genutils==0.2.0 36 | ipywidgets==7.6.5 37 | itsdangerous==2.0.1 38 | jedi==0.18.0 39 | Jinja2==3.0.2 40 | joblib==1.1.0 41 | json5==0.9.6 42 | jsonschema==4.1.2 43 | jupyter-client==7.0.6 44 | jupyter-core==4.8.2 45 | jupyter-server==1.11.1 46 | jupyterlab==3.2.1 47 | jupyterlab-pygments==0.1.2 48 | jupyterlab-server==2.8.2 49 | jupyterlab-widgets==1.0.2 50 | jupytext==1.13.0 51 | kiwisolver==1.3.2 52 | Markdown==3.3.4 53 | markdown-it-py==1.1.0 54 | MarkupSafe==2.0.1 55 | matplotlib==3.5.0rc1 56 | matplotlib-inline==0.1.3 57 | mdit-py-plugins==0.2.8 58 | mistune==0.8.4 59 | mplcursors==0.4 60 | nbclassic==0.3.3 61 | nbclient==0.5.4 62 | nbconvert==6.2.0 63 | nbformat==5.1.3 64 | nest-asyncio==1.5.1 65 | notebook==6.4.5 66 | numpy==1.21.3 67 | packaging==21.0 68 | pandas==1.3.4 69 | pandocfilters==1.5.0 70 | panel==0.12.4 71 | param==1.12.0 72 | parso==0.8.2 73 | pexpect==4.8.0 74 | pickleshare==0.7.5 75 | Pillow==8.4.0 76 | pivottablejs==0.9.0 77 | plotly==5.3.1 78 | prometheus-client==0.11.0 79 | prompt-toolkit==3.0.21 80 | ptyprocess==0.7.0 81 | pycparser==2.20 82 | pyct==0.4.8 83 | Pygments==2.10.0 84 | pyparsing==3.0.1 85 | pyrsistent==0.18.0 86 | python-dateutil==2.8.2 87 | pytz==2021.3 88 | pyviz-comms==2.1.0 89 | PyYAML==6.0 90 | pyzmq==22.3.0 91 | requests==2.26.0 92 | requests-unixsocket==0.2.0 93 | scikit-learn==1.0.1 94 | scipy==1.7.1 95 | seaborn==0.11.2 96 | Send2Trash==1.8.0 97 | setuptools-scm==6.3.2 98 | six==1.16.0 99 | sniffio==1.2.0 100 | tenacity==8.0.1 101 | terminado==0.12.1 102 | testpath==0.5.0 103 | threadpoolctl==3.0.0 104 | toml==0.10.2 105 | tomli==1.2.2 106 | toolz==0.11.1 107 | tornado==6.1 108 | tqdm==4.62.3 109 | traitlets==5.1.1 110 | typing-extensions==3.10.0.2 111 | urllib3==1.26.7 112 | vega-datasets==0.9.0 113 | wcwidth==0.2.5 114 | webencodings==0.5.1 115 | websocket-client==1.2.1 116 | Werkzeug==2.0.2 117 | widgetsnbextension==3.5.1 118 | -------------------------------------------------------------------------------- /06_level3_holoviews.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "8cbdebc4-177d-45e4-9270-485b2c8228cb", 6 | "metadata": {}, 7 | "source": [ 8 | "From https://holoviews.org/gallery/demos/bokeh/choropleth_data_link.html" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "2395b996-ed9e-4e2b-9cf1-8c9fec63c28b", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import holoviews as hv\n", 19 | "from holoviews import opts\n", 20 | "\n", 21 | "from holoviews.plotting.links import DataLink\n", 22 | "\n", 23 | "hv.extension('bokeh')" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "id": "c7f3e2ad-a387-49de-8e09-ccfdd89e6999", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "from bokeh.sampledata.us_counties import data as counties\n", 34 | "from bokeh.sampledata.unemployment import data as unemployment\n", 35 | "\n", 36 | "counties = [dict(county, Unemployment=unemployment[cid])\n", 37 | " for cid, county in counties.items()\n", 38 | " if county[\"state\"] == \"tx\"]\n", 39 | "\n", 40 | "county_data = [(county['detailed name'], county['Unemployment']) for county in counties]\n", 41 | "\n", 42 | "choropleth = hv.Polygons(counties, ['lons', 'lats'], [('detailed name', 'County'), 'Unemployment'], \n", 43 | " label='Texas Unemployment')\n", 44 | "table = hv.Table(county_data, [('detailed name', 'County'), 'Unemployment'])\n", 45 | "\n", 46 | "DataLink(choropleth, table)\n", 47 | "\n", 48 | "(choropleth + table).opts(\n", 49 | " opts.Table(height=428),\n", 50 | " opts.Polygons(width=500, height=500, tools=['box_select', 'hover', 'tap'], xaxis=None, \n", 51 | " yaxis=None, color_index='Unemployment'))\n" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "id": "6a05195f-6c4a-4eda-a418-fc2130c3a9c1", 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [] 61 | } 62 | ], 63 | "metadata": { 64 | "kernelspec": { 65 | "display_name": "Python 3 (ipykernel)", 66 | "language": "python", 67 | "name": "python3" 68 | }, 69 | "language_info": { 70 | "codemirror_mode": { 71 | "name": "ipython", 72 | "version": 3 73 | }, 74 | "file_extension": ".py", 75 | "mimetype": "text/x-python", 76 | "name": "python", 77 | "nbconvert_exporter": "python", 78 | "pygments_lexer": "ipython3", 79 | "version": "3.9.7" 80 | } 81 | }, 82 | "nbformat": 4, 83 | "nbformat_minor": 5 84 | } 85 | -------------------------------------------------------------------------------- /07_level3_altair.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "a1e9a991-a8cf-4953-87ef-6b5ccbbc7bdd", 6 | "metadata": {}, 7 | "source": [ 8 | "From https://altair-viz.github.io/gallery/selection_histogram.html" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "6c5f1f82-8dbf-43be-90d4-49e82a6488d7", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import altair as alt\n", 19 | "from vega_datasets import data\n", 20 | "\n", 21 | "source = data.cars()\n", 22 | "\n", 23 | "brush = alt.selection(type='interval')\n", 24 | "\n", 25 | "points = alt.Chart(source).mark_point().encode(\n", 26 | " x='Horsepower:Q',\n", 27 | " y='Miles_per_Gallon:Q',\n", 28 | " color=alt.condition(brush, 'Origin:N', alt.value('lightgray')),\n", 29 | " tooltip=[\"Name\", \"Year\", \"Miles_per_Gallon\", \"Horsepower\", \"Acceleration\", \"Weight_in_lbs\"]\n", 30 | ").add_selection(brush)\n", 31 | "\n", 32 | "bars = alt.Chart(source).mark_bar().encode(\n", 33 | " alt.X('mean(Acceleration):Q',\n", 34 | " scale=alt.Scale(domain=(0, 25))\n", 35 | " ),\n", 36 | " y='Origin:N',\n", 37 | " color='Origin:N',\n", 38 | ").transform_filter(brush)\n", 39 | "\n", 40 | "bars2 = alt.Chart(source).mark_bar().encode(\n", 41 | " alt.X('mean(Weight_in_lbs):Q',\n", 42 | " scale=alt.Scale(domain=(0, 4000))\n", 43 | " ),\n", 44 | " y='Origin:N',\n", 45 | " color='Origin:N',\n", 46 | ").transform_filter(brush)\n", 47 | "\n", 48 | "bars2 = alt.Chart(source).mark_bar().encode(\n", 49 | " alt.X('mean(Weight_in_lbs):Q',\n", 50 | " scale=alt.Scale(domain=(0, 4000))\n", 51 | " ),\n", 52 | " y='Origin:N',\n", 53 | " color='Origin:N',\n", 54 | ").transform_filter(brush)\n", 55 | "\n", 56 | "hist = alt.Chart(source).mark_bar().encode(\n", 57 | " y='Cylinders:N',\n", 58 | " color='Origin:N',\n", 59 | " x='count(Origin):Q',\n", 60 | ").transform_filter(brush)\n", 61 | "\n", 62 | "points | (bars & bars2 & hist)" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "id": "44d14c41-6e58-4d47-bfe7-10783fbd14bc", 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [] 72 | } 73 | ], 74 | "metadata": { 75 | "kernelspec": { 76 | "display_name": "Python 3 (ipykernel)", 77 | "language": "python", 78 | "name": "python3" 79 | }, 80 | "language_info": { 81 | "codemirror_mode": { 82 | "name": "ipython", 83 | "version": 3 84 | }, 85 | "file_extension": ".py", 86 | "mimetype": "text/x-python", 87 | "name": "python", 88 | "nbconvert_exporter": "python", 89 | "pygments_lexer": "ipython3", 90 | "version": "3.9.7" 91 | } 92 | }, 93 | "nbformat": 4, 94 | "nbformat_minor": 5 95 | } 96 | -------------------------------------------------------------------------------- /04_level2_plotly.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "bf5334f8-67e0-494c-8985-71557b8a8ce1", 6 | "metadata": {}, 7 | "source": [ 8 | "From https://plotly.com/python (various)" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "e1bc6076-d042-4fea-b7f6-a4574faf1a17", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import plotly.express as px" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "id": "0169f190-bebd-4098-a4a1-b2ffd550bbdd", 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "df = px.data.gapminder(year=2007)\n", 29 | "px.scatter(df, x=\"gdpPercap\", y=\"lifeExp\", color=\"continent\", size=\"pop\", template=\"simple_white\",\n", 30 | " hover_name=\"country\", size_max=60, log_x=True, height=600).update_layout(hovermode=False)" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "id": "591d777a-c846-4032-8b11-7db6c8d3b74f", 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "import pandas as pd\n", 41 | "df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/earthquakes-23k.csv')\n", 42 | "\n", 43 | "import plotly.express as px\n", 44 | "fig = px.density_mapbox(df, lat='Latitude', lon='Longitude', z='Magnitude', radius=10,\n", 45 | " center=dict(lat=0, lon=180), zoom=0, hover_name=\"Date\",\n", 46 | " mapbox_style=\"stamen-terrain\", height=600,\n", 47 | " color_continuous_scale=\"magma\")\n", 48 | "fig.show()" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "id": "7874dab0-e340-455d-bb41-45080878b832", 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "df = px.data.gapminder(year=2007)\n", 59 | "px.sunburst(df, path=[\"continent\", \"country\"], values=\"pop\", color=\"lifeExp\", hover_data=[\"gdpPercap\"], height=600,\n", 60 | " color_continuous_scale=\"viridis\")" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "id": "8708d5e3-9b06-4b73-954f-f1b4716471c6", 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "import pandas as pd\n", 71 | "cars_df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/imports-85.csv')\n", 72 | "cars_df = cars_df[[\"price\", \"num-of-cylinders\", \"horsepower\", \"highway-mpg\", \"city-mpg\", \"curb-weight\", \"wheel-base\", \n", 73 | " \"compression-ratio\", \"make\"]]\n", 74 | "\n", 75 | "px.parallel_coordinates(cars_df, color=\"price\", height=600)" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "id": "0228a5c5-e197-4da3-adea-a3b0117256e9", 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [] 85 | } 86 | ], 87 | "metadata": { 88 | "kernelspec": { 89 | "display_name": "Python 3 (ipykernel)", 90 | "language": "python", 91 | "name": "python3" 92 | }, 93 | "language_info": { 94 | "codemirror_mode": { 95 | "name": "ipython", 96 | "version": 3 97 | }, 98 | "file_extension": ".py", 99 | "mimetype": "text/x-python", 100 | "name": "python", 101 | "nbconvert_exporter": "python", 102 | "pygments_lexer": "ipython3", 103 | "version": "3.9.7" 104 | } 105 | }, 106 | "nbformat": 4, 107 | "nbformat_minor": 5 108 | } 109 | -------------------------------------------------------------------------------- /08_level3_plotly.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "ac618e2b-d503-44f4-b81c-8ee6cf708bc8", 6 | "metadata": {}, 7 | "source": [ 8 | "From https://plotly.com/python/parallel-categories-diagram/#parallel-categories-with-multicolor-linked-brushing" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "7a8bf282-bef9-4e0a-98e3-055935a0f943", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import plotly.graph_objects as go\n", 19 | "import ipywidgets as widgets\n", 20 | "import pandas as pd\n", 21 | "import numpy as np\n", 22 | "\n", 23 | "cars_df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/imports-85.csv')\n", 24 | "\n", 25 | "# Build parcats dimensions\n", 26 | "categorical_dimensions = ['drive-wheels', 'body-style', 'fuel-type']\n", 27 | "\n", 28 | "dimensions = [dict(values=cars_df[label], label=label) for label in categorical_dimensions]\n", 29 | "\n", 30 | "# Build colorscale\n", 31 | "color = np.zeros(len(cars_df), dtype='uint8')\n", 32 | "colorscale = [[0, 'gray'], [0.33, 'gray'],\n", 33 | " [0.33, 'firebrick'], [0.66, 'firebrick'],\n", 34 | " [0.66, 'blue'], [1.0, 'blue']]\n", 35 | "cmin = -0.5\n", 36 | "cmax = 2.5\n", 37 | "\n", 38 | "# Build figure as FigureWidget\n", 39 | "fig = go.FigureWidget(\n", 40 | " data=[go.Scatter(x=cars_df.horsepower, y=cars_df['highway-mpg'],\n", 41 | " marker={'color': color, 'cmin': cmin, 'cmax': cmax,\n", 42 | " 'colorscale': colorscale, 'showscale': False},\n", 43 | " mode='markers', text=cars_df['make']),\n", 44 | " go.Parcats(domain={'x': [0, 0.45]}, dimensions=dimensions,\n", 45 | " line={'colorscale': colorscale, 'cmin': cmin,\n", 46 | " 'cmax': cmax, 'color': color, 'shape': 'hspline'})]\n", 47 | ").update_layout(height=600, xaxis={'title': 'Horsepower', 'domain': [0.55, 1]},\n", 48 | " yaxis={'title': 'MPG'},\n", 49 | " dragmode='lasso', hovermode='closest')\n", 50 | "\n", 51 | "color_toggle = widgets.ToggleButtons(\n", 52 | " options=['None', 'Red', 'Blue'],\n", 53 | " index=1, description='Brush Color:', disabled=False)\n", 54 | "\n", 55 | "def update_color(trace, points, state):\n", 56 | " new_color = np.array(fig.data[0].marker.color)\n", 57 | " new_color[points.point_inds] = color_toggle.index\n", 58 | "\n", 59 | " with fig.batch_update():\n", 60 | " fig.data[0].marker.color = new_color\n", 61 | " fig.data[1].line.color = new_color\n", 62 | "\n", 63 | "fig.data[0].on_selection(update_color)\n", 64 | "fig.data[1].on_click(update_color)\n", 65 | "\n", 66 | "widgets.VBox([color_toggle, fig])" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "id": "5b401a1a-3027-485a-9db0-8c9fa1e2819e", 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [] 76 | } 77 | ], 78 | "metadata": { 79 | "kernelspec": { 80 | "display_name": "Python 3 (ipykernel)", 81 | "language": "python", 82 | "name": "python3" 83 | }, 84 | "language_info": { 85 | "codemirror_mode": { 86 | "name": "ipython", 87 | "version": 3 88 | }, 89 | "file_extension": ".py", 90 | "mimetype": "text/x-python", 91 | "name": "python", 92 | "nbconvert_exporter": "python", 93 | "pygments_lexer": "ipython3", 94 | "version": "3.9.7" 95 | } 96 | }, 97 | "nbformat": 4, 98 | "nbformat_minor": 5 99 | } 100 | --------------------------------------------------------------------------------