The idea
A table of numbers makes people squint. A chart makes them nod. Plotly Express (imported as px) is the quickest way to turn a pandas DataFrame into an interactive chart: one function call, and you get a chart you can hover over, zoom into and download as an image.
Every Plotly Express function follows the same pattern, which is why it's so easy to learn:
fig = px.chart_type(data_frame, x="column", y="column", ...)
fig.show()
You hand it a DataFrame, tell it which column goes on which axis, and it returns a figure object. fig.show() draws it. On this site, charts appear in the Output tab.
This module covers the two charts you'll use most: the line chart for change over time, and the scatter plot for the relationship between two numbers.
Line charts: how something changes over time
Here's Toko Kita's revenue for the first half of 2024:
import pandas as pd
import plotly.express as px
monthly = pd.DataFrame({
"month": ["2024-01", "2024-02", "2024-03", "2024-04", "2024-05", "2024-06"],
"revenue": [1693000, 1957000, 1517000, 4227000, 2552000, 1680000],
"orders": [6, 5, 3, 8, 5, 3],
})
fig = px.line(monthly, x="month", y="revenue", title="Monthly revenue")
fig.show()
Press Try it. You'll see a line with a clear spike in April. Hover over a point and Plotly shows the exact month and revenue, no extra code needed.
px.line()draws a line chart.- The first argument is the DataFrame. Plotly Express always wants a DataFrame (or something like one).
x="month"andy="revenue"are column names, as strings. You don't pass the values, you tell Plotly where to find them.title=sets the chart title.
Adding markers
A plain line can hide how many data points there are. markers=True adds a dot at each one:
fig = px.line(monthly, x="month", y="orders", title="Orders per month", markers=True)
fig.show()
With only six months of data, markers make it obvious that each point is one month, which stops readers from imagining data between the dots.
Use a line chart when the x-axis has a natural order (days, months, years) and you care about the trend. Joining points with a line says "these follow each other". Don't use a line for categories like product names, because there's nothing "between" a mug and a kettle.
Scatter plots: is there a relationship?
A scatter plot puts one dot per row, with one number on each axis. It answers questions like "do cheaper products sell more units?"
products = pd.DataFrame({
"product": ["Arabica Gayo 250g", "USB-C Hub", "Notebook A5 Dotted", "Pour-over Kettle",
"Gel Pen Set", "Desk Lamp LED", "Ceramic Mug", "Toraja Kalosi 250g"],
"price": [95000, 289000, 45000, 320000, 38000, 245000, 55000, 110000],
"units_sold": [12, 14, 11, 10, 3, 10, 1, 10],
})
fig = px.scatter(products, x="price", y="units_sold", hover_name="product",
title="Price vs units sold")
fig.show()
px.scatter()draws one marker per row.hover_name="product"puts the product name in bold at the top of the hover box. Without it, a reader sees a dot at (289000, 14) and has no idea which product it is.
In this data there's no clear pattern: expensive products like the USB-C Hub sell as well as cheap notebooks. That's a finding too. A scatter plot is often the fastest way to discover that a relationship you assumed doesn't exist.
The figure object
px.line() and px.scatter() don't draw anything by themselves. They return a figure, a Python object that describes the chart. Drawing it is a separate step. That separation is useful: you can build a figure, inspect it, adjust it and only then show it.
fig = px.line(monthly, x="month", y="revenue")
print(type(fig))
print(fig.data[0].type, fig.data[0].mode)
print(fig.data[0].y.tolist())
<class 'plotly.graph_objs._figure.Figure'>
scatter lines
[1693000, 1957000, 1517000, 4227000, 2552000, 1680000]
Two things worth noticing:
fig.datais a list of traces, one per series of marks. A simple chart has one trace,fig.data[0].- Plotly draws a line chart as a
scattertrace withmodeset to"lines". Scatter traces withmode="markers"are dots. In Plotly's model, lines and dots are two styles of the same trace type.
You'll work with traces directly in the Graph Objects module. For now, it's enough to know the figure is data you can inspect, and that's exactly how this site checks your charts.
A typo in a column name raises an error like ValueError: Value of 'x' is not the name of a column in 'data_frame'. Expected one of ['month', 'revenue', 'orders'] but received: Month. Read the end of the message: Plotly lists the real column names for you.
Why this matters for clean code
Keep data preparation and drawing separate: build a tidy DataFrame first (one row per point, clear column names), then make the chart in one readable px call. When the chart is wrong, you'll know whether to fix the data or the chart. And name figures by what they show, like revenue_trend or price_vs_units, once you have more than one.
Recap
import plotly.express as px, thenfig = px.function(df, x="col", y="col"), thenfig.show().- Line charts (
px.line) show change over an ordered axis like time.markers=Trueshows each data point. - Scatter plots (
px.scatter) show the relationship between two numbers.hover_name=labels each dot. title=sets the title. Columns are passed by name, as strings.- A figure is an object:
fig.dataholds its traces. A line chart is ascattertrace withmode="lines".