# Plotly Tutorial for Python: Basic Interactive Charts (Plotly Part 1)

> Plotly tutorial for Python: interactive charts in one Plotly Express call, when to use Graph Objects, styling, faceting, and HTML exports 100x smaller.

- **Author:** Vanshika Nigam — ETL & Data Engineer, Accenture (https://www.1stepgrow.com/authors/vanshika-nigam/)
- **Published:** Aug 2, 2026 · **Updated:** Sep 17, 2026
- **Topic:** Python & Programming · **Format:** Guide · **Read time:** 9 min
- **Canonical URL:** https://www.1stepgrow.com/articles/plotly-tutorial/

## Key takeaways

- Plotly Express is the high-level API; use it for most charts and drop to Graph Objects only when you need control.
- Interactivity (hover, zoom, pan) comes free and is the main reason to choose Plotly over matplotlib.
- Plotly Express works best with tidy data: one row per observation, one column per variable.
- fig.update_layout() is where most styling happens, and template='plotly_white' fixes the default look in one argument.

This Plotly tutorial shows you how to make interactive charts in Python: install `plotly`, pass a DataFrame to one Plotly Express call such as `px.line`, and you get a chart you can hover over, zoom into and pan around. Where matplotlib produces static images, Plotly gives you that interactivity with no extra work.

The defaults hide a few surprises. A blank figure in Jupyter often comes down to outdated Notebook packages, and the default HTML export of one chart below weighed 4.8 MB against under 40 KB with a single argument changed. This first part is for Python users who know a little pandas and want charts for screens: Express versus Graph Objects, the everyday chart types, styling, faceting and saving.

As of September 2026 the current release is Plotly 7.1. The examples here were run on Plotly 6.3, and the [Plotly 7.0 release notes](https://github.com/plotly/plotly.py/releases/tag/v7.0.0) removes nothing they use.

## How do you install Plotly?

Run `pip install plotly` (with pandas for the examples), and add `anywidget` if you work in Jupyter:

```bash
pip install plotly pandas
```

If you use conda, `conda install -c conda-forge plotly` works too. For notebooks, the [Plotly getting-started page](https://plotly.com/python/getting-started/) lists `jupyterlab` and `anywidget` for JupyterLab, or `notebook>=7.0` and `anywidget` for the classic interface. If you still need a Python environment, the [Anaconda on Windows guide](https://www.1stepgrow.com/articles/install-anaconda-windows) covers the setup.

## What are Plotly Express and Graph Objects?

Plotly has a high-level and a low-level interface, and knowing which you are using prevents most confusion.

**Plotly Express** (`plotly.express`, conventionally `px`) builds a whole figure from a DataFrame in one call. It handles the large majority of charts.

**Graph Objects** (`plotly.graph_objects`, conventionally `go`) constructs figures trace by trace. It is more verbose, but necessary when you need control Express does not expose.

Express returns a Graph Objects figure, so you can start high-level and refine afterwards. That is the workflow to aim for.

```python
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
```

## How do you make basic charts with Plotly Express?

Plotly Express works best with **tidy data**: one row per observation, one column per variable.

```python
df = pd.DataFrame({
    'month': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
    'revenue': [120, 145, 132, 178, 195],
    'region': ['North', 'North', 'North', 'North', 'North'],
})

fig = px.line(df, x='month', y='revenue', title='Monthly revenue')
fig.show()
```

That is a complete interactive chart. Axis labels come from the column names, and hover and zoom work straight away.

**Bar chart:**

```python
fig = px.bar(df, x='month', y='revenue',
             title='Revenue by month',
             labels={'revenue': 'Revenue (₹k)', 'month': 'Month'})
fig.show()
```

**Scatter, with a third variable encoded as colour and a fourth as size:**

```python
world = px.data.gapminder().query("year == 2007")   # 142 countries

fig = px.scatter(
    world,
    x='gdpPercap', y='lifeExp',
    size='pop', color='continent',
    hover_name='country',
    log_x=True,
    size_max=55,
    title='Life expectancy vs GDP per capita, 2007',
)
fig.show()
```

`hover_name` is the small detail that makes Plotly worth using, because hovering a point names the country rather than showing bare coordinates. The gapminder sample data ships with Plotly, so this runs offline.

**Histogram and box plot:**

```python
px.histogram(world, x='lifeExp', nbins=30)
px.box(world, x='continent', y='lifeExp', points='outliers')
```

### Worked example: tidy data with several series

When you have more than one region, keep the data long and let `color` split the lines:

```python
sales = pd.DataFrame({
    'month':   ['Jan', 'Feb', 'Mar'] * 2,
    'region':  ['North'] * 3 + ['South'] * 3,
    'revenue': [120, 145, 132, 90, 110, 128],
})

fig = px.line(sales, x='month', y='revenue', color='region', markers=True)
fig.show()
```

Each region becomes its own trace with its own legend entry. Plotly Express also accepts wide data, for example `y=['north', 'south']` for two columns, but long data scales better once you add faceting.

## How do you style a Plotly chart?

Use `update_layout` for titles, axes, templates and hover behaviour, and `update_traces` for lines and markers. Most adjustments go through `update_layout`:

```python
fig = px.line(df, x='month', y='revenue')

fig.update_layout(
    title={'text': 'Monthly revenue', 'x': 0.02, 'font': {'size': 20}},
    xaxis_title='Month',
    yaxis_title='Revenue (₹ thousands)',
    template='plotly_white',
    hovermode='x unified',
    margin={'l': 60, 'r': 30, 't': 60, 'b': 50},
    showlegend=False,
)
fig.show()
```

Two of those are worth calling out. `template='plotly_white'` replaces the default grey background with something publishable. Meanwhile, `hovermode='x unified'` shows every series at the hovered x-position in one tooltip, which is almost always what you want on a multi-line chart.

Trace-level styling uses `update_traces`:

```python
fig.update_traces(line={'width': 3, 'color': '#2563eb'},
                  mode='lines+markers')
```

## When should you drop to Graph Objects?

When Express cannot express what you need, typically mixing chart types, build the figure directly:

```python
fig = go.Figure()

fig.add_trace(go.Bar(
    x=df['month'], y=df['revenue'],
    name='Revenue', marker_color='#2563eb',
))

fig.add_trace(go.Scatter(
    x=df['month'], y=df['revenue'].rolling(2).mean(),
    name='2-month average',
    mode='lines+markers',
    line={'color': '#f59e0b', 'width': 3},
))

fig.update_layout(title='Revenue with trend',
                  template='plotly_white')
fig.show()
```

The pattern is always the same: create a `go.Figure()`, call `add_trace` for each series, then `update_layout`. The two-month average starts with a gap because the first month has no previous value to average with.

## How do you make small multiples in Plotly?

Pass `facet_col` (and `facet_col_wrap`) to a Plotly Express function. Small multiples in one argument are Express's strongest feature:

```python
gap = px.data.gapminder()

fig = px.line(
    gap.query("continent == 'Asia'"),
    x='year', y='lifeExp',
    facet_col='country', facet_col_wrap=5,
    height=800,
)
fig.update_yaxes(matches=None)   # independent y-axes per panel
fig.show()
```

The Asia subset has 33 countries, so this draws seven rows of panels. Doing that by hand in Graph Objects takes dozens of lines. The [facet plots guide](https://plotly.com/python/facet-plots/) covers `facet_row` and shared axes in more depth.

## How do you save a Plotly chart?

Use `write_html` for an interactive file and `write_image` for PNG or PDF:

```python
fig.write_html('chart.html')                          # interactive, self-contained
fig.write_html('chart_cdn.html', include_plotlyjs='cdn')  # small, loads Plotly.js online
```

The default HTML file embeds the whole Plotly.js library, so it is large (4.8 MB for the facet chart above on Plotly 6.3) but works offline. With `include_plotlyjs='cdn'` the same chart shrank to under 40 KB, although the reader then needs an internet connection. The [HTML export guide](https://plotly.com/python/interactive-html-export/) explains the other options.

For a PNG or PDF, use `fig.write_image('chart.png', scale=2)`. According to the [static image export guide](https://plotly.com/python/static-image-export/), this needs Kaleido 1.0 or later and a Chrome or Chromium install on the machine.

## Plotly Express quick reference

This table collects the functions used in this Plotly tutorial:

| Chart | Function | Key arguments |
|---|---|---|
| Line | `px.line` | `x`, `y`, `color`, `markers=True` |
| Bar | `px.bar` | `x`, `y`, `color`, `barmode` |
| Scatter / bubble | `px.scatter` | `size`, `color`, `hover_name`, `log_x` |
| Distribution | `px.histogram` | `x`, `nbins` |
| Groups | `px.box` | `x`, `y`, `points` |
| Small multiples | any of the above | `facet_col`, `facet_col_wrap` |

## Common mistakes in a first Plotly project

- **Passing wide data with many series.** Reshape to long form with `pandas.melt`, then use `color`.
- **Calling `write_image` without Kaleido or Chrome.** Install Kaleido 1.0+, then run `plotly_get_chrome` if no browser is found.
- **Emailing 5 MB HTML files.** Use `include_plotlyjs='cdn'` when the reader will be online.
- **Styling every chart by hand.** Set `template='plotly_white'` once, then change only what matters.
- **Using an old Jupyter Notebook.** Plotly 6 and later need Notebook 7 or JupyterLab.

## What comes next in this Plotly tutorial?

[Part two](https://www.1stepgrow.com/articles/advanced-plotly-charts) covers subplots, secondary axes, animation, 3D charts and annotation: the customisation that turns a working chart into a presentable one.



## Related reading

[Plotly Part 2: advanced charts](https://www.1stepgrow.com/articles/advanced-plotly-charts) continues this series. For the static alternative, see [matplotlib styling and customisation](https://www.1stepgrow.com/articles/matplotlib-styling-customization). Plotly charts are built on arrays, so the [NumPy tutorial series](https://www.1stepgrow.com/articles/numpy-tutorial) is useful background.

## Frequently asked questions

### Should I use Plotly Express or Graph Objects?

Start with Plotly Express. It builds a complete figure from a DataFrame in one call and returns a normal Graph Objects figure, so you can refine it afterwards. Move to Graph Objects when you need several trace types on one set of axes, fine-grained control over each trace, or a chart type that Express does not cover.

### Should I use Plotly or matplotlib?

Use Plotly for anything read on a screen where hover and zoom help, such as dashboards, exploratory analysis and charts shared with colleagues. Use matplotlib for print, academic papers and precise static layouts. Many analysts use both: Plotly while exploring the data, and matplotlib when a figure has to go into a PDF or a slide at a fixed size.

### Do Plotly charts work in Jupyter?

Yes, they render inline and stay interactive. Plotly's own instructions for JupyterLab are to install jupyterlab and anywidget in the same environment. For the classic interface you need Jupyter Notebook 7 or later plus anywidget, because Plotly 6 dropped support for Notebook 6. If a figure appears blank, check those package versions first.

### How do I save a Plotly chart as an image?

fig.write_html('chart.html') keeps full interactivity and needs nothing extra. fig.write_image('chart.png') produces a static image but requires Kaleido 1.0 or later, which in turn needs Chrome or Chromium on the machine. If Chrome is missing, Plotly provides the plotly_get_chrome command to install a copy it can use.

---
_Source: 1stepGrow (https://www.1stepgrow.com/articles/plotly-tutorial/). Cite with the title, "1stepGrow" and a link._
