Featured resource
Tech Upskilling Playbook 2025
Tech Upskilling Playbook

Build future-ready tech teams and hit key business milestones with seven proven plays from industry leaders.

Learn more
  • Labs icon Lab
  • Data
Labs

Build a Bubble Chart in Python to Visualize Startup Funding and Valuation Trends

In this Code Lab, you'll learn to create a professional bubble chart in Python using Plotly. You'll walk step by step through building, styling, and enhancing a visualization that shows how startup funding relates to valuation and investor interest. By the end, you'll have a polished, interactive chart ready for presentations and data storytelling.

Labs

Path Info

Level
Clock icon Intermediate
Duration
Clock icon 39m
Last updated
Clock icon Aug 14, 2025

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Step 1: Building the Basic Bubble Chart

    Step 1: Create a Basic Bubble Chart

    To begin your analysis, you’ll create a basic bubble chart that compares startup funding and valuation. Bubble charts are ideal for exploring multi-dimensional data—especially when you want to emphasize both magnitude and relationship.

    You’ll use Plotly Express to generate a chart that maps total funding against company valuation, while encoding the number of funding rounds into the bubble size. This gives an immediate sense of both scale and investment activity across startups.


    What You’ll Learn in This Step

    • Create a bubble chart using px.scatter()
    • Assign axes and bubble size using column names
    • Pass a label to help identify each point
    • Render the chart with fig.show()

    #### Open the Notebook

    From the workspace panel, open the notebook file: 1-step-one.ipynb.

    info> Important: You must save your notebook (Control or Command+S) before clicking Validate. Validation checks the most recent saved checkpoint.

    How to Complete Each Task
    • Find the matching code cell labeled Task 1.X.
    • Complete the missing code by following the # TODO comments in the cell.
    • Run the cell using the Run button or by pressing Shift+Enter.
    • Save your progress using the Save icon or by selecting File > Save and Checkpoint.
    • All code and output will appear inline in the notebook.
    ### Starting the Bubble Chart: Create a Basic Scatter Plot

    A scatter plot is the foundational structure for a bubble chart. It compares two numeric variables using Cartesian coordinates.

    In this task, you'll create a basic scatter plot to explore the relationship between startup funding amounts and company valuations.

    The plotly.express.scatter() function from the Plotly Express library is used to generate the chart.

    Required Parameters

    • x: The column for the horizontal axis
    • y: The column for the vertical axis

    #### Syntax Example
    fig = px.scatter(
        dataframe,
        x="column1",
        y="column2"
    )
    

    #### Parameter Notes
    • dataframe: The Pandas DataFrame containing the data
    • column1 and column2: Numeric fields to visualize
    • fig: The resulting Figure object

    To render the chart in the notebook, call:
    fig.show()
    ``` ### Encoding Bubble Size in a Scatter Plot
    
    To convert a basic scatter plot into a bubble chart, a third numeric variable is used to represent the size of each point.
    
    The `size` parameter in `plotly.express.scatter()` enables visualization of this third numeric dimension by scaling each marker proportionally.
    </br>
    #### How Bubble Size Works
    
    - The `size` argument accepts the name of a numeric column.
    - Larger values in that column produce larger bubbles.
    - Plotly automatically scales bubble sizes, but you can fine-tune the scaling using the size_max parameter.
    </br>
    #### Syntax Example
    
    ```python
    fig = px.scatter(
        dataframe,
        x="column1",
        y="column2",
        size="column3"
    )
    

    #### Parameter Notes
    • column3 must contain non-negative numeric values (e.g., counts, scores, revenue).
    • The chart remains a 2D scatter plot, but now includes a third visual encoding via bubble size.

    Applying Color Grouping with the color Parameter

    In a bubble chart, color can be used to group or differentiate data based on a categorical variable. Plotly Express provides the color parameter for this purpose.

    This adds an additional layer of meaning by visually separating data points by category such as industry type, region, or status.

    How the color Parameter Works

    • Accepts the name of a column with categorical values (strings or discrete labels).
    • Automatically assigns distinct colors to each category.
    • Generates a color legend for reference.

    #### Syntax Example
    fig = px.scatter(
        dataframe,
        x="column1",
        y="column2",
        size="column3",
        color="category_column"
    )
    

    #### Parameter Notes
    • category_column should contain short, interpretable labels.
    • Plotly will automatically encode the legend and assign colors accordingly.
    • The color parameter works alongside with size, allowing multiple dimensions in the same chart. ### Adding Custom Hover Labels with hover_name

    Interactive charts often display tooltips when hovering over data points. The hover_name parameter in Plotly Express allows you to specify which column’s values should appear as the main label in the tooltip.

    This is especially useful for identifying individual records—such as like startup names—without crowding the chart visually.

    How hover_name Works

    • Accepts a column name with descriptive labels, such as names or IDs.
    • The column’s values appear prominently when hovering over a point.
    • Supports string or numeric data types.

    #### Syntax Example ```python fig = px.scatter( dataframe, x="column1", y="column2", size="column3", color="category_column", hover_name="label_column" ) ```
    #### Parameter Notes * `label_column` should contain unique or identifying values (e.g., startup names). * This feature does not affect the visual layout—only the interactive tooltip content.
  2. Challenge

    Step 2: Customizing Appearance and Style

    Step 2: Customize Appearance and Style

    Now that the core bubble chart is in place, the next step is to improve its readability and visual appeal.

    In this step, you’ll adjust the bubble size scaling, apply a company-branded color palette, customize the chart’s title and axis labels, and apply a visual theme with opacity adjustments. These enhancements are essential for making charts presentation-ready and aligned stakeholder or brand guidelines.

    What You’ll Learn in This Step

    • Control bubble size scaling using size_max
    • Apply a predefined or custom color palette
    • Set axis labels and chart titles using update_layout()
    • Apply visual themes and marker styling using Plotly options

    #### Open the Notebook

    From the workspace panel, open the notebook file: 2-Step-two.ipynb.

    info> Reminder: You must save your notebook (Control or Command+S) before clicking Validate.

    How to Complete Each Task
    • Find the matching code cell labeled Task 2.X.
    • Complete the missing code by following the # TODO comments inside the cell.
    • Run the cell to preview the updated chart.
    • Save your work before validating each task.
    ### Controlling Maximum Bubble Size with `size_max`

    When using the size parameter in plotly.express.scatter(), Plotly automatically scales bubble sizes based on the data. However, the largest bubbles can sometimes overpower the chart or overlap others.

    The size_max parameter allows you to set a fixed maximum bubble diameter (in pixels), helping to maintain clarity and visual balance.

    Usage Example

    fig = px.scatter(
        dataframe,
        x="column1",
        y="column2",
        size="column3",
        size_max=50
    )
    

    #### Parameter Notes
    • size_max accepts a numeric value (e.g., 40, 60, 100).
    • Affects only the visual scaling—it does not alter the underlying data.
    • Default value is 20. Increasing it makes large bubbles appear more prominent. ### Applying a Custom Brand Palette with color_discrete_sequence

    Plotly allows full customization of category colors using the color_discrete_sequence parameter. This is useful when aligning charts with a company’s visual identity or brand guidelines.

    You can pass a list of valid CSS color names or hex codes to control the order and appearance of category colors in the chart.

    Custom Palette Syntax

    company_colors = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728"]
    

    #### Usage in `px.scatter()`
    fig = px.scatter(
        dataframe,
        x="column1",
        y="column2",
        size="column3",
        color="category_column",
        color_discrete_sequence=company_colors
    )
    

    #### Parameter Notes * `color_discrete_sequence` must be a list of valid color codes. * Colors are assigned in the order they appear in the list. * This only applies to categorical data in the `color` argument. ### Using a Predefined Plotly Color Palette and Adding Chart Labels

    Plotly provides built-in color palettes under the px.colors.qualitative module. These color sequences are designed for categorical data—meaning they help visually separate distinct groups like product names, regions, or industries.

    In this task, you’ll use a palette called Bold, which features high-contrast colors that are easy to distinguish.

    You’ll also use the update_layout() method to improve the chart's readability by customizing the axis labels and chart title.

    Set the Color Palette

    custom_colors = px.colors.qualitative.Bold
    
    • This assigns a pre-configured list of vivid colors to your custom_colors variable.
    • These colors will be used when rendering the Industry categories in your chart.

    #### Customize Chart Labels
    fig.update_layout(
        title="Startup Funding vs. Valuation",
        xaxis_title="Total Funding ($M)",
        yaxis_title="Company Valuation ($M)"
    )
    
    • title: Sets the top-level title of the chart
    • xaxis_title, yaxis_title: Replace default axis labels with clear, professional text

    About Plotly Qualitative Color Palettes

    Qualitative color scales are designed for categorical data—they provide visually distinct colors for each unique label or group.

    The px.colors.qualitative module includes several options, each with its own color feel:

    px.colors.qualitative.Bold        # High-contrast, bright palette
    px.colors.qualitative.Pastel      # Light, muted tones
    px.colors.qualitative.Set1        # Similar to ColorBrewer Set1
    px.colors.qualitative.Dark24      # For high-cardinality categories (24 total)
    px.colors.qualitative.Prism       # Vivid, non-repeating palette
    
    • Use Bold when you want the chart to “pop” with saturated colors.
    • Use Pastel when a softer tone is preferable for context or accessibility.
    • Use Dark24 when you have many categories and still want distinct colors.

    You can preview these palettes by printing them in a notebook:

    print(px.colors.qualitative.Bold)
    
    ### Applying Themes and Adjusting Marker Opacity

    Plotly Express charts can be styled visually using the template parameter. Templates control overall appearance, including background color, font, gridlines, and contrast—all without changing your data or axes.

    This task also introduces marker-level styling. By lowering opacity, you can reduce visual noise caused by overlapping points.

    Applying a Theme

    fig = px.scatter(
        dataframe,
        x="column1",
        y="column2",
        template="plotly_dark"
    )
    
    • The template parameter accepts a string corresponding to built-in Plotly theme.
    • Themes are useful when preparing charts for presentations or dark-mode dashboards.

    Adjusting Opacity

    fig.update_traces(marker=dict(opacity=0.7))
    
    • Use values between 0 (fully transparent) and 1 (fully opaque).
    • Lower opacity helps distinguish clusters and overlapping points.

    🎨 Plotly Theme Options

    These themes are available by default in Plotly:

    | Theme Name | Description | | ---------------- | --------------------------------------------------------- | | "plotly" | The default theme with a white background and gridlines. | | "plotly_dark" | Dark background, high contrast—great for presentations. | | "ggplot2" | Styled after the ggplot2 library in R. | | "seaborn" | Inspired by Seaborn aesthetics (subtle and clean). | | "simple_white" | Minimalist white background with no gridlines. | | "presentation" | Bold fonts and layout tuned for slide decks. | | "none" | Disables all theming—use when building from scratch. |

    To preview a theme, just assign it to the template parameter and rerun the chart.

  3. Challenge

    Step 3: Enhancing Interactivity and Layout

    Step 3: Enhance Interactivity and Layout

    Now that the visual design is polished, you’ll improve how users explore and interpret the chart.

    This step focuses on enhancing readability and interactivity. You’ll apply a log scale to spread out clustered values, split the chart by region using facets, and activate advanced viewer options like scroll zoom and responsive layout.

    These improvements make it easier to analyze trends and compare startup performance across different regions and funding levels.

    What You’ll Learn in This Step

    • Use log scaling to improve spread and reveal smaller values
    • Break charts into small multiples using facet_row parameter
    • Enable scroll zoom and responsive behavior in the notebook

    Open the Notebook

    From the workspace panel, open the notebook file: 3-Step-three.ipynb.

    info> Reminder: You must save your notebook (Control or Command+S) before clicking Validate.

    How to Complete Each Task
    • Locate the correct code cell labeled Task 3.X.
    • Follow the # TODO comments to implement the required changes.
    • Run the cell to preview the updated chart.
    ### Adjusting Layout: Legend Position, Margins, and Font

    Customizing chart layout helps you control how your visual appears in presentations or dashboards. In Plotly, layout-level changes are made using the update_layout() method.

    This method allows you to fine-tune non-data elements such as:

    • Legend positioning
    • Chart margins
    • Font size and styling

    Legend Position

    legend=dict(x=0.02, y=0.98)
    
    • x and y are in relative coordinates (0 to 1).
    • This places the legend in the top-left corner of the chart.

    Margin Settings

    margin=dict(l=40, r=40, t=60, b=40)
    
    • Controls the spacing between the chart and notebook edges.

    Font Size

    font=dict(size=14)
    
    • Increases legibility for labels, axes, and legends text.

    You can pass all of these into a single call to fig.update_layout() to apply visual improvements at once. ### Customizing Hover Labels for Clarity

    By default, Plotly shows all visible chart fields in hover tooltips. You can customize these tooltips to highlight only the most relevant information for your audience.

    This is done using the hover_name and hover_data parameters in px.scatter().

    Key Parameters

    hover_name="StartupName",
    hover_data={"InvestorsCount": True, "Industry": True}
    
    • hover_name controls the main bold label in the tooltip.
    • hover_data allows you to specify which additional columns appear, and whether to format or rename them.
    • You can pass a dictionary to hover_data with column names as keys and Boolean as values.

    Setting a value to True includes the column in the hover. Setting it to False hides it—even if it’s used elsewhere in the chart.

    Example Output

    This configuration will display:

    • The startup name in bold
    • Number of investors and the industry below

    Adjusting Marker Opacity and Styling

    In Plotly, visual emphasis can be enhanced using trace-level styling via update_traces() method. This allows you to change how all markers in the figure appear, such as their transparency, border, and outline color.

    Key Options for update_traces()

    fig.update_traces(
        marker=dict(
            opacity=0.6,
            line=dict(width=1, color="white")
        )
    )
    
    • opacity: Controls marker transparency (0 = fully transparent, 1 = fully opaque).
    • line.width: Adds an outline around each bubble.
    • line.color: Sets the border color.

    This method is useful when you want bubbles to overlap more cleanly or stand out better against dark themes. ### Making Charts Interactive with Layout Options

    Plotly charts can behave more like web apps when you enable interactivity options. You can control things like scroll zoom, responsiveness, and resizing behavior using the fig.update_layout() method with special parameters.

    Enabling Scroll Zoom

    fig.update_layout(
        dragmode="zoom",
        hovermode="closest"
    )
    

    This makes scroll-to-zoom active and improves how users explore dense charts.


    Making the Chart Responsive

    fig.update_layout(
        autosize=True
    )
    

    This allows the chart to adjust to the size of the display, especially helpful in dashboards or resizable interfaces.

    You can also explicitly enable web responsiveness using:

    fig.update_layout(
        uirevision=True
    )
    

    This preserves the current view even after the chart is updated, which is great for interactive notebooks and apps.

  4. Challenge

    Step 4: Creating Advanced Bubble Charts with Graph Objects

    Step 4: Creating Advanced Bubble Charts with Graph Objects

    For more advanced control over your chart’s behavior and style, you can use Plotly’s lower-level graph_objects (or go) interface.

    Unlike plotly.express, which abstracts many details for speed and ease, graph_objects allows you to directly configure every visual and interactive property of a chart.

    This is useful when you need custom marker sizing, conditional formatting, or dynamic hover labels that aren’t possible through Express.

    What You’ll Learn in This Step

    • Build a bubble chart manually using go.Scatter
    • Adjust marker size behavior using sizeref, sizemode, and sizemin
    • Add marker borders and hover templates for pixel-perfect control

    Open the Notebook

    From the workspace panel, open the notebook file: 4-Step-four.ipynb.

    info> Reminder: You must save your notebook (Control or Command+S) before clicking Validate.

    How to Complete Each Task
    • Find the matching code cell labeled Task 4.X
    • Follow the # TODO comments in each code cell to implement the required changes.
    • Run the cells and save your notebook frequently.
    ### Building a Bubble Chart with graph_objects

    Unlike plotly.express, the plotly.graph_objects (or go) interface provides low-level control over how your chart is constructed and styled.

    In this task, you’ll manually create a bubble chart using go.Scatter. This function expects separate arguments for each trace property and gives you full flexibility in formatting.

    Creating a Basic go.Scatter Chart

    import plotly.graph_objects as go
    
    fig = go.Figure(
        go.Scatter(
            x=dataframe["column_x"],
            y=dataframe["column_y"],
            mode="markers",
            marker=dict(size=dataframe["size_column"])
        )
    )
    
    • mode="markers" ensures that no lines are drawn—only points.
    • marker.size controls the size of each bubble.
    • The chart is wrapped in go.Figure() to initialize the figure and render it.

    You’ll use this foundation in later tasks to configure advanced sizing and interactivity. ### Customizing Bubble Size with Marker Settings

    When using plotly.graph_objects, you gain full control over how marker sizes are interpreted and scaled.

    This task introduces three important properties:

    1. sizemode="area"

    Specifies how to scale bubble sizes:

    • "diameter" (default): Size is applied to diameter directly.
    • "area" (recommended): Size values map to bubble's area, which creates more accurate visual comparisons.

    2. sizeref

    A scaling factor used to normalize bubble sizes within the plot. The formula to determine a good sizeref value is:

    sizeref = 2.0 * max_size_value / (desired_max_size ** 2)
    

    Example:

    sizeref = 2.0 * df["InvestorsCount"].max() / (60 ** 2)
    

    This ensures the largest bubble is no wider than 60 pixels.

    3. sizemin

    Sets the smallest visible marker size (in pixels). Use this to prevent small values from disappearing entirely. ### Adding Custom Marker Borders in graph_objects

    When you use plotly.graph_objects, each marker can be enhanced with a border (or "stroke") for better contrast and visibility.

    How Marker Borders Work

    The marker.line dictionary allows you to control the following properties:

    • width: The stroke thickness (in pixels)
    • color: The stroke color (e.g., "white")

    Example Syntax

    marker=dict(
        size=dataframe["column"],
        sizemode="area",
        sizeref=sizeref,
        sizemin=4,
        line=dict(width=1, color="white")
    )
    

    Why use marker borders?
    • They make bubbles stand out, especially on dark or visually dense charts.
    • They help differentiate overlapping markers more clearly. ### Building Custom Hover Templates in graph_objects

    When you need precise control over tooltips, graph_objects allows you to format hover text using the hovertemplate property.

    How hovertemplate Works

    Unlike hover_name or hover_data in plotly.express, the hovertemplate string uses Jinja-style variable placeholders like %{x}, %{customdata[0]}, etc.

    You can display multiple fields, include units, and control the order and labels.

    Key Concepts

    • %{x} and %{y} refer to the values of the x and y axes.
    • %{customdata[0]} accesses additional data you pass through the customdata argument.
    • hovertemplate must end with <extra></extra> to suppress the default trace label.

    Example

    customdata = df[["Industry", "Region"]].values
    
    hovertemplate = (
        "Funding: %{x}<br>" +
        "Valuation: %{y}<br>" +
        "Industry: %{customdata[0]}<br>" +
        "Region: %{customdata[1]}<extra></extra>"
    )
    
  5. Challenge

    Step 5: Exploring Animations and 3D Views

    Step 5: Exploring Animations and 3D Views

    Now that you’ve built interactive 2D visualizations, it’s time to explore some of Plotly’s more advanced capabilities.

    This step introduces animated and 3D bubble charts—both are great tools for presenting time-based data or giving your charts a visual “wow” factor.

    You’ll also practice combining multiple traces in one figure, giving you more flexibility when visualizing comparisons or layered information.

    What You’ll Learn in This Step

    • Animate a chart using animation_frame
    • Create a 3D bubble chart with px.scatter_3d()
    • Combine multiple traces with graph_objects

    Open the Notebook

    From the workspace panel, open the notebook file: 5-Step-five.ipynb.

    info> Reminder: You must save your notebook (Control or Command+S) before clicking Validate.

    How to Complete Each Task
    • Find the matching code cell labeled Task 5.X.
    • Follow the # TODO comments to implement the required changes.
    • Run your chart and save the notebook to validate.
    ### Creating Animated Bubble Charts with `animation_frame`

    Animated charts help you visualize changes across categories or time slices. Plotly’s animation_frame parameter allows you to create frame-by-frame transitions from your dataset.

    How It Works

    The animation_frame parameter tells Plotly to draw one frame per unique value in a given column. This column must be categorical or time-based.

    For example, if your dataset has a column like:

    df["ValuationCheckQuarter"].unique()
    # ['Q1', 'Q2', 'Q3', 'Q4']
    

    You can use it like this:

    fig = px.scatter(
        dataframe,
        x="column1",
        y="column2",
        size="column3",
        animation_frame="ValuationCheckQuarter"
    )
    

    Each unique quarter will animate a different view of your chart.

    Notes

    • The animation_frame column must be non-null and contain distinct, interpretable values.
    • You can combine this with hover labels, sizing, and coloring just like normal. ### Creating 3D Bubble Charts with px.scatter_3d

    3D scatter plots allow you to explore multi-variable data by mapping an additional variable to the z-axis. This can reveal clusters, ranges, or outliers that are not obvious in 2D.

    How It Works

    Plotly Express provides a function called px.scatter_3d(), which works like px.scatter() but accepts three axes: x, y, and z.

    Example syntax:

    fig = px.scatter_3d(
        dataframe,
        x="column1",
        y="column2",
        z="column3",
        size="column4",
        color="column5"
    )
    

    Notes

    • You can rotate, zoom, and pan in all 3 dimensions.
    • Use size_max to control bubble scale in 3D.
    • The x,y, and z axes should contain numeric values. ### Combining Multiple Traces in a Single Figure

    In Plotly, a trace is a single series of data—for example, a group of bubbles representing one category. By combining multiple traces, you can compare distinct groups in a single visualization.

    How It Works

    Using plotly.graph_objects, you can explicitly add each trace using add_trace(). This gives you control over how each group is styled and labeled.

    Example syntax:

    import plotly.graph_objects as go
    
    fig = go.Figure()
    
    fig.add_trace(go.Scatter(
        x=data1["x"],
        y=data1["y"],
        mode="markers",
        name="Group 1"
    ))
    
    fig.add_trace(go.Scatter(
        x=data2["x"],
        y=data2["y"],
        mode="markers",
        name="Group 2"
    ))
    
    fig.show()
    

    Each call to add_trace() adds a new layer to the chart. This is especially useful when comparing categories like industries, product types, or user segments.

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.