diff --git a/CHANGELOG.md b/CHANGELOG.md index ccc184c23af..f281cbf453a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,17 +4,26 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased + +## [6.8.0] - 2026-06-03 + ### Added -- Add optional `font` parameter for `make_subplots` [[#5393](https://github.com/plotly/plotly.py/pull/5393)] +- Add optional `font` parameter for `make_subplots` [[#5393](https://github.com/plotly/plotly.py/pull/5393)], with thanks to @Zomtir for the contribution! ### Fixed - Fix issue where user-specified `color_continuous_scale` was ignored when template had `autocolorscale=True` [[#5439](https://github.com/plotly/plotly.py/pull/5439)], with thanks to @antonymilne for the contribution! - Use presence of `COLAB_NOTEBOOK_ID` env var to enable Colab renderer instead of testing import of `google.colab` [[#5473](https://github.com/plotly/plotly.py/pull/5473)], with thanks to @kevineger for the contribution! +- Fix incorrect annotation placement for `add_vline`, `add_hline`, `add_vrect`, and `add_hrect` on datetime axes [[#5508](https://github.com/plotly/plotly.py/pull/5508)], with thanks to @mosh3eb for the contribution! - Update tests to be compatible with numpy 2.4 [[#5522](https://github.com/plotly/plotly.py/pull/5522)], with thanks to @thunze for the contribution! -- Add default headers to be passed in to Kaleido v1.3.0 to avoid blocked Open Street Map tiles [#5588](https://github.com/plotly/plotly.py/pull/5588)] +- Fix issue where `js/` directory was unintentionally installed as a top-level Python package when installing `plotly` [[#5587](https://github.com/plotly/plotly.py/pull/5587)] +- Add default headers to be passed in to Kaleido v1.3.0 to avoid blocked Open Street Map tiles [[#5588](https://github.com/plotly/plotly.py/pull/5588)] +- Propagate the requested `default_height`/`default_width` to the outer wrapper div produced by `to_html` so that responsive (percentage) dimensions inherit from a sized parent container instead of collapsing to the plotly.js 450px fallback [[#5591](https://github.com/plotly/plotly.py/issues/5591)], with thanks to @SharadhNaidu for the contribution! ### Updated - The `__eq__` method for `graph_objects` classes now returns `NotImplemented` to give the other operand an opportunity to handle the comparison [[#5547](https://github.com/plotly/plotly.py/pull/5547)], with thanks to @RazerM for the contribution! +- Update plotly.js from version 3.5.0 to version 3.6.0. See the plotly.js [release notes](https://github.com/plotly/plotly.js/releases/tag/v3.6.0) for more information [[#5608](https://github.com/plotly/plotly.py/pull/5608)]. Notable changes include: + - Add support for arrays for the pie property `legendrank`, so that it can be configured per slice [[#7723](https://github.com/plotly/plotly.js/pull/7723)] + - Add `hoversort` layout attribute to sort unified hover label items by value [[#7734](https://github.com/plotly/plotly.js/pull/7734)] ## [6.7.0] - 2026-04-09 diff --git a/CITATION.cff b/CITATION.cff index a64871aee61..67736d63d19 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -9,7 +9,7 @@ authors: - family-names: "Parmer" given-names: "Chris" title: "An interactive, open-source, and browser-based graphing library for Python" -version: 6.7.0 +version: 6.8.0 doi: 10.5281/zenodo.14503524 -date-released: 2026-04-09 +date-released: 2026-06-03 url: "https://github.com/plotly/plotly.py" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index abfb2dcb11c..a3e84914e8e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -274,7 +274,21 @@ python commands.py updateplotlyjs This downloads new versions of `plot-schema.json` and `plotly.min.js` from the `plotly/plotly.js` GitHub repository and places them in `plotly/package_data`. -It then regenerates all of the `graph_objs` classes based on the new schema. +It then regenerates all of the `graph_objs` classes based on the new schema, +and finally runs `npm install` in `js/` to refresh `js/package-lock.json` against the new `plotly.js`. +Commit the updated `js/package-lock.json` along with the regenerated files. + +The JupyterLab extension and FigureWidget bundles in `plotly/labextension` and `plotly/package_data/widgetbundle.js` +are rebuilt as part of the release flow (see [RELEASE.md](RELEASE.md)) rather than on every plotly.js bump. + +If you need to skip the `npm install` step entirely (e.g. `npm` isn't available), +set the `SKIP_NPM=1` environment variable: + +```bash +SKIP_NPM=1 python commands.py updateplotlyjs +``` + +If you do skip it, you'll need to run `npm install` in `js/` yourself before committing so the lockfile stays in sync. ### Using a Development Branch of Plotly.js @@ -319,6 +333,6 @@ Usage: `python commands.py ` | `codegen [--noformat]` | Regenerate Python files according to `plot-schema.json`.`--noformat` skips formatter step. | | `lint` | Lint all Python code in `plotly/`. | | `format` | Format all Python code in `plotly/`. | -| `updateplotlyjs` | Update `plotly.min.js` and `plot-schema.json` to match the `plotly.js` version specified in `js/package.json`. Then, run codegen to regenerate the Python files. | +| `updateplotlyjs` | Update `plotly.min.js` and `plot-schema.json` to match the `plotly.js` version specified in `js/package.json`, run codegen to regenerate the Python files, then run `npm install` in `js/` to refresh `js/package-lock.json`. Set `SKIP_NPM=1` to skip the npm step. | | `updateplotlyjsdev [--devrepo REPONAME --devbranch BRANCHNAME] \| [--local PATH]` | Update `plot-schema.json` and `plotly.min.js` to match the version in the provided plotly.js repo name and branch name, OR local path. Then, run codegen to regenerate the Python files. | | `bumpversion X.Y.Z` | Update the plotly.py version number to X.Y.Z across all files where it needs to be updated. | diff --git a/RELEASE.md b/RELEASE.md index 5d15f88fb9d..276a2e51d51 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -110,9 +110,9 @@ Once these are verified working, you can move on to publishing the release. ### Publishing to PyPI -The final step is to publish the release to PyPI. **You will need special permissions from Plotly leadership to do this.**. +The final step is to publish the release to PyPI. **You will need special permissions from Plotly leadership to do this.** -You must install first install [Twine](https://pypi.org/project/twine/) (`pip install twine`) if not already installed. +You must first install [Twine](https://pypi.org/project/twine/) (`pip install twine`) if not already installed. Publishing to PyPI: ```bash @@ -132,10 +132,21 @@ Your account must have permissions to publish to the `plotly` project on PyPI. start by doing it first if not. Then merge `main` into `doc-prod` to deploy the doc related to features in the release. 3. in a clone of the [`graphing-library-docs` repo](https://github.com/plotly/graphing-library-docs): - 1. bump the version of plotly.py in `_data/pyversion.json` + 1. bump the version of plotly.py in `_data/pyversion.json` 2. bump the version of plotly.js with `cd _data && python get_plotschema.py ` fixing any errors that come up. - - If plotly.js contains any new traces or trace or layout attributes, you'll get a warning `“missing key in attributes: `. To resolve, add the attribute to the relevant section in `/_data/orderings.json` in the position you want it to appear in the reference docs. - 3. rebuild the Algolia `schema` index with `ALGOLIA_API_KEY= make update_ref_search` + + **About `_data/orderings.json`:** `get_plotschema.py` downloads the raw `plot-schema.json` from the specified plotly.js release and uses `_data/orderings.json` (which lives in `graphing-library-docs`, not plotly.js) to determine the order in which traces, trace attributes, and layout attributes appear in the [reference documentation](https://plotly.com/python/reference/). The file has three sections: + - `layout` — top-level layout attributes (e.g. `hovermode`, `clickmode`, `xaxis`) + - `traces` — order of trace types (e.g. `scatter`, `bar`, `pie`) + - `trace_attr_order` — order of attributes shared across traces + + If plotly.js adds new traces or trace/layout attributes that aren't listed in `orderings.json`, `get_plotschema.py` prints a warning like `missing key in attributes: ` and appends the missing entry to the end of its section. To resolve: + + - Add each missing attribute to the appropriate section of `/_data/orderings.json` in the position you want it to appear in the reference docs. + - When in doubt about trace-attribute placement, match plotly.js's native order: open the regenerated `_data/plotschema.json` and find where plotly.js itself places the attribute (e.g. inspect a representative trace's `attributes` keys in order). Following the native order keeps related attributes grouped (for example, `texttemplate` → `texttemplatefallback` → `texttemplatesrc`). + - For new top-level layout attributes, group them with semantically related entries rather than appending to the end (for example, a new click-behavior attribute like `clickanywhere` belongs next to `clickmode`). + - Re-run `python get_plotschema.py ` after editing `orderings.json` and confirm the warnings are gone. + 3. Rebuild the Algolia `schema` index with `ALGOLIA_API_KEY= make update_ref_search` 4. Rebuild the Algolia `python` index with `ALGOLIA_API_KEY= make update_python_search` 5. Commit and push the changes to `master` in that repo @@ -158,5 +169,5 @@ PyPI RC (no special flags, just the `rc1` suffix): (plotly_dev) $ twine upload dist/plotly-X.Y.Zrc1* ``` -The `--tag next` part ensures that users won't install this version unless -they explicitly ask for the version or for the version with the `next` tag. +The `rc1` suffix ensures that users won't install this version by default — +they must explicitly request it (e.g., `pip install plotly==X.Y.Zrc1`). diff --git a/codegen/resources/plot-schema.json b/codegen/resources/plot-schema.json index 51624cf2322..318c0578d92 100644 --- a/codegen/resources/plot-schema.json +++ b/codegen/resources/plot-schema.json @@ -3063,6 +3063,17 @@ "y unified" ] }, + "hoversort": { + "description": "Determines the order of items shown in unified hover labels. If *trace*, items are sorted by trace index. If *value descending*, items are sorted by value from largest to smallest. If *value ascending*, items are sorted by value from smallest to largest. Only applies when `hovermode` is *x unified* or *y unified*.", + "dflt": "trace", + "editType": "none", + "valType": "enumerated", + "values": [ + "trace", + "value descending", + "value ascending" + ] + }, "hoversubplots": { "description": "Determines expansion of hover effects to other subplots If *single* just the axis pair of the primary point is included without overlaying subplots. If *overlaying* all subplots using the main axis and occupying the same space are included. If *axis*, also include stacked subplots using the same axis when `hovermode` is set to *x*, *x unified*, *y* or *y unified*.", "dflt": "overlaying", @@ -56775,11 +56786,17 @@ } }, "legendrank": { - "description": "Sets the legend rank for this trace. Items and groups with smaller ranks are presented on top/left side while with *reversed* `legend.traceorder` they are on bottom/right side. The default legendrank is 1000, so that you can use ranks less than 1000 to place certain items before all unranked items, and ranks greater than 1000 to go after all unranked items. When having unranked or equal rank items shapes would be displayed after traces i.e. according to their order in data and layout.", + "arrayOk": true, + "description": "Sets the legend rank for this pie. If passed as an array, this will set the legend rank of the individual pie slices. Items and groups with smaller ranks are presented on top/left side while with *reversed* `legend.traceorder` they are on bottom/right side. The default legendrank is 1000, so that you can use ranks less than 1000 to place certain items before all unranked items, and ranks greater than 1000 to go after all unranked items. When having unranked or equal rank items shapes would be displayed after traces i.e. according to their order in data and layout.", "dflt": 1000, "editType": "style", "valType": "number" }, + "legendranksrc": { + "description": "Sets the source reference on Chart Studio Cloud for `legendrank`.", + "editType": "none", + "valType": "string" + }, "legendsrc": { "description": "Sets the source reference on Chart Studio Cloud for `legend`.", "editType": "none", diff --git a/commands.py b/commands.py index f00f52d5307..aec2055ea5c 100644 --- a/commands.py +++ b/commands.py @@ -44,8 +44,15 @@ def plotly_js_version(): return version -def install_js_deps(local): - """Install package.json dependencies using npm.""" +def install_js_deps(local, build=True): + """Install package.json dependencies using npm. + + When ``build`` is True (the default), also runs ``npm run build`` to + rebuild the JupyterLab extension and FigureWidget bundles and verifies + that the widget bundle exists. Pass ``build=False`` when you only need + to refresh ``node_modules`` / ``package-lock.json`` (e.g. after a + plotly.js version bump) and don't need the bundles rebuilt. + """ npmName = "npm" if platform.system() == "Windows": @@ -86,18 +93,20 @@ def install_js_deps(local): stdout=sys.stdout, stderr=sys.stderr, ) - check_call( - [npmName, "run", "build"], - cwd=NODE_ROOT, - stdout=sys.stdout, - stderr=sys.stderr, - ) + if build: + check_call( + [npmName, "run", "build"], + cwd=NODE_ROOT, + stdout=sys.stdout, + stderr=sys.stderr, + ) os.utime(NODE_MODULES, None) - for target in WIDGET_TARGETS: - if not os.path.exists(target): - msg = "Missing file: %s" % target - raise ValueError(msg) + if build: + for target in WIDGET_TARGETS: + if not os.path.exists(target): + msg = "Missing file: %s" % target + raise ValueError(msg) def overwrite_schema_local(uri): @@ -215,6 +224,7 @@ def update_plotlyjs(plotly_js_version, outdir): update_bundle(plotly_js_version) update_schema(plotly_js_version) perform_codegen(outdir) + install_js_deps(local=None, build=False) # FIXME: switch to argparse diff --git a/dependabot.yml b/dependabot.yml new file mode 100644 index 00000000000..0b8132a6acf --- /dev/null +++ b/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 + +updates: + - package-ecosystem: "uv" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 3 # Should match tool.uv.exclude-newer option in pyproject.toml diff --git a/doc/README.md b/doc/README.md index cb66bb726f2..4ccfaf4f658 100644 --- a/doc/README.md +++ b/doc/README.md @@ -5,23 +5,54 @@ The `doc` directory contains the source files of the documentation of plotly.py. It is composed of two parts: -- inside the [`python/` directory](python), tutorials corresponding to https://plot.ly/python/ +- inside the [`python/` directory](python), tutorials corresponding to https://plotly.com/python/ - inside the [`apidoc/` directory](apidoc), configuration files for generating - the API reference documentation (hosted on https://plot.ly/python-api-reference/) + the API reference documentation (hosted on https://plotly.com/python-api-reference/) -Python packages required to build the doc are listed in +Python packages required to build the docs are listed in [`requirements.txt`](requirements.txt) in the `doc` directory. +## Local environment setup + +Before building the documentation locally, you need to set up a dedicated +environment with the doc-specific dependencies. + +```bash +cd doc +uv venv --python 3.9 +source .venv/bin/activate +uv pip install -r requirements.txt +``` + +If you are documenting a feature that has not yet been released, you also need +an editable install of plotly so your local changes are reflected: + +```bash +uv pip uninstall plotly # remove the PyPI version installed by requirements.txt +uv pip install -e .. # install from your local checkout +``` + +### Mapbox token + +Several geographic examples require a free Mapbox public token. Without it, +those specific pages will fail to build. + +1. Create an account at https://account.mapbox.com/auth/signup +2. Navigate to https://account.mapbox.com/ and copy your "Default public token" +3. Save it to the file `doc/python/.mapbox_token` + +The Makefile symlinks this token into the build directory automatically. + ## Tutorials (`python` directory) -Each tutorial is a markdown (`.md`) file, which can be opened in the Jupyter -notebook or in Jupyterlab by installing [jupytext](https://jupytext.readthedocs.io/en/latest/install.html). +Each tutorial is a markdown (`.md`) file, which can be opened in Jupyter +Notebook or in JupyterLab by installing [jupytext](https://jupytext.readthedocs.io/en/latest/install.html). For small edits (e.g., correcting typos) to an existing tutorial, you can simply click on the "edit this -page on Github" link at the top right of the page (e.g. clicking on this link -on https://plot.ly/python/bar-charts/ will take you to +page on GitHub" link at the top right of the page (e.g. clicking on this link +on https://plotly.com/python/bar-charts/ will take you to https://github.com/plotly/plotly.py/edit/doc-prod/doc/python/bar-charts.md, -where you can edit the page on Github). +where you can edit the page on GitHub). For more important edits where you need to run the notebook to check the output, clone the repository and setup an environment as described in the [main @@ -31,19 +62,126 @@ install (`pip install -e`, as described in [main contributing notes](../CONTRIBUTING.md)), so that you only need to restart the Jupyter kernel when you have changed the source code of the feature. -### Branches +### Branching strategy + +- The `doc-prod` branch contains the live docs which are available on the website. As soon as a change is merged into `doc-prod`, the updated docs are deployed and made publicly available. +- The `main` branch contains docs which have been written but are not ready to be released, such as for an upcoming feature in the next plotly.py release. + +When updating the docs, two workflows are possible: + +- In the case of updating the docs for an already-released feature: your changes can be deployed to the documentation website as soon as they have been merged, so you should branch off of the `doc-prod` branch and open your pull request into the `doc-prod` branch. +- In the case of writing docs for a new (not-yet-released) feature: you should branch off `main` and open your pull request into `main`, so that the documentation of the feature is only deployed when it is available in a released version of `plotly.py`. The `main` branch will be merged into `doc-prod` at release time, as described below. + +#### Keeping `main` and `doc-prod` in sync + +Changes to `doc-prod` are **not** automatically merged back into `main`. To +prevent the branches from diverging, `doc-prod` should be merged into `main` on +a regular basis via a pull request (e.g., a branch named +`merge-doc-prod-to-main-branch` merged into `main`). + +At release time the synchronization is bidirectional (see also +[`RELEASE.md`](../RELEASE.md)): + +1. **`doc-prod` → `main`** — merge any outstanding doc-only fixes into `main` + (if not already done recently). +2. **`main` → `doc-prod`** — merge `main` into `doc-prod` so that documentation + for newly released features is deployed to the live site. +3. **Publish the site** — update the + [`graphing-library-docs`](https://github.com/plotly/graphing-library-docs) + repo to bump the plotly.py and plotly.js versions and rebuild the Algolia + search indexes. See the + [Update documentation site](../RELEASE.md#update-documentation-site) + section of `RELEASE.md` for the full procedure. + +> **Release prep:** When synchronizing `main` into `doc-prod` for a new +> release, update the `plotly==` version pin in `doc/requirements.txt` to match +> the newly released version. The `doc-prod` build uses this pinned version +> (not an editable install), so examples that rely on new features will fail +> if the pin is stale. -Two different cases exist, whether you are documenting a feature already -released, or which has just been included but not yet released. +### Tutorial file format -- Case of an already released feature: your changes can be deployed to the - documentation website as soon as they have been merged, and you should start - your branch off the `doc-prod` branch and open your pull request against this - `doc-prod` branch. -- Case of a new (not released yet) feature: start your branch / pull request - against the `main` branch. `main` and `doc-prod` will be synchronized at - release time, so that the documentation of the feature is only deployed when - it is available in a released version of `plotly.py`. +Tutorial files are Markdown files with a YAML frontmatter block that contains +Jupyter notebook metadata (used by jupytext) and plotly-specific metadata (used +by the documentation site for navigation, SEO, and categorization). + +Here is an annotated example of the frontmatter: + +```yaml +--- +jupyter: + jupytext: + notebook_metadata_filter: all + text_representation: + extension: .md + format_name: markdown + format_version: '1.3' + jupytext_version: 1.17.3 + 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.9.0 + plotly: + description: Short description for SEO and page previews. + display_as: basic # Category: basic, statistical, scientific, maps, 3d, etc. + language: python + layout: base + name: Page Title # Displayed in the navigation sidebar + order: 3 # Position within the display_as category + page_type: example_index + permalink: python/my-page/ # URL path on the documentation site + thumbnail: thumbnail/my-page.jpg +--- +``` + +The `plotly` metadata fields are the most important to enter correctly when creating/updating a tutorial: + +| Field | Description | +|-------|-------------| +| `name` | Page title shown in the sidebar and browser tab | +| `permalink` | URL slug — must match the filename (e.g., `bar-charts.md` → `python/bar-charts/`) | +| `description` | Short description used by search engines | +| `display_as` | Category grouping (e.g., `basic`, `statistical`, `scientific`, `maps`, `3d_charts`, `file_settings`) | +| `order` | Numeric sort order within the category | +| `page_type` | Typically `example_index` for tutorial pages | +| `thumbnail` | Path to the thumbnail image | + +Code cells are written as fenced code blocks with the `python` language tag. +Each code cell is separated by a blank line and starts with ` ```python `. +Markdown cells are written as regular Markdown text between code blocks. + +### Creating a new tutorial page + +1. **Copy an existing tutorial** from `doc/python/` as a starting point to get + the frontmatter structure right. +2. **Update the frontmatter** — at minimum, change `name`, `permalink`, + `description`, `display_as`, and `order`. Make sure `permalink` matches the + filename (e.g., `my-feature.md` → `python/my-feature/`). +3. **Write examples** using fenced `python` code blocks. Each block becomes a + separate Jupyter cell when the file is converted. +4. **Test in Jupyter** — open the file directly in JupyterLab (with jupytext + installed) and run all cells to verify the examples work: + ```bash + jupyter lab doc/python/my-feature.md + ``` +5. **Build the single page** (optional) — you can build just your page instead + of the entire doc set: + ```bash + cd doc + make build/html/2019-07-03-my-feature.html + ``` +6. **Check that CI passes** — push your branch and open a pull request. The CI + will build all pages and run validation on frontmatter and page ordering. ### Guidelines @@ -65,17 +203,60 @@ Checklist ### Build process -This build process requries a free personal public mapbox token to work. +#### Building all tutorials + +From the `doc` directory, with the virtual environment activated: + +```bash +cd doc +source .venv/bin/activate +make +``` + +This runs through every `.md` file in `python/` and: + +1. Appends the "What About Dash?" footer from `what_about_dash.md` +2. Converts each Markdown file to a Jupyter notebook using **jupytext** +3. Executes the notebook and converts it to HTML using **nbconvert** (with a + 10-minute timeout per notebook) +4. Outputs HTML files to `build/html/` with a `2019-07-03-` date prefix +5. Generates redirect pages for v3 backward compatibility and "next version" + previews + +To build in parallel (as CI does): + +```bash +make -kj8 +``` + +The `-k` flag continues past failures and `-j8` runs 8 jobs in parallel. + +#### Building a single tutorial + +To build only one page (useful during development): + +```bash +make build/html/2019-07-03-bar-charts.html +``` -First, create an account at https://account.mapbox.com/auth/signup Once that is done, navigate to https://account.mapbox.com/ and copy your "Default public token" to the file `doc/python/.mapbox_token` +The filename follows the pattern `2019-07-03-.html`. -Next, run `make` to build html pages for the tutorials. This uses `jupytext` to -execute the notebooks and `nbconvert` to convert notebook files to static html -pages. Note that the CI will build the doc, so you don't have to build it -yourself, it is enough to check that the markdown file runs correctly in -Jupyter. +> **Why the `2019-07-03-` prefix?** The downstream `graphing-library-docs` +> site uses Jekyll, whose `_posts/` collection only processes files matching +> the pattern `YYYY-MM-DD-title.ext` and silently ignores anything else. +> The specific date is an arbitrary placeholder — its value is never +> displayed; it just satisfies Jekyll's filename parser. -The output of the `Makefile` is stored by CI in the `built` branch of the `plotly.py-docs` repo which is then used by the `documentation` repo to generate https://plot.ly/python. +#### Build output + +| Directory | Contents | +|-----------|----------| +| `build/ipynb/` | Intermediate Jupyter notebook files | +| `build/html/` | Final HTML tutorial pages | +| `build/html/redir/` | Redirect pages (v3 and next-version) | +| `build/failures/` | Stderr logs for pages that failed to build | + +If a build fails, check `build/failures/` for the error output. ## API reference documentation (`apidoc` directory) @@ -84,16 +265,156 @@ extension](http://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html) in order to generate the documentation of the API. Sphinx uses the [reST markup language](https://www.sphinx-doc.org/en/2.0/usage/restructuredtext/basics.html). -Run `make html` inside `apidoc` to build the API doc in the `_build/html` -directory. +### Building the API docs + +The API docs require an editable install of plotly because the build process +temporarily modifies source files (renaming `graph_objects` references to the +internal `graph_objs` name for Sphinx, then reverting afterward). + +```bash +cd doc +source .venv/bin/activate +uv pip uninstall plotly +uv pip install -e .. +cd apidoc +make html +``` + +The output is written to `apidoc/_build/html/`. + +### How the API doc build works + +The `apidoc/Makefile` performs several steps: + +1. Temporarily rewrites `:class:` cross-references in `plotly/graph_objs/` to + use the internal `graph_objs` name so Sphinx can resolve them. +2. Copies color module files into `plotly/colors/` and `plotly/express/colors/` + so their docstrings are picked up. +3. Runs `sphinx-apidoc` to auto-generate `.rst` stubs from the Python source, + excluding `validators/`, `tests/`, `matplotlylib/`, `offline/`, and `api/`. +4. Runs `sphinx-build` to produce HTML from the `.rst` files. +5. Reverts the `graph_objs` source changes with `git checkout`. +6. Cleans up the temporarily copied color files. +7. Renames all `graph_objs` references back to `graph_objects` in the generated + HTML and related files. + +### Adding new API objects -Lists of objects to be documented are found in files corresponding to -submodules, such as [`plotly.express.rst`](plotly.express.rst). When a new -object is added to the exposed API, it needs to be added to the corresponding -file to appear in the API doc. +Lists of objects to be documented are found in `.rst` files corresponding to +submodules: -Other files +| File | Module | +|------|--------| +| `plotly.express.rst` | `plotly.express` (high-level API) | +| `plotly.graph_objects.rst` | `plotly.graph_objects` (traces, layout) | +| `plotly.io.rst` | `plotly.io` (display, read, write) | +| `plotly.subplots.rst` | `plotly.subplots` (subplot helpers) | +| `plotly.figure_factory.rst` | `plotly.figure_factory` | +| `basefigure.rst` | `BaseFigure` class | + +When a new object is added to the exposed API, it needs to be added to the +corresponding `.rst` file to appear in the API doc. + +### Other files - `css` files are found in `_static` - Template files are found in `_templates`. `.rst` templates describe how the autodoc of the different objects should look like. +- `conf.py` contains the Sphinx configuration (theme, extensions, etc.) + +## CI/CD pipeline + +Documentation is built and deployed automatically by the GitHub Actions workflow +defined in `.github/workflows/build-doc.yml`. + +### What triggers a build + +| Event | What happens | +|-------|-------------| +| Pull request (any branch) | Tutorials (markdown files in doc/python) are built and validated. The build artifact is uploaded but not deployed. | +| Push to `doc-prod` | Full build: tutorials are built, validated, and deployed. API docs are also built and deployed. | + +### Build steps + +1. **Environment setup** — Python 3.9, `uv`, and system dependencies (`rename` + utility) are installed. +2. **Install doc dependencies** — `uv pip install -r requirements.txt` inside + `doc/`. +3. **Install editable plotly** (non-`doc-prod` branches only) — Replaces the + PyPI plotly with the local checkout so that in-development features are + available. +4. **Build HTML tutorials** — Runs `make -kj8` (twice, to retry transient + failures). Then downloads and runs validation scripts from + `plotly/graphing-library-docs`: + - `front-matter-ci.py` validates the YAML frontmatter of all built pages. + - `check-or-enforce-order.py` verifies page ordering within categories. +5. **Upload build artifact** — The built HTML is uploaded as a GitHub Actions + artifact named `doc-html` for inspection. + +### Deployment (doc-prod only) + +When changes are pushed to `doc-prod`, the workflow deploys to three branches +of the [`plotly/plotly.py-docs`](https://github.com/plotly/plotly.py-docs) +repository: + +| Target branch | Contents | +|---------------|----------| +| `built` | Final HTML tutorial pages | +| `built_ipynb` | Intermediate Jupyter notebook files | +| `gh-pages` | API reference HTML (built by Sphinx) | + +After deploying, the workflow triggers a downstream build in +[`plotly/graphing-library-docs`](https://github.com/plotly/graphing-library-docs) +by pushing an empty commit. That repository generates the final +https://plotly.com/python site. + +### Summary of the full deployment path + +``` +doc/python/*.md (source) + ↓ make (jupytext + nbconvert) +doc/build/html/*.html (built tutorials) + ↓ CI deploys to plotly/plotly.py-docs@built +plotly/graphing-library-docs (triggered rebuild) + ↓ Jekyll site generation +https://plotly.com/python/ (live site) +``` + +## Troubleshooting + +### A single page fails to build + +Check `build/failures/` for the full error output. Common causes: + +- **Missing import or dataset** — make sure all imports and remote data URLs + are correct. +- **Timeout** — the default is 600 seconds (10 minutes). If your example + legitimately needs more time, discuss in an issue before increasing the + timeout. +- **Missing Mapbox token** — geographic examples will fail if + `doc/python/.mapbox_token` does not exist. + +### `make` fails immediately + +- Confirm you are running from the `doc/` directory with the virtual + environment activated. +- Check that `jupytext` and `nbconvert` are installed: `jupytext --version` + and `jupyter nbconvert --version`. + +### API doc build fails on `graph_objs` references + +The API doc build temporarily modifies files under `plotly/graph_objs/`. If a +previous build was interrupted, those files may be in a dirty state. Reset them +with: + +```bash +git checkout -- plotly/graph_objs +``` + +### CI frontmatter validation fails + +The CI runs `front-matter-ci.py` and `check-or-enforce-order.py` against the +built HTML. Ensure your tutorial's YAML frontmatter includes all required +fields (`name`, `permalink`, `description`, `display_as`, `order`, `layout`, +`language`) and that the `order` value does not conflict with existing pages in +the same `display_as` category. diff --git a/doc/apidoc/conf.py b/doc/apidoc/conf.py index a9abb3aa8d7..3f50f76cae4 100644 --- a/doc/apidoc/conf.py +++ b/doc/apidoc/conf.py @@ -24,7 +24,7 @@ # The short X.Y version version = "" # The full version, including alpha/beta/rc tags -release = "6.7.0" +release = "6.8.0" # -- General configuration --------------------------------------------------- diff --git a/doc/python/hover-text-and-formatting.md b/doc/python/hover-text-and-formatting.md index a33897eef2e..c81f1f06f0c 100644 --- a/doc/python/hover-text-and-formatting.md +++ b/doc/python/hover-text-and-formatting.md @@ -83,6 +83,24 @@ fig.update_layout(hovermode="x unified") fig.show() ``` +#### Sorting Unified Hover Labels by Value + +*New in 6.8* + +In `'x unified'` and `'y unified'` hover modes, items in the hover label appear in the order their traces were added to the figure (the default, `hoversort="trace"`). Set `layout.hoversort` to `"value descending"` or `"value ascending"` to instead sort the items by the value being shown, which makes it easier to compare traces at a glance. + +```python +import plotly.express as px + +df = px.data.stocks() + +fig = px.line(df, x="date", y=df.columns[1:], title="layout.hoversort='value descending'") +fig.update_traces(hovertemplate=None) +fig.update_layout(hovermode="x unified", hoversort="value descending") + +fig.show() +``` + #### Customize Title in Unified Hover Mode *New in 6.3* @@ -221,7 +239,13 @@ fig.update_layout( fig.show() ``` -### Customizing Hover text with Plotly Express +### Emitting Hover and Click Events Anywhere in the Plot Area + +*New in 6.7* + +By default, hover and click events are only emitted when the cursor is over a trace. Set `hoveranywhere` or `clickanywhere` to `True` to emit these events anywhere inside the plot area, including over empty space: `fig.update_layout(hoveranywhere=True, clickanywhere=True)`. The events carry the cursor's data coordinates, which is useful when building interactive callbacks (for example, in [Dash](https://dash.plotly.com/)) that need to respond to clicks on locations that don't correspond to a specific data point. + +### Customizing Hover Text with Plotly Express Plotly Express functions automatically add all the data being plotted (x, y, color etc) to the hover label. Many Plotly Express functions also support configurable hover text. The `hover_data` argument accepts a list of column names to be added to the hover tooltip, or a dictionary for advanced formatting (see the next section). The `hover_name` property controls which column is displayed in bold as the tooltip title. diff --git a/doc/python/legend.md b/doc/python/legend.md index 0ed08929d03..3f4f8fbd1bd 100644 --- a/doc/python/legend.md +++ b/doc/python/legend.md @@ -154,6 +154,25 @@ fig.add_shape( fig.show() ``` +##### Per-Slice `legendrank` for Pie Traces + +*New in 6.8* + +For `pie` traces, `legendrank` also accepts an array so that each slice can be ranked individually. In the example below, the slices appear in the legend in the order specified by `legendrank` (lowest rank first), independent of the order of `values`. + +```python +import plotly.graph_objects as go + +fig = go.Figure( + go.Pie( + labels=["Oxygen", "Hydrogen", "Carbon", "Nitrogen", "Other"], + values=[4500, 2500, 1053, 500, 600], + legendrank=[3, 1, 2, 5, 4], + ) +) +fig.show() +``` + #### Showing and Hiding the Legend By default the legend is displayed on Plotly charts with multiple traces, and this can be explicitly set with the `layout.showlegend` attribute. diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 43f584e097e..e9b7b317841 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -277,6 +277,8 @@ The following settings are available. `topojson`: Location of the topojson files needed to render choropleth traces. Defaults to a CDN location. If fully offline export is required, set this to a local directory containing the Plotly.js topojson files. +`headers`: *New in 6.8.* A dict of HTTP headers Kaleido sends when fetching external resources during image export (for example, when fetching OpenStreetMap tiles for tile maps). Defaults to `{"X-Requested-With": "plotly.py"}`, which is required to comply with the [OpenStreetMap tile usage policy](https://operations.osmfoundation.org/policies/tiles/). Requires Kaleido v1.3.0 or later. + `mapbox_access_token`: The default Mapbox access token (Kaleido v0 only). Mapbox traces are deprecated. See the [MapLibre Migration](https://plotly.com/python/mapbox-to-maplibre/) page for more details. ### Set Defaults diff --git a/doc/python/subplots.md b/doc/python/subplots.md index 2a327b1354d..4bcbc59993e 100644 --- a/doc/python/subplots.md +++ b/doc/python/subplots.md @@ -156,6 +156,28 @@ fig.update_layout(height=500, width=700, fig.show() ``` +#### Customizing the Subplot Title Font + +*New in 6.8* + +Use the `font` argument of `make_subplots` to customize the font used for `subplot_titles`, `column_titles`, `row_titles`, `x_title`, and `y_title`. The argument accepts a dict with any of the standard [font attributes](https://plotly.com/python/reference/layout/annotations/#layout-annotations-items-annotation-font) (`family`, `size`, `color`, `weight`, etc.). + +```python +from plotly.subplots import make_subplots +import plotly.graph_objects as go + +fig = make_subplots( + rows=1, cols=2, + subplot_titles=("Plot 1", "Plot 2"), + font=dict(family="Courier New, monospace", size=20, color="RebeccaPurple"), +) + +fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 5, 6]), row=1, col=1) +fig.add_trace(go.Scatter(x=[20, 30, 40], y=[50, 60, 70]), row=1, col=2) + +fig.show() +``` + #### Subplots with Annotations ```python diff --git a/doc/requirements.txt b/doc/requirements.txt index 202de270459..7809833b007 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,4 +1,4 @@ -plotly==6.7.0 +plotly==6.8.0 anywidget cufflinks==0.17.3 dash-bio @@ -27,7 +27,7 @@ pooch psutil pyarrow pyshp==2.1.2 -python-frontmatter +python-frontmatter==1.1.0 recommonmark requests scikit-image==0.20.0 diff --git a/js/package-lock.json b/js/package-lock.json index 736832ddc7c..338e8f7fd02 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -1,17 +1,17 @@ { "name": "jupyterlab-plotly", - "version": "6.7.0", + "version": "6.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "jupyterlab-plotly", - "version": "6.7.0", + "version": "6.8.0", "license": "MIT", "dependencies": { "@lumino/widgets": "~2.4.0", "lodash-es": "^4.17.21", - "plotly.js": "3.5.0" + "plotly.js": "3.6.0" }, "devDependencies": { "@jupyterlab/builder": "^4.3.6 || ^3.6.8", @@ -1460,14 +1460,6 @@ } ] }, - "node_modules/canvas-fit": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/canvas-fit/-/canvas-fit-1.5.0.tgz", - "integrity": "sha512-onIcjRpz69/Hx5bB5HGbYKUF2uC6QT6Gp+pfpGm3A7mPfcluSLV5v4Zu+oflDUwLdUw0rLIBhUbi0v8hM4FJQQ==", - "dependencies": { - "element-size": "^1.1.1" - } - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2030,11 +2022,6 @@ "integrity": "sha512-oTUp3gfX1gZI+xfD2djr2rzQdHCwHzPQrrK0CD7WpTdF0nPdQ/INcRVjWgLdCT4a9W3jFObR9DAfsuyFQnI8CQ==", "dev": true }, - "node_modules/element-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/element-size/-/element-size-1.1.1.tgz", - "integrity": "sha512-eaN+GMOq/Q+BIWy0ybsgpcYImjGIdNLyjLFJU4XsLHXYQao5jCNb36GyN6C2qwmDDYSfIBmKpPpr4VnBdLCsPQ==" - }, "node_modules/elementary-circuits-directed-graph": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/elementary-circuits-directed-graph/-/elementary-circuits-directed-graph-1.3.1.tgz", @@ -3355,34 +3342,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mouse-change": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mouse-change/-/mouse-change-1.4.0.tgz", - "integrity": "sha512-vpN0s+zLL2ykyyUDh+fayu9Xkor5v/zRD9jhSqjRS1cJTGS0+oakVZzNm5n19JvvEj0you+MXlYTpNxUDQUjkQ==", - "dependencies": { - "mouse-event": "^1.0.0" - } - }, - "node_modules/mouse-event": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/mouse-event/-/mouse-event-1.0.5.tgz", - "integrity": "sha512-ItUxtL2IkeSKSp9cyaX2JLUuKk2uMoxBg4bbOWVd29+CskYJR9BGsUqtXenNzKbnDshvupjUewDIYVrOB6NmGw==" - }, "node_modules/mouse-event-offset": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mouse-event-offset/-/mouse-event-offset-3.0.2.tgz", "integrity": "sha512-s9sqOs5B1Ykox3Xo8b3Ss2IQju4UwlW6LSR+Q5FXWpprJ5fzMLefIIItr3PH8RwzfGy6gxs/4GAmiNuZScE25w==" }, - "node_modules/mouse-wheel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mouse-wheel/-/mouse-wheel-1.2.0.tgz", - "integrity": "sha512-+OfYBiUOCTWcTECES49neZwL5AoGkXE+lFjIvzwNCnYRlso+EnfvovcBxGoyQ0yQt806eSPjS675K0EwWknXmw==", - "dependencies": { - "right-now": "^1.0.0", - "signum": "^1.0.0", - "to-px": "^1.0.1" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3619,9 +3583,9 @@ } }, "node_modules/plotly.js": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-3.5.0.tgz", - "integrity": "sha512-a3AYQIMG7OdZmrJ/fJ65HSt3g1l5qDeludKqjjafU1dh5E+fwqDhsEBndW7VCYwjlducCfN6KtPdWdiWFcoBWw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-3.6.0.tgz", + "integrity": "sha512-Fu5IaetcuxaeQPULk4wfIik0MnvIsEb5ynOsPAMfhAnjkPOEDFG7eSb/3ZZq1DW5MwYvZFXaTFHpal4U1Q5Yig==", "license": "MIT", "dependencies": { "@plotly/d3": "3.8.2", @@ -3633,10 +3597,7 @@ "@turf/bbox": "^7.1.0", "@turf/centroid": "^7.1.0", "base64-arraybuffer": "^1.0.2", - "canvas-fit": "^1.5.0", - "color-alpha": "1.0.4", "color-normalize": "1.5.0", - "color-parse": "2.0.0", "color-rgba": "3.0.0", "country-regex": "^1.1.0", "d3-force": "^1.2.1", @@ -3654,9 +3615,7 @@ "has-passive-events": "^1.0.0", "is-mobile": "^4.0.0", "maplibre-gl": "^4.7.1", - "mouse-change": "^1.4.0", "mouse-event-offset": "^3.0.2", - "mouse-wheel": "^1.2.0", "native-promise-only": "^0.8.1", "parse-svg-path": "^0.1.2", "point-in-polygon": "^1.1.0", @@ -3667,10 +3626,8 @@ "regl-scatter2d": "^3.3.1", "regl-splom": "^1.0.14", "strongly-connected-components": "^1.0.1", - "superscript-text": "^1.0.0", "svg-path-sdf": "^1.1.3", "tinycolor2": "^1.4.2", - "to-px": "1.0.1", "topojson-client": "^3.1.0", "webgl-context": "^2.2.0", "world-calendars": "^1.0.4" @@ -4045,11 +4002,6 @@ "protocol-buffers-schema": "^3.3.1" } }, - "node_modules/right-now": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/right-now/-/right-now-1.0.0.tgz", - "integrity": "sha512-DA8+YS+sMIVpbsuKgy+Z67L9Lxb1p05mNxRpDPNksPDEFir4vmBlUtuN9jkTGn9YMMdlBuK7XQgFiz6ws+yhSg==" - }, "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", @@ -4162,11 +4114,6 @@ "node": ">=8" } }, - "node_modules/signum": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/signum/-/signum-1.0.0.tgz", - "integrity": "sha512-yodFGwcyt59XRh7w5W3jPcIQb3Bwi21suEfT7MAWnBX3iCdklJpgDgvGT9o04UonglZN5SNMfJFkHIR/jO8GHw==" - }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -4396,11 +4343,6 @@ "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz", "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==" }, - "node_modules/superscript-text": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/superscript-text/-/superscript-text-1.0.0.tgz", - "integrity": "sha512-gwu8l5MtRZ6koO0icVTlmN5pm7Dhh1+Xpe9O4x6ObMAsW+3jPbW14d1DsBq1F4wiI+WOFjXF35pslgec/G8yCQ==" - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/js/package.json b/js/package.json index d833ccfe53d..2b89d2fe0fd 100644 --- a/js/package.json +++ b/js/package.json @@ -1,7 +1,7 @@ { "name": "jupyterlab-plotly", "main": "lib/mimeExtension.js", - "version": "6.7.0", + "version": "6.8.0", "repository": { "type": "git", "url": "https://github.com/plotly/plotly.py" @@ -19,7 +19,7 @@ }, "dependencies": { "lodash-es": "^4.17.21", - "plotly.js": "3.5.0", + "plotly.js": "3.6.0", "@lumino/widgets": "~2.4.0" }, "devDependencies": { diff --git a/plotly/graph_objs/_figure.py b/plotly/graph_objs/_figure.py index 2d134776109..fb6a200a3f0 100644 --- a/plotly/graph_objs/_figure.py +++ b/plotly/graph_objs/_figure.py @@ -12671,6 +12671,7 @@ def add_pie( legendgroup=None, legendgrouptitle=None, legendrank=None, + legendranksrc=None, legendsrc=None, legendwidth=None, marker=None, @@ -12850,16 +12851,20 @@ def add_pie( :class:`plotly.graph_objects.pie.Legendgrouptitle` instance or dict with compatible properties legendrank - Sets the legend rank for this trace. Items and groups - with smaller ranks are presented on top/left side while - with "reversed" `legend.traceorder` they are on - bottom/right side. The default legendrank is 1000, so - that you can use ranks less than 1000 to place certain - items before all unranked items, and ranks greater than - 1000 to go after all unranked items. When having - unranked or equal rank items shapes would be displayed - after traces i.e. according to their order in data and - layout. + Sets the legend rank for this pie. If passed as an + array, this will set the legend rank of the individual + pie slices. Items and groups with smaller ranks are + presented on top/left side while with "reversed" + `legend.traceorder` they are on bottom/right side. The + default legendrank is 1000, so that you can use ranks + less than 1000 to place certain items before all + unranked items, and ranks greater than 1000 to go after + all unranked items. When having unranked or equal rank + items shapes would be displayed after traces i.e. + according to their order in data and layout. + legendranksrc + Sets the source reference on Chart Studio Cloud for + `legendrank`. legendsrc Sets the source reference on Chart Studio Cloud for `legend`. @@ -13052,6 +13057,7 @@ def add_pie( legendgroup=legendgroup, legendgrouptitle=legendgrouptitle, legendrank=legendrank, + legendranksrc=legendranksrc, legendsrc=legendsrc, legendwidth=legendwidth, marker=marker, diff --git a/plotly/graph_objs/_figurewidget.py b/plotly/graph_objs/_figurewidget.py index 1cd94abef0a..d605b579e59 100644 --- a/plotly/graph_objs/_figurewidget.py +++ b/plotly/graph_objs/_figurewidget.py @@ -12673,6 +12673,7 @@ def add_pie( legendgroup=None, legendgrouptitle=None, legendrank=None, + legendranksrc=None, legendsrc=None, legendwidth=None, marker=None, @@ -12852,16 +12853,20 @@ def add_pie( :class:`plotly.graph_objects.pie.Legendgrouptitle` instance or dict with compatible properties legendrank - Sets the legend rank for this trace. Items and groups - with smaller ranks are presented on top/left side while - with "reversed" `legend.traceorder` they are on - bottom/right side. The default legendrank is 1000, so - that you can use ranks less than 1000 to place certain - items before all unranked items, and ranks greater than - 1000 to go after all unranked items. When having - unranked or equal rank items shapes would be displayed - after traces i.e. according to their order in data and - layout. + Sets the legend rank for this pie. If passed as an + array, this will set the legend rank of the individual + pie slices. Items and groups with smaller ranks are + presented on top/left side while with "reversed" + `legend.traceorder` they are on bottom/right side. The + default legendrank is 1000, so that you can use ranks + less than 1000 to place certain items before all + unranked items, and ranks greater than 1000 to go after + all unranked items. When having unranked or equal rank + items shapes would be displayed after traces i.e. + according to their order in data and layout. + legendranksrc + Sets the source reference on Chart Studio Cloud for + `legendrank`. legendsrc Sets the source reference on Chart Studio Cloud for `legend`. @@ -13054,6 +13059,7 @@ def add_pie( legendgroup=legendgroup, legendgrouptitle=legendgrouptitle, legendrank=legendrank, + legendranksrc=legendranksrc, legendsrc=legendsrc, legendwidth=legendwidth, marker=marker, diff --git a/plotly/graph_objs/_layout.py b/plotly/graph_objs/_layout.py index a6280a15a3d..abd1743d50c 100644 --- a/plotly/graph_objs/_layout.py +++ b/plotly/graph_objs/_layout.py @@ -99,6 +99,7 @@ def _subplot_re_match(self, prop): "hoverdistance", "hoverlabel", "hovermode", + "hoversort", "hoversubplots", "iciclecolorway", "imagedefaults", @@ -1109,6 +1110,30 @@ def hovermode(self): def hovermode(self, val): self["hovermode"] = val + @property + def hoversort(self): + """ + Determines the order of items shown in unified hover labels. If + "trace", items are sorted by trace index. If *value + descending*, items are sorted by value from largest to + smallest. If *value ascending*, items are sorted by value from + smallest to largest. Only applies when `hovermode` is *x + unified* or *y unified*. + + The 'hoversort' property is an enumeration that may be specified as: + - One of the following enumeration values: + ['trace', 'value descending', 'value ascending'] + + Returns + ------- + Any + """ + return self["hoversort"] + + @hoversort.setter + def hoversort(self, val): + self["hoversort"] = val + @property def hoversubplots(self): """ @@ -2491,6 +2516,13 @@ def _prop_descriptions(self): mode, spikelines are enabled by default perpendicular to the specified axis. If false, hover interactions are disabled. + hoversort + Determines the order of items shown in unified hover + labels. If "trace", items are sorted by trace index. If + *value descending*, items are sorted by value from + largest to smallest. If *value ascending*, items are + sorted by value from smallest to largest. Only applies + when `hovermode` is *x unified* or *y unified*. hoversubplots Determines expansion of hover effects to other subplots If "single" just the axis pair of the primary point is @@ -2793,6 +2825,7 @@ def __init__( hoverdistance=None, hoverlabel=None, hovermode=None, + hoversort=None, hoversubplots=None, iciclecolorway=None, images=None, @@ -3106,6 +3139,13 @@ def __init__( mode, spikelines are enabled by default perpendicular to the specified axis. If false, hover interactions are disabled. + hoversort + Determines the order of items shown in unified hover + labels. If "trace", items are sorted by trace index. If + *value descending*, items are sorted by value from + largest to smallest. If *value ascending*, items are + sorted by value from smallest to largest. Only applies + when `hovermode` is *x unified* or *y unified*. hoversubplots Determines expansion of hover effects to other subplots If "single" just the axis pair of the primary point is @@ -3414,6 +3454,7 @@ def __init__( "hoverdistance", "hoverlabel", "hovermode", + "hoversort", "hoversubplots", "iciclecolorway", "imagedefaults", @@ -3528,6 +3569,7 @@ def __init__( self._set_property("hoverdistance", arg, hoverdistance) self._set_property("hoverlabel", arg, hoverlabel) self._set_property("hovermode", arg, hovermode) + self._set_property("hoversort", arg, hoversort) self._set_property("hoversubplots", arg, hoversubplots) self._set_property("iciclecolorway", arg, iciclecolorway) self._set_property("images", arg, images) diff --git a/plotly/graph_objs/_pie.py b/plotly/graph_objs/_pie.py index b18aad3e2df..7afb00a3d34 100644 --- a/plotly/graph_objs/_pie.py +++ b/plotly/graph_objs/_pie.py @@ -35,6 +35,7 @@ class Pie(_BaseTraceType): "legendgroup", "legendgrouptitle", "legendrank", + "legendranksrc", "legendsrc", "legendwidth", "marker", @@ -608,21 +609,24 @@ def legendgrouptitle(self, val): @property def legendrank(self): """ - Sets the legend rank for this trace. Items and groups with - smaller ranks are presented on top/left side while with - "reversed" `legend.traceorder` they are on bottom/right side. - The default legendrank is 1000, so that you can use ranks less - than 1000 to place certain items before all unranked items, and - ranks greater than 1000 to go after all unranked items. When - having unranked or equal rank items shapes would be displayed - after traces i.e. according to their order in data and layout. + Sets the legend rank for this pie. If passed as an array, this + will set the legend rank of the individual pie slices. Items + and groups with smaller ranks are presented on top/left side + while with "reversed" `legend.traceorder` they are on + bottom/right side. The default legendrank is 1000, so that you + can use ranks less than 1000 to place certain items before all + unranked items, and ranks greater than 1000 to go after all + unranked items. When having unranked or equal rank items shapes + would be displayed after traces i.e. according to their order + in data and layout. The 'legendrank' property is a number and may be specified as: - An int or float + - A tuple, list, or one-dimensional numpy array of the above Returns ------- - int|float + int|float|numpy.ndarray """ return self["legendrank"] @@ -630,6 +634,25 @@ def legendrank(self): def legendrank(self, val): self["legendrank"] = val + @property + def legendranksrc(self): + """ + Sets the source reference on Chart Studio Cloud for + `legendrank`. + + The 'legendranksrc' property must be specified as a string or + as a plotly.grid_objs.Column object + + Returns + ------- + str + """ + return self["legendranksrc"] + + @legendranksrc.setter + def legendranksrc(self, val): + self["legendranksrc"] = val + @property def legendsrc(self): """ @@ -1416,16 +1439,20 @@ def _prop_descriptions(self): :class:`plotly.graph_objects.pie.Legendgrouptitle` instance or dict with compatible properties legendrank - Sets the legend rank for this trace. Items and groups - with smaller ranks are presented on top/left side while - with "reversed" `legend.traceorder` they are on - bottom/right side. The default legendrank is 1000, so - that you can use ranks less than 1000 to place certain - items before all unranked items, and ranks greater than - 1000 to go after all unranked items. When having - unranked or equal rank items shapes would be displayed - after traces i.e. according to their order in data and - layout. + Sets the legend rank for this pie. If passed as an + array, this will set the legend rank of the individual + pie slices. Items and groups with smaller ranks are + presented on top/left side while with "reversed" + `legend.traceorder` they are on bottom/right side. The + default legendrank is 1000, so that you can use ranks + less than 1000 to place certain items before all + unranked items, and ranks greater than 1000 to go after + all unranked items. When having unranked or equal rank + items shapes would be displayed after traces i.e. + according to their order in data and layout. + legendranksrc + Sets the source reference on Chart Studio Cloud for + `legendrank`. legendsrc Sets the source reference on Chart Studio Cloud for `legend`. @@ -1605,6 +1632,7 @@ def __init__( legendgroup=None, legendgrouptitle=None, legendrank=None, + legendranksrc=None, legendsrc=None, legendwidth=None, marker=None, @@ -1785,16 +1813,20 @@ def __init__( :class:`plotly.graph_objects.pie.Legendgrouptitle` instance or dict with compatible properties legendrank - Sets the legend rank for this trace. Items and groups - with smaller ranks are presented on top/left side while - with "reversed" `legend.traceorder` they are on - bottom/right side. The default legendrank is 1000, so - that you can use ranks less than 1000 to place certain - items before all unranked items, and ranks greater than - 1000 to go after all unranked items. When having - unranked or equal rank items shapes would be displayed - after traces i.e. according to their order in data and - layout. + Sets the legend rank for this pie. If passed as an + array, this will set the legend rank of the individual + pie slices. Items and groups with smaller ranks are + presented on top/left side while with "reversed" + `legend.traceorder` they are on bottom/right side. The + default legendrank is 1000, so that you can use ranks + less than 1000 to place certain items before all + unranked items, and ranks greater than 1000 to go after + all unranked items. When having unranked or equal rank + items shapes would be displayed after traces i.e. + according to their order in data and layout. + legendranksrc + Sets the source reference on Chart Studio Cloud for + `legendrank`. legendsrc Sets the source reference on Chart Studio Cloud for `legend`. @@ -1994,6 +2026,7 @@ def __init__( self._set_property("legendgroup", arg, legendgroup) self._set_property("legendgrouptitle", arg, legendgrouptitle) self._set_property("legendrank", arg, legendrank) + self._set_property("legendranksrc", arg, legendranksrc) self._set_property("legendsrc", arg, legendsrc) self._set_property("legendwidth", arg, legendwidth) self._set_property("marker", arg, marker) diff --git a/plotly/io/_html.py b/plotly/io/_html.py index a9ff68c23ea..c2153dc5b0b 100644 --- a/plotly/io/_html.py +++ b/plotly/io/_html.py @@ -318,11 +318,11 @@ def to_html( ) plotly_html_div = """\ -
\ +
\ {mathjax_script}\ {load_plotlyjs}\
\ +style="height:100%; width:100%;">
\ \n " '