Styling traces and hover templates

Plotly · Practical · 12 min

Consistent styling and clear tooltips are what make interactive charts feel professional rather than default.

fig.update_traces(...) sets properties on every trace, or only those matched by a selector:

fig.update_traces(marker_size=8, selector=dict(type="scatter"))
fig.update_traces(line_width=3, selector=dict(name="forecast"))

fig.for_each_trace(fn) calls a function per trace, useful for logic like renaming: fig.for_each_trace(lambda t: t.update(name=t.name.title())). Direct access also works: fig.data[0].marker.color = "red".

Hover templates define the tooltip exactly. Inside hovertemplate, %{x}, %{y}, %{text} and %{customdata[0]} insert values, with optional d3 formats after a colon: %{y:$,.2f}, %{x|%b %d, %Y} for dates. <br> breaks lines and <b> makes text bold. The secondary box with the trace name is controlled by <extra></extra>: leaving it empty hides that box.

customdata attaches extra per-point values to a trace, usually a 2D array of columns, so tooltips can show fields that are not plotted. Express does this automatically for hover_data columns.

Related layout options: hovermode ("closest", "x", "x unified"), hoverlabel=dict(bgcolor="white", font_size=12), and hoverinfo="skip" on a trace that should never show a tooltip.

Express already writes a hovertemplate; update_traces(hovertemplate=...) replaces it completely, so include every value you want shown.

Example

import plotly.express as px

df = px.data.gapminder().query("year == 2007 and continent == 'Europe'")
fig = px.scatter(df, x="gdpPercap", y="lifeExp", text="iso_alpha",
                 custom_data=["country", "pop"])
fig.update_traces(
    marker=dict(size=10, color="#3F4F75", line=dict(width=1, color="white")),
    textposition="top center",
    hovertemplate=("<b>%{customdata[0]}</b><br>"
                   "GDP: %{x:$,.0f}<br>Life exp.: %{y:.1f} yrs<br>"
                   "Pop: %{customdata[1]:,}<extra></extra>"),
    selector=dict(type="scatter"),
)
t = fig.data[0]
print(t.marker.size, t.customdata.shape)   # 10 (30, 2)
print(t.hovertemplate.endswith("<extra></extra>"))  # True
fig.write_html("europe.html")

Remember

  • update_traces with selector= styles some or all traces at once
  • hovertemplate uses %{field:format} and <extra></extra> hides the trace box
  • customdata carries extra per-point values into tooltips

Watch out for

  • Replacing an Express hovertemplate and forgetting the fields it used to show.

Check yourself

  1. In a hovertemplate, what does `<extra></extra>` do?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: plotly.com/python/hover-text-and-formatting/