Module 5.3

Interactive Visualizations

Create dynamic, interactive charts with Plotly that allow users to hover, zoom, pan, and explore data. Build animated visualizations and export charts for dashboards, web applications, and presentations.

45 min
Intermediate
Hands-on
What You'll Learn
  • Plotly Express for quick charts
  • Interactive hover and zoom features
  • Animated visualizations
  • Exporting and sharing charts
  • Customizing interactivity
Contents
01

Introduction to Plotly

Plotly is a powerful library for creating interactive, publication-quality graphs. Unlike static Matplotlib or Seaborn plots, Plotly charts are fully interactive, allowing users to hover over data points, zoom, pan, and explore data dynamically. This makes Plotly ideal for dashboards, web applications, and exploratory data analysis.

Key Concept

What is Plotly?

Plotly is an open-source graphing library that makes interactive, publication-quality graphs. It supports over 40 chart types, including statistical charts, 3D plots, maps, and animations. Plotly works in Jupyter notebooks, standalone HTML files, and web applications.

Why it matters: Interactive visualizations enable deeper data exploration, better stakeholder engagement, and more intuitive understanding of complex datasets compared to static images.

Plotly vs Plotly Express

Plotly has two main interfaces: the low-level plotly.graph_objects module for fine-grained control, and the high-level plotly.express module for quick, easy charts. Plotly Express is similar in philosophy to Seaborn, providing sensible defaults and concise syntax.

Plotly Express

High-level API for quick charts with minimal code. Perfect for exploration and simple visualizations.

Graph Objects

Low-level API for full customization. Use when you need precise control over every element.

Installing and Importing Plotly

Plotly can be installed via pip. For Jupyter notebook support, you may also need to install the nbformat package. Plotly Express is conventionally imported as px.

# Install plotly (if not already installed)
# pip install plotly

# Standard imports
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np

# Check version
import plotly
print(f"Plotly version: {plotly.__version__}")

Your First Interactive Chart

Let's create a simple interactive scatter plot to see Plotly in action. Notice how you can hover over points, zoom in, and pan around the chart.

# Load built-in dataset
df = px.data.iris()

# Create an interactive scatter plot
fig = px.scatter(df, x="sepal_width", y="sepal_length", 
                 color="species", size="petal_length",
                 hover_data=["petal_width"],
                 title="Iris Dataset - Interactive Scatter Plot")

# Display the chart
fig.show()
Pro Tip: In Jupyter notebooks, Plotly charts are fully interactive. In scripts, fig.show() opens the chart in your default web browser.
02

Plotly Express Quick Charts

Plotly Express provides a simple, consistent API for creating a wide variety of chart types. Each function takes a DataFrame and column names as parameters, automatically handling axes, legends, and interactivity. Let's explore the most common chart types.

Line Charts

Line charts are perfect for showing trends over time or continuous data. Plotly Express makes it easy to create multi-line charts with automatic legend handling.

# Load stock data
df = px.data.stocks()

# Simple line chart
fig = px.line(df, x="date", y="GOOG", 
              title="Google Stock Price Over Time")
fig.show()

# Multiple lines
fig = px.line(df, x="date", y=["GOOG", "AAPL", "AMZN", "FB"],
              title="Tech Stock Comparison")
fig.show()

Bar Charts

Bar charts compare categorical data. Plotly Express supports vertical, horizontal, grouped, and stacked bar charts with the same simple syntax.

# Load gapminder data
df = px.data.gapminder()
df_2007 = df[df["year"] == 2007].nlargest(10, "pop")

# Vertical bar chart
fig = px.bar(df_2007, x="country", y="pop", 
             color="continent",
             title="Top 10 Countries by Population (2007)")
fig.show()

# Horizontal bar chart
fig = px.bar(df_2007, x="pop", y="country", 
             orientation="h", color="continent",
             title="Top 10 Countries by Population")
fig.show()

Scatter Plots

Scatter plots in Plotly Express can encode up to 5 dimensions using x, y, color, size, and symbol. Add trendlines with the trendline parameter.

# Multi-dimensional scatter plot
df = px.data.gapminder().query("year == 2007")

fig = px.scatter(df, x="gdpPercap", y="lifeExp",
                 size="pop", color="continent",
                 hover_name="country",
                 log_x=True,  # Log scale for x-axis
                 size_max=60,
                 title="GDP vs Life Expectancy (2007)")
fig.show()

# Scatter with trendline
fig = px.scatter(df, x="gdpPercap", y="lifeExp",
                 trendline="ols",  # Ordinary least squares
                 title="GDP vs Life Expectancy with Trendline")
fig.show()

Histograms and Box Plots

Distribution plots work similarly to Seaborn but with full interactivity. You can hover to see exact counts and statistics.

# Load tips dataset
df = px.data.tips()

# Histogram
fig = px.histogram(df, x="total_bill", nbins=30,
                   color="sex", barmode="overlay",
                   opacity=0.7,
                   title="Total Bill Distribution")
fig.show()

# Box plot
fig = px.box(df, x="day", y="total_bill", color="smoker",
             title="Total Bill by Day and Smoker Status")
fig.show()

# Violin plot
fig = px.violin(df, x="day", y="total_bill", color="sex",
                box=True, points="all",
                title="Total Bill Distribution by Day")

Pie and Sunburst Charts

Plotly excels at hierarchical data visualization with pie charts, sunburst diagrams, and treemaps.

# Pie chart
df = px.data.gapminder().query("year == 2007 and continent == 'Europe'")
df_top = df.nlargest(8, "pop")

fig = px.pie(df_top, values="pop", names="country",
             title="Population Distribution in Europe (Top 8)")
fig.show()

# Sunburst chart (hierarchical)
df = px.data.gapminder().query("year == 2007")

fig = px.sunburst(df, path=["continent", "country"],
                  values="pop",
                  title="World Population Hierarchy")
fig.show()

Practice: Plotly Express

Task: Using the iris dataset, create a scatter matrix showing all pairwise relationships between sepal_length, sepal_width, petal_length, and petal_width. Color by species, add diagonal histograms, and customize the opacity so overlapping points are visible.

Show Solution
import plotly.express as px

df = px.data.iris()
fig = px.scatter_matrix(df, 
    dimensions=["sepal_length", "sepal_width", 
                "petal_length", "petal_width"],
    color="species",
    opacity=0.6,
    title="Iris Species Feature Relationships")

# Update diagonal to show histograms
fig.update_traces(diagonal_visible=True)
fig.update_layout(height=800, width=800)
fig.show()

Task: Using 2007 gapminder data, create a bubble chart showing GDP per capita vs life expectancy. Size bubbles by population, color by continent, use log scale for x-axis, and add hover_name for country labels.

Show Solution
import plotly.express as px

df = px.data.gapminder().query("year == 2007")
fig = px.scatter(df, 
    x="gdpPercap", y="lifeExp",
    size="pop", color="continent",
    hover_name="country",
    log_x=True,
    size_max=60,
    title="2007: Wealth vs Health by Country")

fig.update_layout(
    xaxis_title="GDP per Capita (log scale)",
    yaxis_title="Life Expectancy (years)")
fig.show()
03

Interactive Hover & Zoom

One of Plotly's greatest strengths is its built-in interactivity. Charts automatically include zoom, pan, hover tooltips, and legend toggling. Let's learn how to customize these features for the best user experience.

Customizing Hover Text

The hover_data parameter controls which columns appear in tooltips. Use hover_name for the main label and custom_data for template formatting.

import plotly.express as px

df = px.data.gapminder().query("year == 2007")

# Add extra columns to hover
fig = px.scatter(df, x="gdpPercap", y="lifeExp",
                 size="pop", color="continent",
                 hover_name="country",  # Main label
                 hover_data={"pop": True, "gdpPercap": ":.2f"},
                 title="Hover for Country Details")
fig.show()

Custom Hover Templates

For complete control over tooltips, use hovertemplate. This uses Plotly's template syntax with placeholders like %{x}, %{y}, and custom data.

import plotly.graph_objects as go

df = px.data.gapminder().query("year == 2007 and continent == 'Europe'")

fig = go.Figure(go.Scatter(
    x=df["gdpPercap"],
    y=df["lifeExp"],
    mode="markers",
    marker=dict(size=df["pop"] / 1e6, sizemode="area", sizemin=5),
    text=df["country"],
    customdata=df[["pop", "country"]],
    hovertemplate=(
        "%{customdata[1]}
" "GDP per Capita: $%{x:,.0f}
" "Life Expectancy: %{y:.1f} years
" "Population: %{customdata[0]:,.0f}" "" # Removes secondary box ) )) fig.update_layout(title="Custom Hover Template") fig.show()

Zoom and Pan Controls

Plotly charts include a modebar with zoom, pan, and reset buttons. You can customize which buttons appear and set zoom behavior.

# Customizing the modebar
fig = px.scatter(df, x="gdpPercap", y="lifeExp",
                 color="continent")

fig.update_layout(
    # Modebar configuration
    modebar=dict(
        remove=["select2d", "lasso2d"],  # Remove buttons
        orientation="v"  # Vertical toolbar
    ),
    # Zoom/pan behavior
    dragmode="zoom",  # "zoom", "pan", "select", "lasso"
    hovermode="closest"  # "x", "y", "closest", "x unified"
)

fig.show()

Range Sliders and Selectors

For time series data, range sliders and buttons allow users to quickly zoom to specific time ranges.

import pandas as pd

# Create time series data
df = px.data.stocks()

fig = px.line(df, x="date", y="GOOG", title="Google Stock with Range Slider")

fig.update_xaxes(
    rangeslider_visible=True,  # Add range slider
    rangeselector=dict(
        buttons=list([
            dict(count=1, label="1M", step="month", stepmode="backward"),
            dict(count=6, label="6M", step="month", stepmode="backward"),
            dict(count=1, label="YTD", step="year", stepmode="todate"),
            dict(count=1, label="1Y", step="year", stepmode="backward"),
            dict(step="all", label="All")
        ])
    )
)

fig.show()

Click Events and Callbacks

In Dash applications, Plotly charts can trigger callbacks on click, hover, and selection. Even in static HTML, you can capture events with JavaScript.

# Using with Dash (for web apps)
from dash import Dash, dcc, html
from dash.dependencies import Input, Output

app = Dash(__name__)

app.layout = html.Div([
    dcc.Graph(id="scatter-plot", 
              figure=px.scatter(df, x="gdpPercap", y="lifeExp")),
    html.Div(id="click-output")
])

@app.callback(
    Output("click-output", "children"),
    Input("scatter-plot", "clickData")
)
def display_click_data(clickData):
    if clickData:
        point = clickData["points"][0]
        return f"Clicked: x={point['x']}, y={point['y']}"
    return "Click a point"

Practice: Interactivity

Task: Using the stocks dataset, create a multi-line chart showing AAPL, GOOG, and MSFT prices over time. Add a range slider for date navigation and quick-select buttons for 1 month, 6 months, YTD, and all time.

Show Solution
import plotly.express as px

df = px.data.stocks()
fig = px.line(df, x="date", y=["AAPL", "GOOG", "MSFT"],
              title="Tech Stock Price Comparison")

fig.update_xaxes(
    rangeslider_visible=True,
    rangeselector=dict(buttons=[
        dict(count=1, label="1M", step="month"),
        dict(count=6, label="6M", step="month"),
        dict(count=1, label="YTD", step="year", stepmode="todate"),
        dict(step="all", label="All")
    ])
)
fig.update_layout(yaxis_title="Price (normalized)")
fig.show()

Task: Using 2007 gapminder data, create a scatter plot where hovering shows a richly formatted tooltip with: country name (bold), continent, life expectancy, GDP per capita (formatted with $), and population (with commas). Remove the default "trace 0" secondary box.

Show Solution
import plotly.graph_objects as go
import plotly.express as px

df = px.data.gapminder().query("year == 2007")

fig = go.Figure(go.Scatter(
    x=df["gdpPercap"],
    y=df["lifeExp"],
    mode="markers",
    marker=dict(size=df["pop"]/5e6, color=df["continent"].astype('category').cat.codes),
    customdata=df[["country", "continent", "pop"]],
    hovertemplate=(
        "%{customdata[0]}
" + "Continent: %{customdata[1]}
" + "Life Expectancy: %{y:.1f} years
" + "GDP/Capita: $%{x:,.0f}
" + "Population: %{customdata[2]:,.0f}" + "" # Removes secondary box ) )) fig.update_layout(title="Hover for Country Details", xaxis_title="GDP per Capita", yaxis_title="Life Expectancy") fig.show()
04

Animated Visualizations

Plotly's animation capabilities let you create compelling visualizations that show how data changes over time or across categories. With just the animation_frame parameter, you can bring your data to life.

Basic Animations with Plotly Express

Adding animation is as simple as specifying which column to animate over. Plotly automatically creates a play button, slider, and smooth transitions.

import plotly.express as px

# The famous Gapminder animation
df = px.data.gapminder()

fig = px.scatter(df, 
                 x="gdpPercap", 
                 y="lifeExp",
                 size="pop", 
                 color="continent",
                 hover_name="country",
                 animation_frame="year",  # Animate over years
                 animation_group="country",  # Track same countries
                 log_x=True,
                 size_max=60,
                 range_x=[100, 100000],
                 range_y=[25, 90],
                 title="GDP vs Life Expectancy Over Time")

fig.show()
Note: Always set fixed range_x and range_y for animations to prevent jarring axis rescaling during playback.

Animated Bar Charts

Bar chart races are a popular way to show rankings change over time. Plotly makes these easy to create.

# Animated bar chart race
df = px.data.gapminder()
df_subset = df[df["continent"].isin(["Europe", "Asia"])]

fig = px.bar(df_subset, 
             x="country", 
             y="pop",
             color="continent",
             animation_frame="year",
             animation_group="country",
             range_y=[0, 1.5e9],
             title="Population Growth Over Time")

# Sort bars by value in each frame
fig.update_layout(
    xaxis=dict(categoryorder="total descending")
)

fig.show()

Choropleth Map Animations

Animated maps are incredibly powerful for showing geographic changes over time, such as the spread of a phenomenon or demographic shifts.

# Animated world map
df = px.data.gapminder()

fig = px.choropleth(df,
                    locations="iso_alpha",
                    color="lifeExp",
                    hover_name="country",
                    animation_frame="year",
                    color_continuous_scale="Viridis",
                    range_color=[30, 85],
                    title="Life Expectancy Around the World")

fig.update_layout(
    geo=dict(showframe=False, showcoastlines=True)
)

fig.show()

Customizing Animation Settings

Control animation speed, easing, and transition duration for smoother or faster playback.

# Customizing animation speed and transitions
fig = px.scatter(df, 
                 x="gdpPercap", y="lifeExp",
                 size="pop", color="continent",
                 animation_frame="year",
                 log_x=True,
                 range_x=[100, 100000],
                 range_y=[25, 90])

# Customize animation settings
fig.layout.updatemenus[0].buttons[0].args[1]["frame"]["duration"] = 500
fig.layout.updatemenus[0].buttons[0].args[1]["transition"]["duration"] = 300

# Customize slider
fig.layout.sliders[0].currentvalue = dict(
    prefix="Year: ",
    font=dict(size=16)
)

fig.show()

Creating Animations with Graph Objects

For complete control over animations, use go.Figure with explicit frames.

import plotly.graph_objects as go
import numpy as np

# Create animation frames manually
frames = []
t = np.linspace(0, 2*np.pi, 100)

for k in range(50):
    frame = go.Frame(
        data=[go.Scatter(
            x=t, 
            y=np.sin(t + k/10),
            mode="lines"
        )],
        name=str(k)
    )
    frames.append(frame)

# Initial figure
fig = go.Figure(
    data=[go.Scatter(x=t, y=np.sin(t), mode="lines")],
    layout=go.Layout(
        title="Animated Sine Wave",
        updatemenus=[dict(
            type="buttons",
            buttons=[dict(label="Play",
                         method="animate",
                         args=[None, {"frame": {"duration": 50}}])]
        )]
    ),
    frames=frames
)

fig.show()

Practice: Animations

Task: Create the famous animated bubble chart showing health vs wealth over time. Use GDP per capita (log scale) on x-axis, life expectancy on y-axis, bubble size for population, color by continent, and animate over years. Set fixed axis ranges so bubbles don't jump around.

Show Solution
import plotly.express as px

df = px.data.gapminder()

fig = px.scatter(df, 
    x="gdpPercap", y="lifeExp",
    size="pop", color="continent",
    hover_name="country",
    animation_frame="year",
    animation_group="country",  # Track each country
    log_x=True,
    size_max=55,
    range_x=[100, 100000],  # Fixed range
    range_y=[25, 90],
    title="The Wealth & Health of Nations Over Time")

fig.layout.updatemenus[0].buttons[0].args[1]["frame"]["duration"] = 100
fig.show()

Task: Create an animated choropleth map showing GDP per capita changes from 1952 to 2007. Use a sequential color scale that clearly shows wealth differences, fix the color range across all frames for fair comparison, and add a descriptive title.

Show Solution
import plotly.express as px

df = px.data.gapminder()

fig = px.choropleth(df,
    locations="iso_alpha",
    color="gdpPercap",
    hover_name="country",
    animation_frame="year",
    color_continuous_scale="Viridis",
    range_color=[0, 50000],  # Fixed for comparison
    labels={"gdpPercap": "GDP/Capita"},
    title="Global Wealth Distribution (1952-2007)")

fig.update_layout(
    coloraxis_colorbar=dict(title="GDP per Capita ($)"),
    geo=dict(showframe=False, showcoastlines=True)
)
fig.layout.updatemenus[0].buttons[0].args[1]["frame"]["duration"] = 300
fig.show()

Task: Filter gapminder to Asian countries and create an animated horizontal bar chart showing population over time. Sort bars by population for each frame, use a consistent y-axis range, and set a fast frame duration (150ms) for smooth playback.

Show Solution
import plotly.express as px

df = px.data.gapminder().query("continent == 'Asia'")

# Sort for each year to get bar race effect
df_sorted = df.sort_values(['year', 'pop'], ascending=[True, True])

fig = px.bar(df_sorted,
    y="country", x="pop",
    animation_frame="year",
    orientation='h',
    color="country",
    range_x=[0, 1.4e9],
    title="Asian Population Growth (1952-2007)")

fig.update_layout(
    showlegend=False,
    xaxis_title="Population",
    yaxis_title="",
    yaxis={'categoryorder': 'total ascending'}
)
fig.layout.updatemenus[0].buttons[0].args[1]["frame"]["duration"] = 150
fig.show()
05

Exporting & Sharing

Plotly charts can be exported in multiple formats for different use cases. From static images for reports to interactive HTML files for web sharing, and even embedding in Dash applications for dynamic dashboards.

Saving as Static Images

Plotly can export charts as PNG, JPEG, SVG, PDF, and WebP. You need the kaleido package for static image export.

# Install kaleido for static export
# pip install -U kaleido

import plotly.express as px

df = px.data.iris()
fig = px.scatter(df, x="sepal_length", y="sepal_width", color="species")

# Save as PNG
fig.write_image("scatter_plot.png")

# Save with custom dimensions and scale
fig.write_image("scatter_plot_hd.png", 
                width=1200, height=800, 
                scale=2)  # 2x for retina displays

# Save as SVG (vector format - great for publications)
fig.write_image("scatter_plot.svg")

# Save as PDF
fig.write_image("scatter_plot.pdf")

Interactive HTML Export

The most versatile export option preserves all interactivity. Recipients can zoom, pan, and hover without needing Python.

# Save as standalone HTML file
fig.write_html("interactive_chart.html")

# Include Plotly.js in the file (self-contained)
fig.write_html("standalone_chart.html", 
               include_plotlyjs=True,
               full_html=True)

# Just the div (for embedding in existing pages)
fig.write_html("chart_div.html",
               include_plotlyjs="cdn",  # Use CDN
               full_html=False)

# Minimal file size with CDN
fig.write_html("minimal_chart.html",
               include_plotlyjs="cdn",
               config={"responsive": True})

Saving and Loading as JSON

Plotly figures can be serialized to JSON for storage, version control, or later reconstruction in any language.

import plotly.io as pio

# Save figure as JSON
fig.write_json("figure.json")

# Load figure from JSON
loaded_fig = pio.read_json("figure.json")
loaded_fig.show()

# Get JSON string
json_string = fig.to_json()

# Recreate from JSON string
import plotly.io as pio
fig_from_json = pio.from_json(json_string)

Customizing Export Settings

Control export appearance with templates, fonts, and layout configurations.

# Set default template
import plotly.io as pio
pio.templates.default = "plotly_white"

# Update layout for export
fig.update_layout(
    font_family="Arial",
    title_font_size=24,
    legend_font_size=14,
    paper_bgcolor="white",
    plot_bgcolor="white",
    margin=dict(l=50, r=50, t=80, b=50)
)

# Save with white background
fig.write_image("publication_ready.png",
                width=800, height=600)

Embedding in Dash Applications

For interactive web applications, Dash provides a full framework for building Plotly dashboards.

# pip install dash

from dash import Dash, dcc, html
import plotly.express as px

# Create app
app = Dash(__name__)

# Create figure
df = px.data.gapminder()
fig = px.scatter(df.query("year==2007"), 
                 x="gdpPercap", y="lifeExp",
                 color="continent", size="pop")

# Layout
app.layout = html.Div([
    html.H1("My Plotly Dashboard"),
    dcc.Graph(figure=fig)
])

# Run server
if __name__ == "__main__":
    app.run_server(debug=True)

Sharing on Plotly Chart Studio

Plotly Chart Studio provides cloud hosting for interactive charts with sharing and collaboration features.

# pip install chart-studio

import chart_studio
import chart_studio.plotly as py

# Set credentials (get from chart-studio.plotly.com)
chart_studio.tools.set_credentials_file(
    username='your_username',
    api_key='your_api_key'
)

# Upload figure to Chart Studio
py.plot(fig, filename='my_chart', auto_open=True)

# Get embed URL
url = py.plot(fig, filename='my_chart', auto_open=False)
embed_url = url + ".embed"

Practice: Exporting

Task: Create an interactive gapminder bubble chart and export it as a lightweight HTML file suitable for embedding in a blog. Use CDN for Plotly.js (smaller file size), generate only the div content (not full HTML), and keep the file self-contained.

Show Solution
import plotly.express as px

df = px.data.gapminder().query("year == 2007")
fig = px.scatter(df, x="gdpPercap", y="lifeExp",
                 color="continent", size="pop",
                 hover_name="country", log_x=True,
                 title="2007 Global Health vs Wealth")

# Export for blog embedding
fig.write_html(
    "blog_chart.html",
    include_plotlyjs="cdn",  # Use CDN for smaller file
    full_html=False,  # Just the div
    config={"displayModeBar": False}  # Hide toolbar
)

# Also save a full standalone version
fig.write_html("standalone_chart.html", include_plotlyjs="cdn")

Task: Create a publication-ready scatter plot with: Times New Roman font, white backgrounds, 300 DPI resolution, specific dimensions (7 inches wide for single-column journals), clean axis titles, and export as both SVG (for vector graphics) and high-resolution PNG.

Show Solution
import plotly.express as px

df = px.data.iris()
fig = px.scatter(df, x="sepal_length", y="petal_length",
                 color="species", symbol="species")

# Publication formatting
fig.update_layout(
    font=dict(family="Times New Roman", size=12),
    title=None,  # Usually added in figure caption
    paper_bgcolor="white",
    plot_bgcolor="white",
    margin=dict(l=60, r=20, t=20, b=60),
    legend=dict(title="Species", yanchor="top", y=0.99, 
                xanchor="right", x=0.99)
)

fig.update_xaxes(title="Sepal Length (cm)", showline=True, 
                 linewidth=1, linecolor='black', mirror=True)
fig.update_yaxes(title="Petal Length (cm)", showline=True,
                 linewidth=1, linecolor='black', mirror=True)

# Export for publication (7 inches = ~700px at 100 DPI)
fig.write_image("figure1.svg", width=700, height=500)  # Vector
fig.write_image("figure1.png", width=2100, height=1500, scale=3)  # 300 DPI

Task: Create a customized chart, save it as JSON (preserving all settings), then load it back and verify it looks identical. This is useful for saving chart templates or sharing configurations with colleagues.

Show Solution
import plotly.express as px
import plotly.io as pio

# Create and customize
df = px.data.tips()
fig = px.box(df, x="day", y="total_bill", color="smoker",
             title="Weekend Spending Patterns")
fig.update_layout(
    xaxis_title="Day of Week",
    yaxis_title="Total Bill ($)",
    legend_title="Smoker"
)

# Save configuration
fig.write_json("chart_config.json")
print("Chart saved!")

# Later: restore the chart
loaded_fig = pio.read_json("chart_config.json")
loaded_fig.show()  # Identical to original!

Key Takeaways

Plotly Express for Speed

Use px.scatter(), px.bar(), px.line() for quick, interactive charts with minimal code. Express handles axes, legends, and colors automatically.

Built-in Interactivity

Every Plotly chart includes zoom, pan, hover tooltips, and legend toggling. Use hover_data and hovertemplate to customize what users see.

Easy Animations

Add animation_frame="column" to animate over time. Use animation_group to track items and fixed range_x/y for smooth playback.

Graph Objects for Control

When you need complete customization, use go.Figure() with go.Scatter(), go.Bar() etc. Combine with update_layout() for fine-tuning.

Multiple Export Formats

Use write_image() for PNG/SVG/PDF and write_html() for interactive sharing. JSON export enables version control and cross-language compatibility.

Web-Ready Visualizations

Plotly charts work seamlessly in Jupyter notebooks, Dash applications, and static HTML pages. They're designed for web-first, interactive data exploration.

Knowledge Check

Test your understanding of Plotly interactive visualizations with this quick quiz.

Question 1 of 6

Which function creates a scatter plot in Plotly Express?

Question 2 of 6

Which parameter adds animation to a Plotly Express chart?

Question 3 of 6

What package is needed to export Plotly charts as PNG images?

Question 4 of 6

Which method saves a Plotly figure as an interactive HTML file?

Question 5 of 6

What does hover_name do in Plotly Express?

Question 6 of 6

Which import is used for fine-grained control over Plotly charts?

Answer all questions to check your score