Library / SDK
plotly/plotly.py avatar
plotly/plotly.py

plotly.py: a declarative Python front end for plotly.js

The interactive graphing library for Python :sparkles:

18,815 stars2,857 forksPythonMIT

At a glance

What is it?
plotly.py renders interactive charts by generating plotly.js figures, and it can also export static images through Kaleido. Here is how the package is put together, how to install it, and where it stops being the right tool.
Who is it for?
Adopt plotly.py if you are producing charts inside Jupyter, marimo, an HTML file or a Dash application and you want the browser to do the rendering. Do not adopt it if you need a server-side rasterizer with no Chrome dependency, or if you want a grammar-of-graphics API rather than a declarative figure schema.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What plotly.py is for, and who ends up using it

plotly.py is a Python package that builds chart specifications and hands the actual drawing to a browser. The README describes it as "an interactive, open-source, and browser-based graphing library for Python" built on top of plotly.js, which it calls a high-level, declarative charting library. That sentence is the whole design in miniature: Python builds a figure object, plotly.js renders it.

The audience follows from that. If you work in a Jupyter notebook, marimo, or any Python notebook software, the figure appears inline and stays interactive. If you need a standalone HTML file to hand to someone, the same figure serializes to one. If you are building a Dash application, the figure drops into it. The README lists exactly those four destinations and no others, which is a useful signal about scope: this is not a general-purpose image generator for batch pipelines.

The declarative part matters more than it sounds. You do not place marks on a canvas or manage a render loop. You describe what the chart should contain, and plotly.js decides how to draw it. That is why the same figure object can survive a round trip through JSON, a notebook cell, and a web page without you rewriting anything.

How plotly.py relates to plotly.js and the figure schema

The repository layout makes the split visible. There is a plotly/ directory holding the Python package, a js/ directory, a codegen/ directory, a templategen/ directory, and a _plotly_utils/ directory. The presence of codegen and templategen is the architectural tell: the Python API is not hand-written against the JavaScript library. It is generated from plotly.js's schema, which is why plotly.js's chart inventory becomes plotly.py's chart inventory.

The README states that plotly.js ships with over 30 chart types, listing scientific charts, 3D graphs, statistical charts, SVG maps and financial charts among them. Those arrive in Python through the generated layer. The practical consequence is that when you reach for a chart type, you are reaching for something that already exists in the JavaScript library, and the Python side is a typed wrapper around it.

Dependencies are unusually thin for a library of this reach. pyproject.toml lists only narwhals and packaging as required dependencies. narwhals is the dataframe interchange layer, which is what lets the px interface accept different dataframe libraries without plotly.py depending on any of them directly. numpy is not a hard requirement: it sits in the express optional-dependency group as numpy>=1.22. So the base install is small, and the heavier conveniences are opt-in.

Installing plotly.py and drawing a first chart

The README gives pip and conda as the two installation routes. The pip form is the one most people will use, and it is a single command with no extras.

bash
pip install plotly

The conda equivalent is `conda install -c conda-forge plotly`. After either, the README's quickstart is short enough to reproduce in full. It imports the express interface, builds a bar chart from two plain lists, and calls show().

python
import plotly.express as px
fig = px.bar(x=["a", "b", "c"], y=[1, 3, 2])
fig.show()

What you should see depends on where you ran it. In a notebook, a rendered bar chart with three bars. Outside a notebook, show() opens the figure in a browser. Note that px.bar here is given bare lists rather than a dataframe, so numpy is not needed for this example even though it is listed under the express extra.

If you want the figure to behave as a Jupyter widget rather than a static output, the README asks for two additional packages. Install jupyter and anywidget with pip, or both from conda-forge. The README does not say what changes visually once anywidget is present, only that it is required for widget support.

Static image export is a separate concern with a separate dependency. The README points at kaleido, version 1.0 or greater, installable as `pip install -U kaleido` or as python-kaleido from conda-forge. Kaleido needs Chrome or Chromium. By default it looks for a browser already on the system; if it cannot find one, the README says to run this on the command line:

bash
plotly_get_chrome

That last step is the one people miss. A container with plotly.py installed but no Chrome will import fine and fail at export time.

The static export path is where plotly.py gets awkward

Everything about plotly.py's core is browser-shaped, and static export is the part that has to work around that. Kaleido is described in the README as having minimal dependencies, which is true of the Python package and not true of the runtime: it needs Chrome or Chromium to produce an image. The README's own fallback is a command that downloads a browser, plotly_get_chrome.

For a notebook user this is invisible. For a scheduled job that renders figures to PNG on a headless worker, it is the main operational cost. You are shipping a browser into your image, or relying on a system one being present and findable. That is a real constraint, and the README documents the requirement plainly rather than hiding it.

There is a second boundary worth naming. The README lists four viewing destinations: Jupyter notebooks, other Python notebook software such as marimo, standalone HTML files, and Dash applications. A server-rendered PDF report is not on that list. If your output target is a document rather than a page, you are working against the grain of the library, and the browser dependency is the reason why.

The third limitation is less about infrastructure and more about API shape. plotly.express is a convenience layer, and the README's quickstart uses it, but the underlying model is a declarative figure schema rather than a grammar of graphics. Users coming from a layered grammar will find the express functions fast for standard charts and the transition to the lower-level graph objects less predictable than they expect. Nothing in the README promises otherwise.

plotly.py against a grammar-of-graphics library

The most natural alternative for a Python user is a grammar-of-graphics library, where a plot is composed from explicit layers and scales rather than from a chart-type function. The difference in approach shows up immediately in the quickstart. plotly.py's first example is px.bar, a named chart type with keyword arguments. A grammar system would instead ask you to declare a dataset mapping and then add a geometric layer on top of it.

That distinction has consequences. With named chart types, discovering what is available means browsing plotly.js's chart inventory, because the README states that plotly.js ships with over 30 chart types and plotly.py wraps them. With a grammar, you compose from a smaller set of primitives and the chart inventory is effectively unbounded, at the cost of writing more code for common cases.

The rendering model differs too. plotly.py output is interactive by default because plotly.js draws it in a browser. A grammar library that targets a static backend produces an image and stops there. If interactivity is the requirement, that is a decisive difference. If a reproducible raster at a fixed size is the requirement, the browser dependency in plotly.py becomes a liability the alternative does not have.

The two are not mutually exclusive in a codebase, and the choice often comes down to output target rather than API preference.

Maintenance, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-09-18. Releases are frequent: v7.1.0 on 2026-09-15, v7.0.0 on 2026-08-25, and a v7.0.0rc0 before that on 2026-07-29. The README carries a "Maintained by Plotly" badge linking to a project-maintenance page, and pyproject.toml classifies the package as "Development Status :: 5 - Production/Stable".

Those version numbers are the thing to plan around. A major version bump from 6 to 7 landed in August 2026, and there is a MIGRATION_GUIDE.md at the top level of the repository, which tells you the project expects breaking changes to need a written path. Before upgrading across a major version, read that file rather than the changelog alone.

The dependency surface keeps upgrade risk low. Only narwhals and packaging are required, and narwhals is pinned at >=1.15.1. Python support runs from 3.8 through 3.13 per the classifiers, with requires-python set to >=3.8. The optional groups are where version pressure lives: kaleido>=1.3.0 in the kaleido extra, and numpy>=1.22 in express.

On licensing, the code is MIT and the README states that documentation is released under a Creative Commons licence. MIT is permissive and imposes no obligation on how you distribute your own application. That is a statement about the licence text, not advice about your situation; if you are embedding the library in a product, have your own counsel read LICENSE.txt rather than treating this paragraph as clearance. Note also that the README offers consulting and OEM contact for dashboard development and feature additions, which is a commercial option sitting alongside the open source package.

Editorial conclusion

Adopt plotly.py if you are producing charts inside Jupyter, marimo, an HTML file or a Dash application and you want the browser to do the rendering. Do not adopt it if you need a server-side rasterizer with no Chrome dependency, or if you want a grammar-of-graphics API rather than a declarative figure schema. Before committing, verify three things in your own environment: that pip install plotly pulls narwhals and packaging without conflict, that Jupyter actually renders the widget path with jupyter and anywidget installed, and that plotly_get_chrome finds a Chrome or Chromium binary on the machine that will run your export job.

Frequently asked questions

What is plotly.py used for?

It builds interactive charts in Python and renders them through plotly.js in a browser. The README lists four destinations: Jupyter notebooks, other Python notebook software such as marimo, standalone HTML files, and Dash applications.

What does plotly.py do, and how does it relate to plotly.js?

plotly.py is a high-level, declarative charting library for Python built on top of plotly.js. The Python package generates figure specifications, and plotly.js, which the README says ships with over 30 chart types, does the drawing.

Is plotly.py free?

Yes. The code is released under the MIT licence, and the README states that documentation is released under a Creative Commons licence. The README also lists a separate consulting and OEM contact for commercial work.

What are the disadvantages of using plotly.py?

Static image export depends on Kaleido, which the README says requires Chrome or Chromium, so a headless render job needs a browser present or the plotly_get_chrome command run first. The README also lists only notebook, HTML and Dash outputs, so document-oriented pipelines are outside its stated scope.

Official sources

  1. License: MIT
  2. plotly/plotly.py on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/plotly-plotly-py.svg)](https://hysenlabs.com/projects/plotly-plotly-py)