xarray-plotly 0.0.2__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. xarray_plotly-0.0.4/.github/dependabot.yml +25 -0
  2. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/.github/workflows/ci.yml +3 -3
  3. xarray_plotly-0.0.4/.github/workflows/dependabot-auto-merge.yml +24 -0
  4. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/.github/workflows/docs.yml +2 -2
  5. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/.github/workflows/release.yml +2 -2
  6. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/PKG-INFO +17 -12
  7. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/README.md +4 -0
  8. xarray_plotly-0.0.4/docs/examples/dimensions.ipynb +232 -0
  9. xarray_plotly-0.0.4/docs/examples/figure.ipynb +236 -0
  10. xarray_plotly-0.0.4/docs/examples/kwargs.ipynb +251 -0
  11. xarray_plotly-0.0.4/docs/examples/plot-types.ipynb +170 -0
  12. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/docs/getting-started.ipynb +30 -34
  13. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/docs/index.md +2 -1
  14. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/mkdocs.yml +3 -1
  15. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/pyproject.toml +12 -11
  16. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/tests/test_accessor.py +89 -3
  17. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly/__init__.py +36 -9
  18. xarray_plotly-0.0.4/xarray_plotly/accessor.py +586 -0
  19. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly/config.py +1 -0
  20. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly/plotting.py +61 -0
  21. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly.egg-info/PKG-INFO +17 -12
  22. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly.egg-info/SOURCES.txt +5 -1
  23. xarray_plotly-0.0.4/xarray_plotly.egg-info/requires.txt +19 -0
  24. xarray_plotly-0.0.2/docs/examples/advanced.ipynb +0 -425
  25. xarray_plotly-0.0.2/docs/examples/plot-types.ipynb +0 -381
  26. xarray_plotly-0.0.2/xarray_plotly/accessor.py +0 -275
  27. xarray_plotly-0.0.2/xarray_plotly.egg-info/requires.txt +0 -18
  28. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/.gitignore +0 -0
  29. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/.pre-commit-config.yaml +0 -0
  30. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/CONTRIBUTING.md +0 -0
  31. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/LICENSE +0 -0
  32. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/docs/api.md +0 -0
  33. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/setup.cfg +0 -0
  34. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/tests/__init__.py +0 -0
  35. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/tests/test_common.py +0 -0
  36. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/tests/test_config.py +0 -0
  37. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly/common.py +0 -0
  38. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly/py.typed +0 -0
  39. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly.egg-info/dependency_links.txt +0 -0
  40. {xarray_plotly-0.0.2 → xarray_plotly-0.0.4}/xarray_plotly.egg-info/top_level.txt +0 -0
@@ -0,0 +1,25 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ groups:
8
+ dev-dependencies:
9
+ patterns:
10
+ - "pytest*"
11
+ - "mypy"
12
+ - "ruff"
13
+ - "pre-commit"
14
+ - "nbstripout"
15
+ docs-dependencies:
16
+ patterns:
17
+ - "mkdocs*"
18
+ - "pooch"
19
+ - "netcdf4"
20
+ - "jupyter"
21
+
22
+ - package-ecosystem: "github-actions"
23
+ directory: "/"
24
+ schedule:
25
+ interval: "weekly"
@@ -14,10 +14,10 @@ jobs:
14
14
  python-version: ["3.10", "3.11", "3.12", "3.13"]
15
15
 
16
16
  steps:
17
- - uses: actions/checkout@v4
17
+ - uses: actions/checkout@v6
18
18
 
19
19
  - name: Install uv
20
- uses: astral-sh/setup-uv@v4
20
+ uses: astral-sh/setup-uv@v7
21
21
 
22
22
  - name: Set up Python ${{ matrix.python-version }}
23
23
  run: uv python install ${{ matrix.python-version }}
@@ -35,7 +35,7 @@ jobs:
35
35
  run: uv run pytest --cov=xarray_plotly --cov-report=xml
36
36
 
37
37
  - name: Upload coverage
38
- uses: codecov/codecov-action@v4
38
+ uses: codecov/codecov-action@v5
39
39
  if: matrix.python-version == '3.12'
40
40
  with:
41
41
  token: ${{ secrets.CODECOV_TOKEN }}
@@ -0,0 +1,24 @@
1
+ name: Dependabot auto-merge
2
+ on: pull_request
3
+
4
+ permissions:
5
+ contents: write
6
+ pull-requests: write
7
+
8
+ jobs:
9
+ dependabot:
10
+ runs-on: ubuntu-latest
11
+ if: github.actor == 'dependabot[bot]'
12
+ steps:
13
+ - name: Dependabot metadata
14
+ id: metadata
15
+ uses: dependabot/fetch-metadata@v2
16
+ with:
17
+ github-token: "${{ secrets.GITHUB_TOKEN }}"
18
+
19
+ - name: Auto-merge minor and patch updates
20
+ if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor'
21
+ run: gh pr merge --auto --squash "$PR_URL"
22
+ env:
23
+ PR_URL: ${{ github.event.pull_request.html_url }}
24
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -14,10 +14,10 @@ jobs:
14
14
  runs-on: ubuntu-latest
15
15
 
16
16
  steps:
17
- - uses: actions/checkout@v4
17
+ - uses: actions/checkout@v6
18
18
 
19
19
  - name: Install uv
20
- uses: astral-sh/setup-uv@v4
20
+ uses: astral-sh/setup-uv@v7
21
21
 
22
22
  - name: Install dependencies
23
23
  run: uv sync --extra docs
@@ -13,10 +13,10 @@ jobs:
13
13
  contents: write # for creating GitHub release
14
14
 
15
15
  steps:
16
- - uses: actions/checkout@v4
16
+ - uses: actions/checkout@v6
17
17
 
18
18
  - name: Install uv
19
- uses: astral-sh/setup-uv@v4
19
+ uses: astral-sh/setup-uv@v7
20
20
 
21
21
  - name: Build package
22
22
  run: uv build
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xarray_plotly
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Interactive Plotly Express plotting accessor for xarray
5
5
  Author: Felix
6
6
  License: MIT
@@ -25,18 +25,19 @@ Requires-Dist: xarray>=2023.1.0
25
25
  Requires-Dist: plotly>=5.0.0
26
26
  Requires-Dist: pandas>=1.5.0
27
27
  Provides-Extra: dev
28
- Requires-Dist: pytest>=7.0; extra == "dev"
29
- Requires-Dist: pytest-cov>=4.0; extra == "dev"
30
- Requires-Dist: mypy>=1.0; extra == "dev"
31
- Requires-Dist: ruff>=0.4; extra == "dev"
32
- Requires-Dist: pre-commit>=3.0; extra == "dev"
33
- Requires-Dist: nbstripout>=0.6; extra == "dev"
28
+ Requires-Dist: pytest==9.0.2; extra == "dev"
29
+ Requires-Dist: pytest-cov==7.0.0; extra == "dev"
30
+ Requires-Dist: mypy==1.19.1; extra == "dev"
31
+ Requires-Dist: ruff==0.14.11; extra == "dev"
32
+ Requires-Dist: pre-commit==4.5.1; extra == "dev"
33
+ Requires-Dist: nbstripout==0.8.2; extra == "dev"
34
34
  Provides-Extra: docs
35
- Requires-Dist: mkdocs>=1.5; extra == "docs"
36
- Requires-Dist: mkdocs-material>=9.0; extra == "docs"
37
- Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
38
- Requires-Dist: mkdocs-jupyter>=0.24; extra == "docs"
39
- Requires-Dist: mkdocs-plotly-plugin>=0.1; extra == "docs"
35
+ Requires-Dist: mkdocs==1.6.1; extra == "docs"
36
+ Requires-Dist: mkdocs-material==9.7.1; extra == "docs"
37
+ Requires-Dist: mkdocstrings[python]==1.0.0; extra == "docs"
38
+ Requires-Dist: mkdocs-jupyter==0.25.1; extra == "docs"
39
+ Requires-Dist: mkdocs-plotly-plugin==0.1.3; extra == "docs"
40
+ Requires-Dist: jupyter==1.1.1; extra == "docs"
40
41
  Dynamic: license-file
41
42
 
42
43
  # xarray_plotly
@@ -45,7 +46,9 @@ Dynamic: license-file
45
46
 
46
47
  [![PyPI version](https://badge.fury.io/py/xarray_plotly.svg)](https://badge.fury.io/py/xarray_plotly)
47
48
  [![Python](https://img.shields.io/pypi/pyversions/xarray_plotly.svg)](https://pypi.org/project/xarray_plotly/)
49
+ [![CI](https://github.com/FBumann/xarray_plotly/actions/workflows/ci.yml/badge.svg)](https://github.com/FBumann/xarray_plotly/actions)
48
50
  [![Docs](https://img.shields.io/badge/docs-fbumann.github.io-blue)](https://fbumann.github.io/xarray_plotly/)
51
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
49
52
 
50
53
  ## Installation
51
54
 
@@ -75,6 +78,8 @@ from xarray_plotly import xpx
75
78
  fig = xpx(da).line()
76
79
  ```
77
80
 
81
+ **Why `xpx()`?** The accessor (`da.plotly`) works but IDEs can't provide code completion for it. This is because xarray accessors are registered dynamically at runtime, making them invisible to static type checkers. The `xpx()` function provides the same functionality with full IDE support. This limitation could only be solved by xarray itself, if at all — it may be a fundamental Python limitation.
82
+
78
83
  ## Documentation
79
84
 
80
85
  Full documentation: [https://fbumann.github.io/xarray_plotly](https://fbumann.github.io/xarray_plotly)
@@ -4,7 +4,9 @@
4
4
 
5
5
  [![PyPI version](https://badge.fury.io/py/xarray_plotly.svg)](https://badge.fury.io/py/xarray_plotly)
6
6
  [![Python](https://img.shields.io/pypi/pyversions/xarray_plotly.svg)](https://pypi.org/project/xarray_plotly/)
7
+ [![CI](https://github.com/FBumann/xarray_plotly/actions/workflows/ci.yml/badge.svg)](https://github.com/FBumann/xarray_plotly/actions)
7
8
  [![Docs](https://img.shields.io/badge/docs-fbumann.github.io-blue)](https://fbumann.github.io/xarray_plotly/)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
10
 
9
11
  ## Installation
10
12
 
@@ -34,6 +36,8 @@ from xarray_plotly import xpx
34
36
  fig = xpx(da).line()
35
37
  ```
36
38
 
39
+ **Why `xpx()`?** The accessor (`da.plotly`) works but IDEs can't provide code completion for it. This is because xarray accessors are registered dynamically at runtime, making them invisible to static type checkers. The `xpx()` function provides the same functionality with full IDE support. This limitation could only be solved by xarray itself, if at all — it may be a fundamental Python limitation.
40
+
37
41
  ## Documentation
38
42
 
39
43
  Full documentation: [https://fbumann.github.io/xarray_plotly](https://fbumann.github.io/xarray_plotly)
@@ -0,0 +1,232 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Dimensions, Facets & Animation\n",
8
+ "\n",
9
+ "How to control which dimensions map to which visual properties."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "import plotly.express as px\n",
19
+ "import xarray as xr\n",
20
+ "\n",
21
+ "from xarray_plotly import config, xpx\n",
22
+ "\n",
23
+ "config.notebook()"
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "code",
28
+ "execution_count": null,
29
+ "metadata": {},
30
+ "outputs": [],
31
+ "source": [
32
+ "# Sample data: 2D\n",
33
+ "df = px.data.stocks().set_index(\"date\")\n",
34
+ "df.index = df.index.astype(\"datetime64[ns]\")\n",
35
+ "\n",
36
+ "stocks = xr.DataArray(\n",
37
+ " df.values,\n",
38
+ " dims=[\"date\", \"company\"],\n",
39
+ " coords={\"date\": df.index, \"company\": df.columns.tolist()},\n",
40
+ " name=\"price\",\n",
41
+ ")\n",
42
+ "\n",
43
+ "# Sample data: 3D\n",
44
+ "df_gap = px.data.gapminder()\n",
45
+ "countries = [\"United States\", \"China\", \"Germany\", \"Brazil\"]\n",
46
+ "metrics = [\"lifeExp\", \"gdpPercap\"]\n",
47
+ "\n",
48
+ "arrays = []\n",
49
+ "for metric in metrics:\n",
50
+ " df_pivot = df_gap[df_gap[\"country\"].isin(countries)].pivot(\n",
51
+ " index=\"year\", columns=\"country\", values=metric\n",
52
+ " )\n",
53
+ " arrays.append(df_pivot.values)\n",
54
+ "\n",
55
+ "data_3d = xr.DataArray(\n",
56
+ " arrays,\n",
57
+ " dims=[\"metric\", \"year\", \"country\"],\n",
58
+ " coords={\n",
59
+ " \"metric\": metrics,\n",
60
+ " \"year\": df_pivot.index.tolist(),\n",
61
+ " \"country\": df_pivot.columns.tolist(),\n",
62
+ " },\n",
63
+ " name=\"value\",\n",
64
+ ")"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "markdown",
69
+ "metadata": {},
70
+ "source": [
71
+ "## Default Dimension Assignment\n",
72
+ "\n",
73
+ "Dimensions are assigned to slots in order:"
74
+ ]
75
+ },
76
+ {
77
+ "cell_type": "code",
78
+ "execution_count": null,
79
+ "metadata": {},
80
+ "outputs": [],
81
+ "source": [
82
+ "# date → x, company → color\n",
83
+ "xpx(stocks).line()"
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "markdown",
88
+ "metadata": {},
89
+ "source": [
90
+ "## Explicit Assignment\n",
91
+ "\n",
92
+ "Override the defaults by specifying which dimension goes where:"
93
+ ]
94
+ },
95
+ {
96
+ "cell_type": "code",
97
+ "execution_count": null,
98
+ "metadata": {},
99
+ "outputs": [],
100
+ "source": [
101
+ "# Swap: company → x, date → color\n",
102
+ "xpx(stocks.isel(date=[0, 50, 100])).bar(x=\"company\", color=\"date\")"
103
+ ]
104
+ },
105
+ {
106
+ "cell_type": "markdown",
107
+ "metadata": {},
108
+ "source": [
109
+ "## Skipping Slots with None\n",
110
+ "\n",
111
+ "Use `None` to skip a slot, so dimensions shift to the next available slot:"
112
+ ]
113
+ },
114
+ {
115
+ "cell_type": "code",
116
+ "execution_count": null,
117
+ "metadata": {},
118
+ "outputs": [],
119
+ "source": [
120
+ "# Skip color → company goes to line_dash instead\n",
121
+ "xpx(stocks.sel(company=[\"GOOG\", \"AAPL\", \"MSFT\"])).line(color=None)"
122
+ ]
123
+ },
124
+ {
125
+ "cell_type": "markdown",
126
+ "metadata": {},
127
+ "source": [
128
+ "## Available Slots\n",
129
+ "\n",
130
+ "Different plot types have different slots:\n",
131
+ "\n",
132
+ "| Plot | Slots (in order) |\n",
133
+ "|------|------------------|\n",
134
+ "| line | x, color, line_dash, facet_col, facet_row, animation_frame |\n",
135
+ "| scatter | x, color, symbol, facet_col, facet_row, animation_frame |\n",
136
+ "| bar | x, color, facet_col, facet_row, animation_frame |\n",
137
+ "| imshow | x, y, facet_col, facet_row, animation_frame |"
138
+ ]
139
+ },
140
+ {
141
+ "cell_type": "code",
142
+ "execution_count": null,
143
+ "metadata": {},
144
+ "outputs": [],
145
+ "source": [
146
+ "# line_dash for third dimension\n",
147
+ "xpx(stocks.sel(company=[\"GOOG\", \"AAPL\"])).line(line_dash=\"company\")"
148
+ ]
149
+ },
150
+ {
151
+ "cell_type": "code",
152
+ "execution_count": null,
153
+ "metadata": {},
154
+ "outputs": [],
155
+ "source": [
156
+ "# symbol for scatter\n",
157
+ "xpx(stocks.sel(company=[\"GOOG\", \"AAPL\"])).scatter(symbol=\"company\")"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "markdown",
162
+ "metadata": {},
163
+ "source": [
164
+ "## Faceting\n",
165
+ "\n",
166
+ "Create a grid of subplots with `facet_col` and `facet_row`:"
167
+ ]
168
+ },
169
+ {
170
+ "cell_type": "code",
171
+ "execution_count": null,
172
+ "metadata": {},
173
+ "outputs": [],
174
+ "source": [
175
+ "# One subplot per metric\n",
176
+ "xpx(data_3d).line(facet_col=\"metric\")"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": null,
182
+ "metadata": {},
183
+ "outputs": [],
184
+ "source": [
185
+ "# Grid: metric x country\n",
186
+ "xpx(data_3d).line(x=\"year\", facet_col=\"metric\", facet_row=\"country\")"
187
+ ]
188
+ },
189
+ {
190
+ "cell_type": "markdown",
191
+ "metadata": {},
192
+ "source": [
193
+ "## Animation\n",
194
+ "\n",
195
+ "Animate over a dimension with `animation_frame`:"
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "metadata": {},
202
+ "outputs": [],
203
+ "source": [
204
+ "# Animate through years\n",
205
+ "xpx(data_3d.sel(metric=\"lifeExp\")).bar(x=\"country\", animation_frame=\"year\")"
206
+ ]
207
+ },
208
+ {
209
+ "cell_type": "code",
210
+ "execution_count": null,
211
+ "metadata": {},
212
+ "outputs": [],
213
+ "source": [
214
+ "# Animate heatmap\n",
215
+ "xpx(data_3d).imshow(animation_frame=\"metric\")"
216
+ ]
217
+ }
218
+ ],
219
+ "metadata": {
220
+ "kernelspec": {
221
+ "display_name": "Python 3",
222
+ "language": "python",
223
+ "name": "python3"
224
+ },
225
+ "language_info": {
226
+ "name": "python",
227
+ "version": "3.12.0"
228
+ }
229
+ },
230
+ "nbformat": 4,
231
+ "nbformat_minor": 4
232
+ }
@@ -0,0 +1,236 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Working with Figures\n",
8
+ "\n",
9
+ "All methods return a [Plotly Figure](https://plotly.com/python/figure-structure/) that can be modified and exported."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "import plotly.express as px\n",
19
+ "import plotly.graph_objects as go\n",
20
+ "import xarray as xr\n",
21
+ "\n",
22
+ "from xarray_plotly import config, xpx\n",
23
+ "\n",
24
+ "config.notebook()"
25
+ ]
26
+ },
27
+ {
28
+ "cell_type": "code",
29
+ "execution_count": null,
30
+ "metadata": {},
31
+ "outputs": [],
32
+ "source": [
33
+ "df = px.data.stocks().set_index(\"date\")\n",
34
+ "df.index = df.index.astype(\"datetime64[ns]\")\n",
35
+ "\n",
36
+ "stocks = xr.DataArray(\n",
37
+ " df.values,\n",
38
+ " dims=[\"date\", \"company\"],\n",
39
+ " coords={\"date\": df.index, \"company\": df.columns.tolist()},\n",
40
+ " name=\"price\",\n",
41
+ ")"
42
+ ]
43
+ },
44
+ {
45
+ "cell_type": "markdown",
46
+ "metadata": {},
47
+ "source": [
48
+ "## update_layout\n",
49
+ "\n",
50
+ "Modify [layout properties](https://plotly.com/python/reference/layout/): title, legend, margins, fonts."
51
+ ]
52
+ },
53
+ {
54
+ "cell_type": "code",
55
+ "execution_count": null,
56
+ "metadata": {},
57
+ "outputs": [],
58
+ "source": [
59
+ "fig = xpx(stocks).line()\n",
60
+ "fig.update_layout(\n",
61
+ " title={\"text\": \"Stock Prices\", \"x\": 0.5},\n",
62
+ " legend={\"orientation\": \"h\", \"y\": 1.02},\n",
63
+ ")\n",
64
+ "fig"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "markdown",
69
+ "metadata": {},
70
+ "source": [
71
+ "## update_traces\n",
72
+ "\n",
73
+ "Modify [trace properties](https://plotly.com/python/reference/): line width, markers, opacity."
74
+ ]
75
+ },
76
+ {
77
+ "cell_type": "code",
78
+ "execution_count": null,
79
+ "metadata": {},
80
+ "outputs": [],
81
+ "source": [
82
+ "fig = xpx(stocks).line()\n",
83
+ "fig.update_traces(line={\"width\": 3})\n",
84
+ "fig"
85
+ ]
86
+ },
87
+ {
88
+ "cell_type": "code",
89
+ "execution_count": null,
90
+ "metadata": {},
91
+ "outputs": [],
92
+ "source": [
93
+ "fig = xpx(stocks).scatter()\n",
94
+ "fig.update_traces(marker={\"size\": 10, \"opacity\": 0.7})\n",
95
+ "fig"
96
+ ]
97
+ },
98
+ {
99
+ "cell_type": "markdown",
100
+ "metadata": {},
101
+ "source": [
102
+ "## update_xaxes / update_yaxes\n",
103
+ "\n",
104
+ "Modify [axis properties](https://plotly.com/python/axes/)."
105
+ ]
106
+ },
107
+ {
108
+ "cell_type": "code",
109
+ "execution_count": null,
110
+ "metadata": {},
111
+ "outputs": [],
112
+ "source": [
113
+ "fig = xpx(stocks).line()\n",
114
+ "fig.update_xaxes(rangeslider_visible=True)\n",
115
+ "fig.update_yaxes(tickformat=\".0%\")\n",
116
+ "fig"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "markdown",
121
+ "metadata": {},
122
+ "source": [
123
+ "## add_hline / add_vline\n",
124
+ "\n",
125
+ "Add reference lines. See [shapes](https://plotly.com/python/shapes/)."
126
+ ]
127
+ },
128
+ {
129
+ "cell_type": "code",
130
+ "execution_count": null,
131
+ "metadata": {},
132
+ "outputs": [],
133
+ "source": [
134
+ "fig = xpx(stocks).line()\n",
135
+ "fig.add_hline(y=1.0, line_dash=\"dash\", line_color=\"gray\", annotation_text=\"Baseline\")\n",
136
+ "fig.add_vline(x=\"2018-10-01\", line_dash=\"dot\", line_color=\"red\")\n",
137
+ "fig"
138
+ ]
139
+ },
140
+ {
141
+ "cell_type": "markdown",
142
+ "metadata": {},
143
+ "source": [
144
+ "## add_annotation\n",
145
+ "\n",
146
+ "Add text annotations. See [annotations](https://plotly.com/python/text-and-annotations/)."
147
+ ]
148
+ },
149
+ {
150
+ "cell_type": "code",
151
+ "execution_count": null,
152
+ "metadata": {},
153
+ "outputs": [],
154
+ "source": [
155
+ "fig = xpx(stocks).line()\n",
156
+ "fig.add_annotation(x=\"2018-10-01\", y=1.4, text=\"Peak\", showarrow=True, arrowhead=2)\n",
157
+ "fig"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "markdown",
162
+ "metadata": {},
163
+ "source": [
164
+ "## add_trace\n",
165
+ "\n",
166
+ "Add custom traces using [Graph Objects](https://plotly.com/python/graph-objects/)."
167
+ ]
168
+ },
169
+ {
170
+ "cell_type": "code",
171
+ "execution_count": null,
172
+ "metadata": {},
173
+ "outputs": [],
174
+ "source": [
175
+ "fig = xpx(stocks.sel(company=\"GOOG\")).line()\n",
176
+ "\n",
177
+ "# Add moving average\n",
178
+ "goog = stocks.sel(company=\"GOOG\")\n",
179
+ "ma = goog.rolling(date=20, center=True).mean()\n",
180
+ "\n",
181
+ "fig.add_trace(\n",
182
+ " go.Scatter(\n",
183
+ " x=ma.coords[\"date\"].values,\n",
184
+ " y=ma.values,\n",
185
+ " mode=\"lines\",\n",
186
+ " name=\"20-day MA\",\n",
187
+ " line={\"dash\": \"dash\", \"color\": \"red\"},\n",
188
+ " )\n",
189
+ ")\n",
190
+ "fig"
191
+ ]
192
+ },
193
+ {
194
+ "cell_type": "markdown",
195
+ "metadata": {},
196
+ "source": [
197
+ "## Export\n",
198
+ "\n",
199
+ "### HTML\n",
200
+ "\n",
201
+ "See [HTML export](https://plotly.com/python/interactive-html-export/).\n",
202
+ "\n",
203
+ "```python\n",
204
+ "fig.write_html(\"plot.html\")\n",
205
+ "fig.write_html(\"plot.html\", include_plotlyjs=\"cdn\") # smaller file\n",
206
+ "```\n",
207
+ "\n",
208
+ "### Images\n",
209
+ "\n",
210
+ "Requires [kaleido](https://github.com/plotly/Kaleido): `pip install kaleido`\n",
211
+ "\n",
212
+ "See [static image export](https://plotly.com/python/static-image-export/).\n",
213
+ "\n",
214
+ "```python\n",
215
+ "fig.write_image(\"plot.png\")\n",
216
+ "fig.write_image(\"plot.png\", scale=2) # higher resolution\n",
217
+ "fig.write_image(\"plot.svg\")\n",
218
+ "fig.write_image(\"plot.pdf\")\n",
219
+ "```"
220
+ ]
221
+ }
222
+ ],
223
+ "metadata": {
224
+ "kernelspec": {
225
+ "display_name": "Python 3",
226
+ "language": "python",
227
+ "name": "python3"
228
+ },
229
+ "language_info": {
230
+ "name": "python",
231
+ "version": "3.12.0"
232
+ }
233
+ },
234
+ "nbformat": 4,
235
+ "nbformat_minor": 4
236
+ }