diff --git a/2D-Histogram.ipynb b/2D-Histogram.ipynb
new file mode 100644
index 000000000..8f4d98891
--- /dev/null
+++ b/2D-Histogram.ipynb
@@ -0,0 +1,454 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1eef2039",
+ "metadata": {},
+ "source": [
+ "## 2D Histograms or Density Heatmaps\n",
+ "\n",
+ "A 2D histogram, also known as a density heatmap, is the 2-dimensional generalization of a [histogram](/python/histograms/) which resembles a [heatmap](/python/heatmaps/) but is computed by grouping a set of points specified by their `x` and `y` coordinates into bins, and applying an aggregation function such as `count` or `sum` (if `z` is provided) to compute the color of the tile representing the bin. This kind of visualization (and the related [2D histogram contour, or density contour](https://plotly.com/python/2d-histogram-contour/)) is often used to manage over-plotting, or situations where showing large data sets as [scatter plots](/python/line-and-scatter/) would result in points overlapping each other and hiding patterns. For data sets of more than a few thousand points, a better approach than the ones listed here would be to [use Plotly with Datashader](/python/datashader/) to precompute the aggregations before displaying the data with Plotly.\n",
+ "\n",
+ "## Density Heatmaps with Plotly Express\n",
+ "\n",
+ "[Plotly Express](/python/plotly-express/) is the easy-to-use, high-level interface to Plotly, which [operates on a variety of types of data](/python/px-arguments/) and produces [easy-to-style figures](/python/styling-plotly-express/). The Plotly Express function `density_heatmap()` can be used to produce density heatmaps."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c1a828fe",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_heatmap(df, x=\"total_bill\", y=\"tip\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cd127a2f",
+ "metadata": {},
+ "source": [
+ "The number of bins can be controlled with `nbinsx` and `nbinsy` and the [color scale](/python/colorscales/) with `color_continuous_scale`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "439e9b3d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_heatmap(df, x=\"total_bill\", y=\"tip\", nbinsx=20, nbinsy=20, color_continuous_scale=\"Viridis\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "474e326c",
+ "metadata": {},
+ "source": [
+ "Marginal plots can be added to visualize the 1-dimensional distributions of the two variables. Here we use a marginal [`histogram`](/python/histograms/). Other allowable values are `violin`, `box` and `rug`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f68ba4b2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_heatmap(df, x=\"total_bill\", y=\"tip\", marginal_x=\"histogram\", marginal_y=\"histogram\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0a64cdef",
+ "metadata": {},
+ "source": [
+ "Density heatmaps can also be [faceted](/python/facet-plots/):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4fad0a36",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_heatmap(df, x=\"total_bill\", y=\"tip\", facet_row=\"sex\", facet_col=\"smoker\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "03d41dab",
+ "metadata": {},
+ "source": [
+ "### Displaying Text\n",
+ "\n",
+ "*New in v5.5*\n",
+ "\n",
+ "You can add the `z` values as text using the `text_auto` argument. Setting it to `True` will display the values on the bars, and setting it to a `d3-format` formatting string will control the output format."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "28f6af46",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_heatmap(df, x=\"total_bill\", y=\"tip\", text_auto=True)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5c7c46fe",
+ "metadata": {},
+ "source": [
+ "### Other aggregation functions than `count`\n",
+ "\n",
+ "By passing in a `z` value and a `histfunc`, density heatmaps can perform basic aggregation operations. Here we show average Sepal Length grouped by Petal Length and Petal Width for the Iris dataset."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7a678676",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.iris()\n",
+ "\n",
+ "fig = px.density_heatmap(df, x=\"petal_length\", y=\"petal_width\", z=\"sepal_length\", histfunc=\"avg\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c9f14e88",
+ "metadata": {},
+ "source": [
+ "### 2D Histograms with Graph Objects\n",
+ "\n",
+ "To build this kind of figure using [graph objects](/python/graph-objects/) without using Plotly Express, we can use the `go.Histogram2d` class."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dfe41deb",
+ "metadata": {},
+ "source": [
+ "### 2D Histogram of a Bivariate Normal Distribution ###"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a6e91ba3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "import numpy as np\n",
+ "np.random.seed(1)\n",
+ "\n",
+ "x = np.random.randn(500)\n",
+ "y = np.random.randn(500)+1\n",
+ "\n",
+ "fig = go.Figure(go.Histogram2d(\n",
+ " x=x,\n",
+ " y=y\n",
+ " ))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1e1866a7",
+ "metadata": {},
+ "source": [
+ "### 2D Histogram Binning and Styling Options ###"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7dfaf077",
+ "metadata": {
+ "lines_to_next_cell": 0
+ },
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "import numpy as np\n",
+ "\n",
+ "x = np.random.randn(500)\n",
+ "y = np.random.randn(500)+1\n",
+ "\n",
+ "fig = go.Figure(go.Histogram2d(x=x, y=y, histnorm='probability',\n",
+ " autobinx=False,\n",
+ " xbins=dict(start=-3, end=3, size=0.1),\n",
+ " autobiny=False,\n",
+ " ybins=dict(start=-2.5, end=4, size=0.1),\n",
+ " colorscale=[[0, 'rgb(12,51,131)'], [0.25, 'rgb(10,136,186)'], [0.5, 'rgb(242,211,56)'], [0.75, 'rgb(242,143,56)'], [1, 'rgb(217,30,30)']]\n",
+ " ))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28d202d8",
+ "metadata": {},
+ "source": [
+ "### Sharing bin settings between 2D Histograms\n",
+ "This example shows how to use [bingroup](https://plotly.com/python/reference/histogram/#histogram-bingroup) attribute to have a compatible bin settings for both histograms. To define `start`, `end` and `size` value of x-axis and y-axis separately, set [ybins](https://plotly.com/python/reference/histogram2dcontour/#histogram2dcontour-ybins) and `xbins`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7cd12899",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "from plotly.subplots import make_subplots\n",
+ "\n",
+ "fig = make_subplots(2,2)\n",
+ "fig.add_trace(go.Histogram2d(\n",
+ " x = [ 1, 2, 2, 3, 4 ],\n",
+ " y = [ 1, 2, 2, 3, 4 ],\n",
+ " coloraxis = \"coloraxis\",\n",
+ " xbins = {'start':1, 'size':1}), 1,1)\n",
+ "fig.add_trace(go.Histogram2d(\n",
+ " x = [ 4, 5, 5, 5, 6 ],\n",
+ " y = [ 4, 5, 5, 5, 6 ],\n",
+ " coloraxis = \"coloraxis\",\n",
+ " ybins = {'start': 3, 'size': 1}),1,2)\n",
+ "fig.add_trace(go.Histogram2d(\n",
+ " x = [ 1, 2, 2, 3, 4 ],\n",
+ " y = [ 1, 2, 2, 3, 4 ],\n",
+ " bingroup = 1,\n",
+ " coloraxis = \"coloraxis\",\n",
+ " xbins = {'start':1, 'size':1}), 2,1)\n",
+ "fig.add_trace(go.Histogram2d(\n",
+ " x = [ 4, 5, 5, 5, 6 ],\n",
+ " y = [ 4, 5, 5, 5, 6 ],\n",
+ " bingroup = 1,\n",
+ " coloraxis = \"coloraxis\",\n",
+ " ybins = {'start': 3, 'size': 1}),2,2)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "46e75035",
+ "metadata": {},
+ "source": [
+ "### 2D Histogram Overlaid with a Scatter Chart ###"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "865bbcc9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "import numpy as np\n",
+ "\n",
+ "x0 = np.random.randn(100)/5. + 0.5 # 5. enforces float division\n",
+ "y0 = np.random.randn(100)/5. + 0.5\n",
+ "x1 = np.random.rand(50)\n",
+ "y1 = np.random.rand(50) + 1.0\n",
+ "\n",
+ "x = np.concatenate([x0, x1])\n",
+ "y = np.concatenate([y0, y1])\n",
+ "\n",
+ "fig = go.Figure()\n",
+ "\n",
+ "fig.add_trace(go.Scatter(\n",
+ " x=x0,\n",
+ " y=y0,\n",
+ " mode='markers',\n",
+ " showlegend=False,\n",
+ " marker=dict(\n",
+ " symbol='x',\n",
+ " opacity=0.7,\n",
+ " color='white',\n",
+ " size=8,\n",
+ " line=dict(width=1),\n",
+ " )\n",
+ "))\n",
+ "fig.add_trace(go.Scatter(\n",
+ " x=x1,\n",
+ " y=y1,\n",
+ " mode='markers',\n",
+ " showlegend=False,\n",
+ " marker=dict(\n",
+ " symbol='circle',\n",
+ " opacity=0.7,\n",
+ " color='white',\n",
+ " size=8,\n",
+ " line=dict(width=1),\n",
+ " )\n",
+ "))\n",
+ "fig.add_trace(go.Histogram2d(\n",
+ " x=x,\n",
+ " y=y,\n",
+ " colorscale='YlGnBu',\n",
+ " zmax=10,\n",
+ " nbinsx=14,\n",
+ " nbinsy=14,\n",
+ " zauto=False,\n",
+ "))\n",
+ "\n",
+ "fig.update_layout(\n",
+ " xaxis=dict( ticks='', showgrid=False, zeroline=False, nticks=20 ),\n",
+ " yaxis=dict( ticks='', showgrid=False, zeroline=False, nticks=20 ),\n",
+ " autosize=False,\n",
+ " height=550,\n",
+ " width=550,\n",
+ " hovermode='closest',\n",
+ "\n",
+ ")\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b18e1cc2",
+ "metadata": {},
+ "source": [
+ "### Text on 2D Histogram Points\n",
+ "\n",
+ "In this example we add text to 2D Histogram points. We use the values from the `z` attribute for the text."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14816b45",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "from plotly import data\n",
+ "\n",
+ "df = data.tips()\n",
+ "\n",
+ "fig = go.Figure(go.Histogram2d(\n",
+ " x=df.total_bill,\n",
+ " y=df.tip,\n",
+ " texttemplate= \"%{z}\"\n",
+ " ))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fac86a3a",
+ "metadata": {},
+ "source": [
+ "#### Reference\n",
+ "See https://plotly.com/python/reference/histogram2d/ for more information and chart attribute options!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4aad9065",
+ "metadata": {},
+ "source": [
+ "### What About Dash?\n",
+ "\n",
+ "[Dash](https://dash.plot.ly/) is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.\n",
+ "\n",
+ "Learn about how to install Dash at https://dash.plot.ly/installation.\n",
+ "\n",
+ "Everywhere in this page that you see `fig.show()`, you can display the same figure in a Dash application by passing it to the `figure` argument of the [`Graph` component](https://dash.plot.ly/dash-core-components/graph) from the built-in `dash_core_components` package like this:\n",
+ "\n",
+ "```python\n",
+ "import plotly.graph_objects as go # or plotly.express as px\n",
+ "fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)\n",
+ "# fig.add_trace( ... )\n",
+ "# fig.update_layout( ... )\n",
+ "\n",
+ "from dash import Dash, dcc, html\n",
+ "\n",
+ "app = Dash()\n",
+ "app.layout = html.Div([\n",
+ " dcc.Graph(figure=fig)\n",
+ "])\n",
+ "\n",
+ "app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "jupytext": {
+ "notebook_metadata_filter": "all"
+ },
+ "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.11"
+ },
+ "plotly": {
+ "description": "How to make 2D Histograms in Python with Plotly.",
+ "display_as": "statistical",
+ "language": "python",
+ "layout": "base",
+ "name": "2D Histograms",
+ "order": 5,
+ "page_type": "u-guide",
+ "permalink": "python/2D-Histogram/",
+ "redirect_from": [
+ "python/2d-histogram/",
+ "python/2d-histograms/"
+ ],
+ "thumbnail": "thumbnail/histogram2d.jpg"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/2d-histogram-contour.ipynb b/2d-histogram-contour.ipynb
new file mode 100644
index 000000000..8f8553a80
--- /dev/null
+++ b/2d-histogram-contour.ipynb
@@ -0,0 +1,401 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "9330d1bc",
+ "metadata": {},
+ "source": [
+ "## 2D Histogram Contours or Density Contours\n",
+ "\n",
+ "A 2D histogram contour plot, also known as a density contour plot, is a 2-dimensional generalization of a [histogram](/python/histograms/) which resembles a [contour plot](/python/contour-plots/) but is computed by grouping a set of points specified by their `x` and `y` coordinates into bins, and applying an aggregation function such as `count` or `sum` (if `z` is provided) to compute the value to be used to compute contours. This kind of visualization (and the related [2D histogram, or density heatmap](/python/2d-histogram/)) is often used to manage over-plotting, or situations where showing large data sets as [scatter plots](/python/line-and-scatter/) would result in points overlapping each other and hiding patterns.\n",
+ "\n",
+ "## Density Contours with Plotly Express\n",
+ "\n",
+ "[Plotly Express](/python/plotly-express/) is the easy-to-use, high-level interface to Plotly, which [operates on a variety of types of data](/python/px-arguments/) and produces [easy-to-style figures](/python/styling-plotly-express/). The Plotly Express function `density_contour()` can be used to produce density contours."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1055f4a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_contour(df, x=\"total_bill\", y=\"tip\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e5db23f2",
+ "metadata": {},
+ "source": [
+ "Marginal plots can be added to visualize the 1-dimensional distributions of the two variables. Here we use a marginal [`histogram`](/python/histograms/). Other allowable values are `violin`, `box` and `rug`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0551df8f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_contour(df, x=\"total_bill\", y=\"tip\", marginal_x=\"histogram\", marginal_y=\"histogram\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4c657367",
+ "metadata": {},
+ "source": [
+ "Density contours can also be [faceted](/python/facet-plots/) and [discretely colored](/python/discrete-color/):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "99e14f6e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_contour(df, x=\"total_bill\", y=\"tip\", facet_col=\"sex\", color=\"smoker\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "405f46d4",
+ "metadata": {},
+ "source": [
+ "Plotly Express density contours can be [continuously-colored](/python/colorscales/) and labeled:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ab260026",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.tips()\n",
+ "\n",
+ "fig = px.density_contour(df, x=\"total_bill\", y=\"tip\")\n",
+ "fig.update_traces(contours_coloring=\"fill\", contours_showlabels = True)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5d2c5c02",
+ "metadata": {},
+ "source": [
+ "### Other aggregation functions than `count`\n",
+ "\n",
+ "By passing in a `z` value and a `histfunc`, density contours can perform basic aggregation operations. Here we show average Sepal Length grouped by Petal Length and Petal Width for the Iris dataset."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c3aaff55",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.iris()\n",
+ "\n",
+ "fig = px.density_contour(df, x=\"petal_length\", y=\"petal_width\", z=\"sepal_length\", histfunc=\"avg\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7df9bb9",
+ "metadata": {},
+ "source": [
+ "### 2D Histograms with Graph Objects\n",
+ "\n",
+ "To build this kind of figure with [graph objects](/python/graph-objects/) without using Plotly Express, we can use the `go.Histogram2d` class.\n",
+ "\n",
+ "#### Basic 2D Histogram Contour"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a56ae5df",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "import numpy as np\n",
+ "np.random.seed(1)\n",
+ "\n",
+ "x = np.random.uniform(-1, 1, size=500)\n",
+ "y = np.random.uniform(-1, 1, size=500)\n",
+ "\n",
+ "fig = go.Figure(go.Histogram2dContour(\n",
+ " x = x,\n",
+ " y = y\n",
+ "))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5d40ea2a",
+ "metadata": {},
+ "source": [
+ "#### 2D Histogram Contour Colorscale"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "47bde4de",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "import numpy as np\n",
+ "\n",
+ "x = np.random.uniform(-1, 1, size=500)\n",
+ "y = np.random.uniform(-1, 1, size=500)\n",
+ "\n",
+ "fig = go.Figure(go.Histogram2dContour(\n",
+ " x = x,\n",
+ " y = y,\n",
+ " colorscale = 'Blues'\n",
+ "))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "515902ec",
+ "metadata": {},
+ "source": [
+ "#### 2D Histogram Contour Styled"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ead9b5b6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "import numpy as np\n",
+ "\n",
+ "x = np.random.uniform(-1, 1, size=500)\n",
+ "y = np.random.uniform(-1, 1, size=500)\n",
+ "\n",
+ "fig = go.Figure(go.Histogram2dContour(\n",
+ " x = x,\n",
+ " y = y,\n",
+ " colorscale = 'Jet',\n",
+ " contours = dict(\n",
+ " showlabels = True,\n",
+ " labelfont = dict(\n",
+ " family = 'Raleway',\n",
+ " color = 'white'\n",
+ " )\n",
+ " ),\n",
+ " hoverlabel = dict(\n",
+ " bgcolor = 'white',\n",
+ " bordercolor = 'black',\n",
+ " font = dict(\n",
+ " family = 'Raleway',\n",
+ " color = 'black'\n",
+ " )\n",
+ " )\n",
+ "\n",
+ "))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dc6e8520",
+ "metadata": {},
+ "source": [
+ "#### 2D Histogram Contour Subplot"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ab165388",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "import numpy as np\n",
+ "\n",
+ "t = np.linspace(-1, 1.2, 2000)\n",
+ "x = (t**3) + (0.3 * np.random.randn(2000))\n",
+ "y = (t**6) + (0.3 * np.random.randn(2000))\n",
+ "\n",
+ "fig = go.Figure()\n",
+ "fig.add_trace(go.Histogram2dContour(\n",
+ " x = x,\n",
+ " y = y,\n",
+ " colorscale = 'Blues',\n",
+ " reversescale = True,\n",
+ " xaxis = 'x',\n",
+ " yaxis = 'y'\n",
+ " ))\n",
+ "fig.add_trace(go.Scatter(\n",
+ " x = x,\n",
+ " y = y,\n",
+ " xaxis = 'x',\n",
+ " yaxis = 'y',\n",
+ " mode = 'markers',\n",
+ " marker = dict(\n",
+ " color = 'rgba(0,0,0,0.3)',\n",
+ " size = 3\n",
+ " )\n",
+ " ))\n",
+ "fig.add_trace(go.Histogram(\n",
+ " y = y,\n",
+ " xaxis = 'x2',\n",
+ " marker = dict(\n",
+ " color = 'rgba(0,0,0,1)'\n",
+ " )\n",
+ " ))\n",
+ "fig.add_trace(go.Histogram(\n",
+ " x = x,\n",
+ " yaxis = 'y2',\n",
+ " marker = dict(\n",
+ " color = 'rgba(0,0,0,1)'\n",
+ " )\n",
+ " ))\n",
+ "\n",
+ "fig.update_layout(\n",
+ " autosize = False,\n",
+ " xaxis = dict(\n",
+ " zeroline = False,\n",
+ " domain = [0,0.85],\n",
+ " showgrid = False\n",
+ " ),\n",
+ " yaxis = dict(\n",
+ " zeroline = False,\n",
+ " domain = [0,0.85],\n",
+ " showgrid = False\n",
+ " ),\n",
+ " xaxis2 = dict(\n",
+ " zeroline = False,\n",
+ " domain = [0.85,1],\n",
+ " showgrid = False\n",
+ " ),\n",
+ " yaxis2 = dict(\n",
+ " zeroline = False,\n",
+ " domain = [0.85,1],\n",
+ " showgrid = False\n",
+ " ),\n",
+ " height = 600,\n",
+ " width = 600,\n",
+ " bargap = 0,\n",
+ " hovermode = 'closest',\n",
+ " showlegend = False\n",
+ ")\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e655f124",
+ "metadata": {},
+ "source": [
+ "#### Reference\n",
+ "See https://plotly.com/python/reference/histogram2dcontour/ for more information and chart attribute options!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "455e355f",
+ "metadata": {},
+ "source": [
+ "### What About Dash?\n",
+ "\n",
+ "[Dash](https://dash.plot.ly/) is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.\n",
+ "\n",
+ "Learn about how to install Dash at https://dash.plot.ly/installation.\n",
+ "\n",
+ "Everywhere in this page that you see `fig.show()`, you can display the same figure in a Dash application by passing it to the `figure` argument of the [`Graph` component](https://dash.plot.ly/dash-core-components/graph) from the built-in `dash_core_components` package like this:\n",
+ "\n",
+ "```python\n",
+ "import plotly.graph_objects as go # or plotly.express as px\n",
+ "fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)\n",
+ "# fig.add_trace( ... )\n",
+ "# fig.update_layout( ... )\n",
+ "\n",
+ "from dash import Dash, dcc, html\n",
+ "\n",
+ "app = Dash()\n",
+ "app.layout = html.Div([\n",
+ " dcc.Graph(figure=fig)\n",
+ "])\n",
+ "\n",
+ "app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "jupytext": {
+ "notebook_metadata_filter": "all"
+ },
+ "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.6.8"
+ },
+ "plotly": {
+ "description": "How to make 2D Histogram Contour plots in Python with Plotly.",
+ "display_as": "statistical",
+ "language": "python",
+ "layout": "base",
+ "name": "2D Histogram Contour",
+ "order": 11,
+ "page_type": "u-guide",
+ "permalink": "python/2d-histogram-contour/",
+ "redirect_from": "python/2d-density-plots/",
+ "thumbnail": "thumbnail/hist2dcontour.png"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/3d-axes.ipynb b/3d-axes.ipynb
new file mode 100644
index 000000000..9f1f213dc
--- /dev/null
+++ b/3d-axes.ipynb
@@ -0,0 +1,395 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "68bb6fe8",
+ "metadata": {},
+ "source": [
+ "### Range of axes\n",
+ "\n",
+ "3D figures have an attribute in `layout` called `scene`, which contains\n",
+ "attributes such as `xaxis`, `yaxis` and `zaxis` parameters, in order to\n",
+ "set the range, title, ticks, color etc. of the axes.\n",
+ "\n",
+ "For creating 3D charts, see [this page](https://plotly.com/python/3d-charts/).\n",
+ "\n",
+ "Set `range` on an axis to manually configure a range for that axis. If you don't set `range`, it's automatically calculated. In this example, we set a `range` on `xaxis`, `yaxis`, and `zaxis`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b6f2d4dc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "np.random.seed(1)\n",
+ "\n",
+ "N = 70\n",
+ "\n",
+ "fig = go.Figure(data=[go.Mesh3d(x=(70*np.random.randn(N)),\n",
+ " y=(55*np.random.randn(N)),\n",
+ " z=(40*np.random.randn(N)),\n",
+ " opacity=0.5,\n",
+ " color='rgba(244,22,100,0.6)'\n",
+ " )])\n",
+ "\n",
+ "fig.update_layout(\n",
+ " scene = dict(\n",
+ " xaxis = dict(nticks=4, range=[-100,100],),\n",
+ " yaxis = dict(nticks=4, range=[-50,100],),\n",
+ " zaxis = dict(nticks=4, range=[-100,100],),),\n",
+ " width=700,\n",
+ " margin=dict(r=20, l=10, b=10, t=10))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c9e11629",
+ "metadata": {},
+ "source": [
+ "### Setting only a Lower or Upper Bound for Range\n",
+ "\n",
+ "*New in 5.17*\n",
+ "\n",
+ "You can also set just a lower or upper bound for `range`. In this case, autorange is used for the other bound. In this example, we apply autorange to the lower bound of the `yaxis` and the upper bound of `zaxis` by setting them to `None`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1d6c29ba",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "np.random.seed(1)\n",
+ "\n",
+ "N = 70\n",
+ "\n",
+ "fig = go.Figure(data=[go.Mesh3d(x=(70*np.random.randn(N)),\n",
+ " y=(55*np.random.randn(N)),\n",
+ " z=(40*np.random.randn(N)),\n",
+ " opacity=0.5,\n",
+ " color='rgba(244,22,100,0.6)'\n",
+ " )])\n",
+ "\n",
+ "fig.update_layout(\n",
+ " scene = dict(\n",
+ " xaxis = dict(nticks=4, range=[-100,100],),\n",
+ " yaxis = dict(nticks=4, range=[None, 100],),\n",
+ " zaxis = dict(nticks=4, range=[-100, None],),),\n",
+ " width=700,\n",
+ " margin=dict(r=20, l=10, b=10, t=10))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fd61d49e",
+ "metadata": {},
+ "source": [
+ "### Fixed Ratio Axes"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4478ccb7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "from plotly.subplots import make_subplots\n",
+ "import numpy as np\n",
+ "\n",
+ "N = 50\n",
+ "\n",
+ "fig = make_subplots(rows=2, cols=2,\n",
+ " specs=[[{'is_3d': True}, {'is_3d': True}],\n",
+ " [{'is_3d': True}, {'is_3d': True}]],\n",
+ " print_grid=False)\n",
+ "for i in [1,2]:\n",
+ " for j in [1,2]:\n",
+ " fig.add_trace(\n",
+ " go.Mesh3d(\n",
+ " x=(60*np.random.randn(N)),\n",
+ " y=(25*np.random.randn(N)),\n",
+ " z=(40*np.random.randn(N)),\n",
+ " opacity=0.5,\n",
+ " ),\n",
+ " row=i, col=j)\n",
+ "\n",
+ "fig.update_layout(width=700, margin=dict(r=10, l=10, b=10, t=10))\n",
+ "# fix the ratio in the top left subplot to be a cube\n",
+ "fig.update_layout(scene_aspectmode='cube')\n",
+ "# manually force the z-axis to appear twice as big as the other two\n",
+ "fig.update_layout(scene2_aspectmode='manual',\n",
+ " scene2_aspectratio=dict(x=1, y=1, z=2))\n",
+ "# draw axes in proportion to the proportion of their ranges\n",
+ "fig.update_layout(scene3_aspectmode='data')\n",
+ "# automatically produce something that is well proportioned using 'data' as the default\n",
+ "fig.update_layout(scene4_aspectmode='auto')\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "38f8ca0d",
+ "metadata": {},
+ "source": [
+ "### Set Axes Title"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a59f6639",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "# Define random surface\n",
+ "N = 50\n",
+ "fig = go.Figure()\n",
+ "fig.add_trace(go.Mesh3d(x=(60*np.random.randn(N)),\n",
+ " y=(25*np.random.randn(N)),\n",
+ " z=(40*np.random.randn(N)),\n",
+ " opacity=0.5,\n",
+ " color='yellow'\n",
+ " ))\n",
+ "fig.add_trace(go.Mesh3d(x=(70*np.random.randn(N)),\n",
+ " y=(55*np.random.randn(N)),\n",
+ " z=(30*np.random.randn(N)),\n",
+ " opacity=0.5,\n",
+ " color='pink'\n",
+ " ))\n",
+ "\n",
+ "fig.update_layout(scene = dict(\n",
+ " xaxis=dict(\n",
+ " title=dict(\n",
+ " text='X AXIS TITLE'\n",
+ " )\n",
+ " ),\n",
+ " yaxis=dict(\n",
+ " title=dict(\n",
+ " text='Y AXIS TITLE'\n",
+ " )\n",
+ " ),\n",
+ " zaxis=dict(\n",
+ " title=dict(\n",
+ " text='Z AXIS TITLE'\n",
+ " )\n",
+ " ),\n",
+ " ),\n",
+ " width=700,\n",
+ " margin=dict(r=20, b=10, l=10, t=10))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "315c4538",
+ "metadata": {},
+ "source": [
+ "### Ticks Formatting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "421cba75",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "# Define random surface\n",
+ "N = 50\n",
+ "fig = go.Figure(data=[go.Mesh3d(x=(60*np.random.randn(N)),\n",
+ " y=(25*np.random.randn(N)),\n",
+ " z=(40*np.random.randn(N)),\n",
+ " opacity=0.5,\n",
+ " color='rgba(100,22,200,0.5)'\n",
+ " )])\n",
+ "\n",
+ "# Different types of customized ticks\n",
+ "fig.update_layout(scene = dict(\n",
+ " xaxis = dict(\n",
+ " ticktext= ['TICKS','MESH','PLOTLY','PYTHON'],\n",
+ " tickvals= [0,50,75,-50]),\n",
+ " yaxis = dict(\n",
+ " nticks=5, tickfont=dict(\n",
+ " color='green',\n",
+ " size=12,\n",
+ " family='Old Standard TT, serif',),\n",
+ " ticksuffix='#'),\n",
+ " zaxis = dict(\n",
+ " nticks=4, ticks='outside',\n",
+ " tick0=0, tickwidth=4),),\n",
+ " width=700,\n",
+ " margin=dict(r=10, l=10, b=10, t=10)\n",
+ " )\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "88e41734",
+ "metadata": {},
+ "source": [
+ "### Background and Grid Color"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5fbfaadb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "N = 50\n",
+ "fig = go.Figure(data=[go.Mesh3d(x=(30*np.random.randn(N)),\n",
+ " y=(25*np.random.randn(N)),\n",
+ " z=(30*np.random.randn(N)),\n",
+ " opacity=0.5,)])\n",
+ "\n",
+ "\n",
+ "# xaxis.backgroundcolor is used to set background color\n",
+ "fig.update_layout(scene = dict(\n",
+ " xaxis = dict(\n",
+ " backgroundcolor=\"rgb(200, 200, 230)\",\n",
+ " gridcolor=\"white\",\n",
+ " showbackground=True,\n",
+ " zerolinecolor=\"white\",),\n",
+ " yaxis = dict(\n",
+ " backgroundcolor=\"rgb(230, 200,230)\",\n",
+ " gridcolor=\"white\",\n",
+ " showbackground=True,\n",
+ " zerolinecolor=\"white\"),\n",
+ " zaxis = dict(\n",
+ " backgroundcolor=\"rgb(230, 230,200)\",\n",
+ " gridcolor=\"white\",\n",
+ " showbackground=True,\n",
+ " zerolinecolor=\"white\",),),\n",
+ " width=700,\n",
+ " margin=dict(\n",
+ " r=10, l=10,\n",
+ " b=10, t=10)\n",
+ " )\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "29a75416",
+ "metadata": {},
+ "source": [
+ "### Disabling tooltip spikes\n",
+ "\n",
+ "By default, guidelines originating from the tooltip point are drawn. It is possible to disable this behaviour with the `showspikes` parameter. In this example we only keep the `z` spikes (projection of the tooltip on the `x-y` plane). Hover on the data to show this behaviour."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cab2807f",
+ "metadata": {
+ "lines_to_next_cell": 2
+ },
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "N = 50\n",
+ "fig = go.Figure(data=[go.Mesh3d(x=(30*np.random.randn(N)),\n",
+ " y=(25*np.random.randn(N)),\n",
+ " z=(30*np.random.randn(N)),\n",
+ " opacity=0.5,)])\n",
+ "fig.update_layout(scene=dict(xaxis_showspikes=False,\n",
+ " yaxis_showspikes=False))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9bb6ce1d",
+ "metadata": {},
+ "source": [
+ "### What About Dash?\n",
+ "\n",
+ "[Dash](https://dash.plot.ly/) is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.\n",
+ "\n",
+ "Learn about how to install Dash at https://dash.plot.ly/installation.\n",
+ "\n",
+ "Everywhere in this page that you see `fig.show()`, you can display the same figure in a Dash application by passing it to the `figure` argument of the [`Graph` component](https://dash.plot.ly/dash-core-components/graph) from the built-in `dash_core_components` package like this:\n",
+ "\n",
+ "```python\n",
+ "import plotly.graph_objects as go # or plotly.express as px\n",
+ "fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)\n",
+ "# fig.add_trace( ... )\n",
+ "# fig.update_layout( ... )\n",
+ "\n",
+ "from dash import Dash, dcc, html\n",
+ "\n",
+ "app = Dash()\n",
+ "app.layout = html.Div([\n",
+ " dcc.Graph(figure=fig)\n",
+ "])\n",
+ "\n",
+ "app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "jupytext": {
+ "notebook_metadata_filter": "all"
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "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.10.4"
+ },
+ "plotly": {
+ "description": "How to format axes of 3d plots in Python with Plotly.",
+ "display_as": "3d_charts",
+ "language": "python",
+ "layout": "base",
+ "name": "3D Axes",
+ "order": 1,
+ "page_type": "example_index",
+ "permalink": "python/3d-axes/",
+ "thumbnail": "thumbnail/3d-axes.png"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/3d-bubble-charts.ipynb b/3d-bubble-charts.ipynb
new file mode 100644
index 000000000..45680349a
--- /dev/null
+++ b/3d-bubble-charts.ipynb
@@ -0,0 +1,309 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a481006f",
+ "metadata": {},
+ "source": [
+ "### 3d Bubble chart with Plotly Express"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "94b088f9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "import numpy as np\n",
+ "df = px.data.gapminder()\n",
+ "fig = px.scatter_3d(df, x='year', y='continent', z='pop', size='gdpPercap', color='lifeExp',\n",
+ " hover_data=['country'])\n",
+ "fig.update_layout(scene_zaxis_type=\"log\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7e5f2ec5",
+ "metadata": {},
+ "source": [
+ "#### Simple Bubble Chart"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17d6f5d6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Get Data: this ex will only use part of it (i.e. rows 750-1500)\n",
+ "df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')\n",
+ "\n",
+ "start, end = 750, 1500\n",
+ "\n",
+ "fig = go.Figure(data=go.Scatter3d(\n",
+ " x=df['year'][start:end],\n",
+ " y=df['continent'][start:end],\n",
+ " z=df['pop'][start:end],\n",
+ " text=df['country'][start:end],\n",
+ " mode='markers',\n",
+ " marker=dict(\n",
+ " sizemode='diameter',\n",
+ " sizeref=750,\n",
+ " size=df['gdpPercap'][start:end],\n",
+ " color = df['lifeExp'][start:end],\n",
+ " colorscale = 'Viridis',\n",
+ " colorbar_title = 'Life
Expectancy',\n",
+ " line_color='rgb(140, 140, 170)'\n",
+ " )\n",
+ "))\n",
+ "\n",
+ "\n",
+ "fig.update_layout(height=800, width=800,\n",
+ " title=dict(text='Examining Population and Life Expectancy Over Time'))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d52cc9f6",
+ "metadata": {},
+ "source": [
+ "#### Bubble Chart Sized by a Variable\n",
+ "\n",
+ "Plot planets' distance from sun, density, and gravity with bubble size based on planet size"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bc877ab1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "planets = ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto']\n",
+ "planet_colors = ['rgb(135, 135, 125)', 'rgb(210, 50, 0)', 'rgb(50, 90, 255)',\n",
+ " 'rgb(178, 0, 0)', 'rgb(235, 235, 210)', 'rgb(235, 205, 130)',\n",
+ " 'rgb(55, 255, 217)', 'rgb(38, 0, 171)', 'rgb(255, 255, 255)']\n",
+ "distance_from_sun = [57.9, 108.2, 149.6, 227.9, 778.6, 1433.5, 2872.5, 4495.1, 5906.4]\n",
+ "density = [5427, 5243, 5514, 3933, 1326, 687, 1271, 1638, 2095]\n",
+ "gravity = [3.7, 8.9, 9.8, 3.7, 23.1, 9.0, 8.7, 11.0, 0.7]\n",
+ "planet_diameter = [4879, 12104, 12756, 6792, 142984, 120536, 51118, 49528, 2370]\n",
+ "\n",
+ "# Create trace, sizing bubbles by planet diameter\n",
+ "fig = go.Figure(data=go.Scatter3d(\n",
+ " x = distance_from_sun,\n",
+ " y = density,\n",
+ " z = gravity,\n",
+ " text = planets,\n",
+ " mode = 'markers',\n",
+ " marker = dict(\n",
+ " sizemode = 'diameter',\n",
+ " sizeref = 750, # info on sizeref: https://plotly.com/python/reference/scatter/#scatter-marker-sizeref\n",
+ " size = planet_diameter,\n",
+ " color = planet_colors,\n",
+ " )\n",
+ "))\n",
+ "\n",
+ "fig.update_layout(\n",
+ " width=800,\n",
+ " height=800,\n",
+ " title=dict(text=\"Planets!\"),\n",
+ " scene=dict(\n",
+ " xaxis=dict(\n",
+ " title=dict(\n",
+ " text=\"Distance from Sun\",\n",
+ " font=dict(\n",
+ " color=\"white\"\n",
+ " )\n",
+ " )\n",
+ " ),\n",
+ " yaxis=dict(\n",
+ " title=dict(\n",
+ " text=\"Density\",\n",
+ " font=dict(\n",
+ " color=\"white\"\n",
+ " )\n",
+ " )\n",
+ " ),\n",
+ " zaxis=dict(\n",
+ " title=dict(\n",
+ " text=\"Gravity\",\n",
+ " font=dict(\n",
+ " color=\"white\"\n",
+ " )\n",
+ " )\n",
+ " ),\n",
+ " bgcolor=\"rgb(20, 24, 54)\"\n",
+ " )\n",
+ ")\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "063e7747",
+ "metadata": {},
+ "source": [
+ "#### Edit the Colorbar\n",
+ "\n",
+ "Plot planets' distance from sun, density, and gravity with bubble size based on planet size"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b5e22291",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "planets = ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto']\n",
+ "temperatures = [167, 464, 15, -20, -65, -110, -140, -195, -200, -225]\n",
+ "distance_from_sun = [57.9, 108.2, 149.6, 227.9, 778.6, 1433.5, 2872.5, 4495.1, 5906.4]\n",
+ "density = [5427, 5243, 5514, 3933, 1326, 687, 1271, 1638, 2095]\n",
+ "gravity = [3.7, 8.9, 9.8, 3.7, 23.1, 9.0, 8.7, 11.0, 0.7]\n",
+ "planet_diameter = [4879, 12104, 12756, 6792, 142984, 120536, 51118, 49528, 2370]\n",
+ "\n",
+ "# Create trace, sizing bubbles by planet diameter\n",
+ "fig = go.Figure(go.Scatter3d(\n",
+ " x = distance_from_sun,\n",
+ " y = density,\n",
+ " z = gravity,\n",
+ " text = planets,\n",
+ " mode = 'markers',\n",
+ " marker = dict(\n",
+ " sizemode = 'diameter',\n",
+ " sizeref = 750, # info on sizeref: https://plotly.com/python/reference/scatter/#scatter-marker-sizeref\n",
+ " size = planet_diameter,\n",
+ " color = temperatures,\n",
+ " colorbar_title = 'Mean
Temperature',\n",
+ " colorscale=[[0, 'rgb(5, 10, 172)'], [.3, 'rgb(255, 255, 255)'], [1, 'rgb(178, 10, 28)']]\n",
+ " )\n",
+ "))\n",
+ "\n",
+ "fig.update_layout(\n",
+ " width=800,\n",
+ " height=800,\n",
+ " title=dict(text=\"Planets!\"),\n",
+ " scene=dict(\n",
+ " xaxis=dict(\n",
+ " title=dict(\n",
+ " text=\"Distance from Sun\",\n",
+ " font=dict(\n",
+ " color=\"white\"\n",
+ " )\n",
+ " )\n",
+ " ),\n",
+ " yaxis=dict(\n",
+ " title=dict(\n",
+ " text=\"Density\",\n",
+ " font=dict(\n",
+ " color=\"white\"\n",
+ " )\n",
+ " )\n",
+ " ),\n",
+ " zaxis=dict(\n",
+ " title=dict(\n",
+ " text=\"Gravity\",\n",
+ " font=dict(\n",
+ " color=\"white\"\n",
+ " )\n",
+ " )\n",
+ " ),\n",
+ " bgcolor=\"rgb(20, 24, 54)\"\n",
+ " )\n",
+ ")\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "14447a0c",
+ "metadata": {},
+ "source": [
+ "#### Reference\n",
+ "\n",
+ "See https://plotly.com/python/reference/scatter3d/ and https://plotly.com/python/reference/scatter/#scatter-marker-sizeref
for more information and chart attribute options!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5814eb68",
+ "metadata": {},
+ "source": [
+ "### What About Dash?\n",
+ "\n",
+ "[Dash](https://dash.plot.ly/) is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.\n",
+ "\n",
+ "Learn about how to install Dash at https://dash.plot.ly/installation.\n",
+ "\n",
+ "Everywhere in this page that you see `fig.show()`, you can display the same figure in a Dash application by passing it to the `figure` argument of the [`Graph` component](https://dash.plot.ly/dash-core-components/graph) from the built-in `dash_core_components` package like this:\n",
+ "\n",
+ "```python\n",
+ "import plotly.graph_objects as go # or plotly.express as px\n",
+ "fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)\n",
+ "# fig.add_trace( ... )\n",
+ "# fig.update_layout( ... )\n",
+ "\n",
+ "from dash import Dash, dcc, html\n",
+ "\n",
+ "app = Dash()\n",
+ "app.layout = html.Div([\n",
+ " dcc.Graph(figure=fig)\n",
+ "])\n",
+ "\n",
+ "app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "jupytext": {
+ "notebook_metadata_filter": "all"
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "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.11.10"
+ },
+ "plotly": {
+ "description": "How to make 3D Bubble Charts in Python with Plotly. Three examples of 3D Bubble Charts.",
+ "display_as": "3d_charts",
+ "language": "python",
+ "layout": "base",
+ "name": "3D Bubble Charts",
+ "order": 6,
+ "page_type": "u-guide",
+ "permalink": "python/3d-bubble-charts/",
+ "thumbnail": "thumbnail/3dbubble.jpg"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/3d-camera-controls.ipynb b/3d-camera-controls.ipynb
new file mode 100644
index 000000000..f1df22a9c
--- /dev/null
+++ b/3d-camera-controls.ipynb
@@ -0,0 +1,452 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "05128697",
+ "metadata": {},
+ "source": [
+ "### How camera controls work\n",
+ "\n",
+ "The camera position and direction is determined by three vectors: *up*, *center*, *eye*. Their coordinates refer to the 3-d domain, i.e., `(0, 0, 0)` is always the center of the domain, no matter data values.\n",
+ "The `eye` vector determines the position of the camera. The default is $(x=1.25, y=1.25, z=1.25)$.\n",
+ "\n",
+ "The `up` vector determines the `up` direction on the page. The default is $(x=0, y=0, z=1)$, that is, the z-axis points up.\n",
+ "\n",
+ "The projection of the `center` point lies at the center of the view. By default it is $(x=0, y=0, z=0)$."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cd46a1c4",
+ "metadata": {},
+ "source": [
+ "### Default parameters"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c604d207",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=40, r=0, l=20, b=20)\n",
+ ")\n",
+ "\n",
+ "name = 'default'\n",
+ "# Default parameters which are used when `layout.scene.camera` is not provided\n",
+ "camera = dict(\n",
+ " up=dict(x=0, y=0, z=1),\n",
+ " center=dict(x=0, y=0, z=0),\n",
+ " eye=dict(x=1.25, y=1.25, z=1.25)\n",
+ ")\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "293cb18e",
+ "metadata": {},
+ "source": [
+ "### Changing the camera position by setting the eye parameter\n",
+ "\n",
+ "#### Lower the View Point\n",
+ "\n",
+ "by setting `eye.z` to a smaller value."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8eec7d90",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=30, r=0, l=20, b=10)\n",
+ ")\n",
+ "\n",
+ "name = 'eye = (x:2, y:2, z:0.1)'\n",
+ "camera = dict(\n",
+ " eye=dict(x=2, y=2, z=0.1)\n",
+ ")\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f9202780",
+ "metadata": {},
+ "source": [
+ "#### X-Z plane\n",
+ "\n",
+ "set `eye.x` and `eye.z` to zero"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7ec7a384",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=30, r=0, l=20, b=10)\n",
+ ")\n",
+ "\n",
+ "name = 'eye = (x:0., y:2.5, z:0.)'\n",
+ "camera = dict(\n",
+ " eye=dict(x=0., y=2.5, z=0.)\n",
+ ")\n",
+ "\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2e46ab5b",
+ "metadata": {},
+ "source": [
+ "#### Y-Z plane"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2ab246a0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=30, r=0, l=20, b=10)\n",
+ ")\n",
+ "\n",
+ "name = 'eye = (x:2.5, y:0., z:0.)'\n",
+ "camera = dict(\n",
+ " eye=dict(x=2.5, y=0., z=0.)\n",
+ ")\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "962f286a",
+ "metadata": {},
+ "source": [
+ "#### View from Above (X-Y plane)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b372c3c8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=30, r=0, l=20, b=10)\n",
+ ")\n",
+ "\n",
+ "name = 'eye = (x:0., y:0., z:2.5)'\n",
+ "camera = dict(\n",
+ " eye=dict(x=0., y=0., z=2.5)\n",
+ ")\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b7f76db5",
+ "metadata": {},
+ "source": [
+ "#### Zooming In\n",
+ "... by placing the camera closer to the origin (`eye` with a smaller norm)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5a4beb95",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=30, r=0, l=20, b=10)\n",
+ ")\n",
+ "\n",
+ "name = 'eye = (x:0.1, y:0.1, z:1.5)'\n",
+ "camera = dict(\n",
+ " eye=dict(x=0.1, y=0.1, z=1.5)\n",
+ ")\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d8a31fda",
+ "metadata": {},
+ "source": [
+ "### Tilting the camera vertical by setting the up parameter\n",
+ "\n",
+ "Tilt camera by changing the `up` vector: here the vertical of the view points in the `x` direction."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "98b92a24",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=30, r=0, l=20, b=10)\n",
+ ")\n",
+ "\n",
+ "name = 'eye = (x:0., y:2.5, z:0.), point along x'\n",
+ "camera = dict(\n",
+ " up=dict(x=1, y=0., z=0),\n",
+ " eye=dict(x=0., y=2.5, z=0.)\n",
+ ")\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2de56bf0",
+ "metadata": {},
+ "source": [
+ "Note when `up` does not correspond to the direction of an axis, you also need to set `layout.scene.dragmode='orbit'`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0689c113",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import math\n",
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=30, r=0, l=20, b=10)\n",
+ ")\n",
+ "\n",
+ "angle = math.pi / 4 # 45 degrees\n",
+ "\n",
+ "name = 'vertical is along y+z'\n",
+ "camera = dict(\n",
+ " up=dict(x=0, y=math.cos(angle), z=math.sin(angle)),\n",
+ " eye=dict(x=2, y=0, z=0)\n",
+ ")\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, scene_dragmode='orbit', title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c8da7f0f",
+ "metadata": {},
+ "source": [
+ "### Changing the focal point by setting center\n",
+ "\n",
+ "You can change the focal point (a point which projection lies at the center of the view) by setting the `center` parameter of `camera`. Note how a part of the data is cropped below because the camera is looking up."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fa6b1137",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "\n",
+ "# Read data from a csv\n",
+ "z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')\n",
+ "\n",
+ "fig = go.Figure(data=go.Surface(z=z_data, showscale=False))\n",
+ "fig.update_layout(\n",
+ " title=dict(text='Mt Bruno Elevation'),\n",
+ " width=400, height=400,\n",
+ " margin=dict(t=25, r=0, l=20, b=30)\n",
+ ")\n",
+ "\n",
+ "name = 'looking up'\n",
+ "camera = dict(\n",
+ " center=dict(x=0, y=0, z=0.7))\n",
+ "\n",
+ "\n",
+ "fig.update_layout(scene_camera=camera, title=name)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2183cfd9",
+ "metadata": {},
+ "source": [
+ "#### Reference"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "347966eb",
+ "metadata": {},
+ "source": [
+ "See https://plotly.com/python/reference/layout/scene/#layout-scene-camera for more information and chart attribute options!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e138cbc8",
+ "metadata": {},
+ "source": [
+ "### What About Dash?\n",
+ "\n",
+ "[Dash](https://dash.plot.ly/) is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.\n",
+ "\n",
+ "Learn about how to install Dash at https://dash.plot.ly/installation.\n",
+ "\n",
+ "Everywhere in this page that you see `fig.show()`, you can display the same figure in a Dash application by passing it to the `figure` argument of the [`Graph` component](https://dash.plot.ly/dash-core-components/graph) from the built-in `dash_core_components` package like this:\n",
+ "\n",
+ "```python\n",
+ "import plotly.graph_objects as go # or plotly.express as px\n",
+ "fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)\n",
+ "# fig.add_trace( ... )\n",
+ "# fig.update_layout( ... )\n",
+ "\n",
+ "from dash import Dash, dcc, html\n",
+ "\n",
+ "app = Dash()\n",
+ "app.layout = html.Div([\n",
+ " dcc.Graph(figure=fig)\n",
+ "])\n",
+ "\n",
+ "app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "jupytext": {
+ "notebook_metadata_filter": "all"
+ },
+ "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.7.3"
+ },
+ "plotly": {
+ "description": "How to Control the Camera in your 3D Charts in Python with Plotly.",
+ "display_as": "3d_charts",
+ "language": "python",
+ "layout": "base",
+ "name": "3D Camera Controls",
+ "order": 5,
+ "permalink": "python/3d-camera-controls/",
+ "thumbnail": "thumbnail/3d-camera-controls.jpg"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/3d-isosurface-plots.ipynb b/3d-isosurface-plots.ipynb
new file mode 100644
index 000000000..75c5c8384
--- /dev/null
+++ b/3d-isosurface-plots.ipynb
@@ -0,0 +1,375 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ed53c539",
+ "metadata": {},
+ "source": [
+ "With ``go.Isosurface``, you can plot [isosurface contours](https://en.wikipedia.org/wiki/Isosurface) of a scalar field ``value``, which is defined on ``x``, ``y`` and ``z`` coordinates.\n",
+ "\n",
+ "#### Basic Isosurface\n",
+ "\n",
+ "In this first example, we plot the isocontours of values ``isomin=2`` and ``isomax=6``. In addition, portions of the sides of the coordinate domains for which the value is between ``isomin`` and ``isomax`` (named the ``caps``) are colored. Please rotate the figure to visualize both the internal surfaces and the caps surfaces on the sides."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "40e0cc1c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "\n",
+ "fig= go.Figure(data=go.Isosurface(\n",
+ " x=[0,0,0,0,1,1,1,1],\n",
+ " y=[1,0,1,0,1,0,1,0],\n",
+ " z=[1,1,0,0,1,1,0,0],\n",
+ " value=[1,2,3,4,5,6,7,8],\n",
+ " isomin=2,\n",
+ " isomax=6,\n",
+ "))\n",
+ "\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "86b4e156",
+ "metadata": {},
+ "source": [
+ "### Removing caps when visualizing isosurfaces\n",
+ "\n",
+ "For a clearer visualization of internal surfaces, it is possible to remove the caps (color-coded surfaces on the sides of the visualization domain). Caps are visible by default."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "832b4ca3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "X, Y, Z = np.mgrid[-5:5:40j, -5:5:40j, -5:5:40j]\n",
+ "\n",
+ "# ellipsoid\n",
+ "values = X * X * 0.5 + Y * Y + Z * Z * 2\n",
+ "\n",
+ "fig = go.Figure(data=go.Isosurface(\n",
+ " x=X.flatten(),\n",
+ " y=Y.flatten(),\n",
+ " z=Z.flatten(),\n",
+ " value=values.flatten(),\n",
+ " isomin=10,\n",
+ " isomax=40,\n",
+ " caps=dict(x_show=False, y_show=False)\n",
+ " ))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5aed1772",
+ "metadata": {},
+ "source": [
+ "### Modifying the number of isosurfaces"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "681f666a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "X, Y, Z = np.mgrid[-5:5:40j, -5:5:40j, -5:5:40j]\n",
+ "\n",
+ "# ellipsoid\n",
+ "values = X * X * 0.5 + Y * Y + Z * Z * 2\n",
+ "\n",
+ "fig = go.Figure(data=go.Isosurface(\n",
+ " x=X.flatten(),\n",
+ " y=Y.flatten(),\n",
+ " z=Z.flatten(),\n",
+ " value=values.flatten(),\n",
+ " isomin=10,\n",
+ " isomax=50,\n",
+ " surface_count=5, # number of isosurfaces, 2 by default: only min and max\n",
+ " colorbar_nticks=5, # colorbar ticks correspond to isosurface values\n",
+ " caps=dict(x_show=False, y_show=False)\n",
+ " ))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "44494531",
+ "metadata": {},
+ "source": [
+ "### Changing the opacity of isosurfaces"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14fc412a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "X, Y, Z = np.mgrid[-5:5:40j, -5:5:40j, -5:5:40j]\n",
+ "\n",
+ "# ellipsoid\n",
+ "values = X * X * 0.5 + Y * Y + Z * Z * 2\n",
+ "\n",
+ "fig = go.Figure(data=go.Isosurface(\n",
+ " x=X.flatten(),\n",
+ " y=Y.flatten(),\n",
+ " z=Z.flatten(),\n",
+ " value=values.flatten(),\n",
+ " opacity=0.6,\n",
+ " isomin=10,\n",
+ " isomax=50,\n",
+ " surface_count=3,\n",
+ " caps=dict(x_show=False, y_show=False)\n",
+ " ))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0127c47f",
+ "metadata": {},
+ "source": [
+ "#### Isosurface with Additional Slices\n",
+ "\n",
+ "Here we visualize slices parallel to the axes on top of isosurfaces. For a clearer visualization, the `fill` ratio of isosurfaces is decreased below 1 (completely filled)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6541dba9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "X, Y, Z = np.mgrid[-5:5:40j, -5:5:40j, -5:5:40j]\n",
+ "\n",
+ "# ellipsoid\n",
+ "values = X * X * 0.5 + Y * Y + Z * Z * 2\n",
+ "\n",
+ "fig = go.Figure(data=go.Isosurface(\n",
+ " x=X.flatten(),\n",
+ " y=Y.flatten(),\n",
+ " z=Z.flatten(),\n",
+ " value=values.flatten(),\n",
+ " isomin=5,\n",
+ " isomax=50,\n",
+ " surface_fill=0.4,\n",
+ " caps=dict(x_show=False, y_show=False),\n",
+ " slices_z=dict(show=True, locations=[-1, -3,]),\n",
+ " slices_y=dict(show=True, locations=[0]),\n",
+ " ))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "15037375",
+ "metadata": {},
+ "source": [
+ "#### Multiple Isosurfaces with Caps"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "77e979e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "X, Y, Z = np.mgrid[-5:5:40j, -5:5:40j, 0:5:20j]\n",
+ "\n",
+ "values = X * X * 0.5 + Y * Y + Z * Z * 2\n",
+ "\n",
+ "fig = go.Figure(data=go.Isosurface(\n",
+ " x=X.flatten(),\n",
+ " y=Y.flatten(),\n",
+ " z=Z.flatten(),\n",
+ " value=values.flatten(),\n",
+ " isomin=30,\n",
+ " isomax=50,\n",
+ " surface=dict(count=3, fill=0.7, pattern='odd'),\n",
+ " caps=dict(x_show=True, y_show=True),\n",
+ " ))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2e60868f",
+ "metadata": {},
+ "source": [
+ "### Changing the default colorscale of isosurfaces"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "01cb6941",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "X, Y, Z = np.mgrid[-5:5:40j, -5:5:40j, -5:5:40j]\n",
+ "\n",
+ "# ellipsoid\n",
+ "values = X * X * 0.5 + Y * Y + Z * Z * 2\n",
+ "\n",
+ "fig = go.Figure(data=go.Isosurface(\n",
+ " x=X.flatten(),\n",
+ " y=Y.flatten(),\n",
+ " z=Z.flatten(),\n",
+ " value=values.flatten(),\n",
+ " colorscale='BlueRed',\n",
+ " isomin=10,\n",
+ " isomax=50,\n",
+ " surface_count=3,\n",
+ " caps=dict(x_show=False, y_show=False)\n",
+ " ))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5fb22106",
+ "metadata": {},
+ "source": [
+ "### Customizing the layout and appearance of isosurface plots"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "05f9d380",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "X, Y, Z = np.mgrid[-5:5:40j, -5:5:40j, 0:5:20j]\n",
+ "\n",
+ "values = X * X * 0.5 + Y * Y + Z * Z * 2\n",
+ "\n",
+ "fig = go.Figure(data=go.Isosurface(\n",
+ " x=X.flatten(),\n",
+ " y=Y.flatten(),\n",
+ " z=Z.flatten(),\n",
+ " value=values.flatten(),\n",
+ " isomin=30,\n",
+ " isomax=50,\n",
+ " surface=dict(count=3, fill=0.7, pattern='odd'),\n",
+ " showscale=False, # remove colorbar\n",
+ " caps=dict(x_show=True, y_show=True),\n",
+ " ))\n",
+ "\n",
+ "fig.update_layout(\n",
+ " margin=dict(t=0, l=0, b=0), # tight layout\n",
+ " scene_camera_eye=dict(x=1.86, y=0.61, z=0.98))\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5da8d6bc",
+ "metadata": {},
+ "source": [
+ "#### Reference\n",
+ "See https://plotly.com/python/reference/isosurface/ for more information and chart attribute options!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e6a7d4af",
+ "metadata": {},
+ "source": [
+ "### What About Dash?\n",
+ "\n",
+ "[Dash](https://dash.plot.ly/) is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.\n",
+ "\n",
+ "Learn about how to install Dash at https://dash.plot.ly/installation.\n",
+ "\n",
+ "Everywhere in this page that you see `fig.show()`, you can display the same figure in a Dash application by passing it to the `figure` argument of the [`Graph` component](https://dash.plot.ly/dash-core-components/graph) from the built-in `dash_core_components` package like this:\n",
+ "\n",
+ "```python\n",
+ "import plotly.graph_objects as go # or plotly.express as px\n",
+ "fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)\n",
+ "# fig.add_trace( ... )\n",
+ "# fig.update_layout( ... )\n",
+ "\n",
+ "from dash import Dash, dcc, html\n",
+ "\n",
+ "app = Dash()\n",
+ "app.layout = html.Div([\n",
+ " dcc.Graph(figure=fig)\n",
+ "])\n",
+ "\n",
+ "app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "jupytext": {
+ "notebook_metadata_filter": "all"
+ },
+ "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.7.3"
+ },
+ "plotly": {
+ "description": "How to make 3D Isosurface Plots in Python with Plotly.",
+ "display_as": "3d_charts",
+ "language": "python",
+ "layout": "base",
+ "name": "3D Isosurface Plots",
+ "order": 10,
+ "page_type": "u-guide",
+ "permalink": "python/3d-isosurface-plots/",
+ "redirect_from": "python/isosurfaces-with-marching-cubes/",
+ "thumbnail": "thumbnail/isosurface.jpg"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/3d-line-plots.ipynb b/3d-line-plots.ipynb
new file mode 100644
index 000000000..452033bd5
--- /dev/null
+++ b/3d-line-plots.ipynb
@@ -0,0 +1,191 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "245e34e9",
+ "metadata": {},
+ "source": [
+ "### 3D Line plot with Plotly Express"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "084c05da",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.gapminder().query(\"country=='Brazil'\")\n",
+ "fig = px.line_3d(df, x=\"gdpPercap\", y=\"pop\", z=\"year\")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3757d751",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.express as px\n",
+ "df = px.data.gapminder().query(\"continent=='Europe'\")\n",
+ "fig = px.line_3d(df, x=\"gdpPercap\", y=\"pop\", z=\"year\", color='country')\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "849cc244",
+ "metadata": {},
+ "source": [
+ "#### 3D Line Plot of Brownian Motion\n",
+ "\n",
+ "Here we represent a trajectory in 3D."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "720fa984",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "\n",
+ "rs = np.random.RandomState()\n",
+ "rs.seed(0)\n",
+ "\n",
+ "def brownian_motion(T = 1, N = 100, mu = 0.1, sigma = 0.01, S0 = 20):\n",
+ " dt = float(T)/N\n",
+ " t = np.linspace(0, T, N)\n",
+ " W = rs.standard_normal(size = N)\n",
+ " W = np.cumsum(W)*np.sqrt(dt) # standard brownian motion\n",
+ " X = (mu-0.5*sigma**2)*t + sigma*W\n",
+ " S = S0*np.exp(X) # geometric brownian motion\n",
+ " return S\n",
+ "\n",
+ "dates = pd.date_range('2012-01-01', '2013-02-22')\n",
+ "T = (dates.max()-dates.min()).days / 365\n",
+ "N = dates.size\n",
+ "start_price = 100\n",
+ "y = brownian_motion(T, N, sigma=0.1, S0=start_price)\n",
+ "z = brownian_motion(T, N, sigma=0.1, S0=start_price)\n",
+ "\n",
+ "fig = go.Figure(data=go.Scatter3d(\n",
+ " x=dates, y=y, z=z,\n",
+ " marker=dict(\n",
+ " size=4,\n",
+ " color=z,\n",
+ " colorscale='Viridis',\n",
+ " ),\n",
+ " line=dict(\n",
+ " color='darkblue',\n",
+ " width=2\n",
+ " )\n",
+ "))\n",
+ "\n",
+ "fig.update_layout(\n",
+ " width=800,\n",
+ " height=700,\n",
+ " autosize=False,\n",
+ " scene=dict(\n",
+ " camera=dict(\n",
+ " up=dict(\n",
+ " x=0,\n",
+ " y=0,\n",
+ " z=1\n",
+ " ),\n",
+ " eye=dict(\n",
+ " x=0,\n",
+ " y=1.0707,\n",
+ " z=1,\n",
+ " )\n",
+ " ),\n",
+ " aspectratio = dict( x=1, y=1, z=0.7 ),\n",
+ " aspectmode = 'manual'\n",
+ " ),\n",
+ ")\n",
+ "\n",
+ "fig.show()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "be3134b2",
+ "metadata": {},
+ "source": [
+ "#### Reference\n",
+ "\n",
+ "See [function reference for `px.(line_3d)`](https://plotly.com/python-api-reference/generated/plotly.express.line_3d) or https://plotly.com/python/reference/scatter3d/#scatter3d-marker-line for more information and chart attribute options!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "05ca706c",
+ "metadata": {},
+ "source": [
+ "### What About Dash?\n",
+ "\n",
+ "[Dash](https://dash.plot.ly/) is an open-source framework for building analytical applications, with no Javascript required, and it is tightly integrated with the Plotly graphing library.\n",
+ "\n",
+ "Learn about how to install Dash at https://dash.plot.ly/installation.\n",
+ "\n",
+ "Everywhere in this page that you see `fig.show()`, you can display the same figure in a Dash application by passing it to the `figure` argument of the [`Graph` component](https://dash.plot.ly/dash-core-components/graph) from the built-in `dash_core_components` package like this:\n",
+ "\n",
+ "```python\n",
+ "import plotly.graph_objects as go # or plotly.express as px\n",
+ "fig = go.Figure() # or any Plotly Express function e.g. px.bar(...)\n",
+ "# fig.add_trace( ... )\n",
+ "# fig.update_layout( ... )\n",
+ "\n",
+ "from dash import Dash, dcc, html\n",
+ "\n",
+ "app = Dash()\n",
+ "app.layout = html.Div([\n",
+ " dcc.Graph(figure=fig)\n",
+ "])\n",
+ "\n",
+ "app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "jupytext": {
+ "notebook_metadata_filter": "all"
+ },
+ "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.7.3"
+ },
+ "plotly": {
+ "description": "How to make 3D Line Plots",
+ "display_as": "3d_charts",
+ "language": "python",
+ "layout": "base",
+ "name": "3D Line Plots",
+ "order": 7,
+ "page_type": "u-guide",
+ "permalink": "python/3d-line-plots/",
+ "thumbnail": "thumbnail/3d-line.jpg"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/3d-mesh.ipynb b/3d-mesh.ipynb
new file mode 100644
index 000000000..ca45f5e54
--- /dev/null
+++ b/3d-mesh.ipynb
@@ -0,0 +1,307 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "9d7fea44",
+ "metadata": {},
+ "source": [
+ "### Simple 3D Mesh example ###\n",
+ "\n",
+ "`go.Mesh3d` draws a 3D set of triangles with vertices given by `x`, `y` and `z`. If only coordinates are given, an algorithm such as [Delaunay triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation) is used to draw the triangles. Otherwise the triangles can be given using the `i`, `j` and `k` parameters (see examples below)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9f1a44ed",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "# Download data set from plotly repo\n",
+ "pts = np.loadtxt(np.DataSource().open('https://raw.githubusercontent.com/plotly/datasets/master/mesh_dataset.txt'))\n",
+ "x, y, z = pts.T\n",
+ "\n",
+ "fig = go.Figure(data=[go.Mesh3d(x=x, y=y, z=z, color='lightpink', opacity=0.50)])\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "17893fbc",
+ "metadata": {},
+ "source": [
+ "### 3D Mesh example with Alphahull"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bc0241aa",
+ "metadata": {},
+ "source": [
+ "The `alphahull` parameter sets the shape of the mesh. If the value is -1 (default value) then [Delaunay triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation) is used. If >0 then the [alpha-shape algorithm](https://en.wikipedia.org/wiki/Alpha_shape) is used. If 0, the [convex hull](https://en.wikipedia.org/wiki/Convex_hull) is represented (resulting in a convex body)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "00680451",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.graph_objects as go\n",
+ "import numpy as np\n",
+ "\n",
+ "pts = np.loadtxt(np.DataSource().open('https://raw.githubusercontent.com/plotly/datasets/master/mesh_dataset.txt'))\n",
+ "x, y, z = pts.T\n",
+ "\n",
+ "fig = go.Figure(data=[go.Mesh3d(x=x, y=y, z=z,\n",
+ " alphahull=5,\n",
+ " opacity=0.4,\n",
+ " color='cyan')])\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "371bfe89",
+ "metadata": {},
+ "source": [
+ "### 3D Mesh in Dash\n",
+ "\n",
+ "[Dash](https://plotly.com/dash/) is the best way to build analytical apps in Python using Plotly figures. To run the app below, run `pip install dash`, click \"Download\" to get the code and run `python app.py`.\n",
+ "\n",
+ "Get started with [the official Dash docs](https://dash.plotly.com/installation) and **learn how to effortlessly [style](https://plotly.com/dash/design-kit/) & [deploy](https://plotly.com/dash/app-manager/) apps like this with Dash Enterprise.**\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "aac1af9e",
+ "metadata": {
+ "hide_code": true
+ },
+ "outputs": [],
+ "source": [
+ "from IPython.display import IFrame\n",
+ "snippet_url = 'https://python-docs-dash-snippets.herokuapp.com/python-docs-dash-snippets/'\n",
+ "IFrame(snippet_url + '3d-mesh', width='100%', height=1200)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "408c13af",
+ "metadata": {},
+ "source": [
+ "
Sign up for Dash Club → Free cheat sheets plus updates from Chris Parmer and Adam Schroeder delivered to your inbox every two months. Includes tips and tricks, community apps, and deep dives into the Dash architecture.\n", + "Join now.
Sign up for Dash Club → Free cheat sheets plus updates from Chris Parmer and Adam Schroeder delivered to your inbox every two months. Includes tips and tricks, community apps, and deep dives into the Dash architecture.\n", + "Join now.