How to Create a Bar Chart in Plotly

Plotly is the go-to library when you need interactive, publication-quality bar charts in Python. Unlike matplotlib, every Plotly chart is interactive by default—users can hover for details, zoom into...

Key Insights

  • Plotly Express provides the fastest path to creating bar charts with px.bar(), while Graph Objects offers more granular control for complex customizations
  • Horizontal, grouped, and stacked bar charts each serve distinct analytical purposes—choose based on whether you’re comparing categories, multiple series, or part-to-whole relationships
  • Plotly’s built-in interactivity (hover tooltips, zoom, pan) makes your charts immediately more useful than static matplotlib alternatives, with zero additional code required

Introduction & Setup

Plotly is the go-to library when you need interactive, publication-quality bar charts in Python. Unlike matplotlib, every Plotly chart is interactive by default—users can hover for details, zoom into specific regions, and toggle data series on and off. This interactivity makes Plotly particularly valuable for dashboards, reports, and exploratory data analysis.

Bar charts are your tool of choice when comparing discrete categories: monthly sales figures, survey responses across demographics, or performance metrics across teams. Plotly makes creating these visualizations straightforward while giving you fine-grained control when you need it.

Install Plotly with pip:

pip install plotly

You’ll primarily work with two modules:

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

Plotly Express (px) is your high-level interface for quick charts. Graph Objects (go) provides lower-level control for complex customizations. Start with Express, move to Graph Objects when you need more power.

Creating a Basic Bar Chart

Let’s start with a simple vertical bar chart showing quarterly revenue:

import plotly.express as px

# Sample data
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
revenue = [245000, 312000, 289000, 401000]

fig = px.bar(x=quarters, y=revenue, 
             labels={'x': 'Quarter', 'y': 'Revenue ($)'},
             title='Quarterly Revenue 2024')

fig.show()

This creates an interactive bar chart with minimal code. The labels parameter customizes axis titles, and title adds a chart heading. Plotly automatically handles sizing, colors, and interactivity.

For more control, use Graph Objects:

import plotly.graph_objects as go

fig = go.Figure(data=[
    go.Bar(x=quarters, y=revenue)
])

fig.update_layout(
    title='Quarterly Revenue 2024',
    xaxis_title='Quarter',
    yaxis_title='Revenue ($)'
)

fig.show()

The Graph Objects approach is more verbose but gives you explicit control over every element. Use this when you need to layer multiple chart types or implement complex interactions.

Customizing Bar Chart Appearance

Default styling is fine for exploration, but production charts need polish. Here’s how to customize colors, labels, and formatting:

import plotly.express as px

quarters = ['Q1', 'Q2', 'Q3', 'Q4']
revenue = [245000, 312000, 289000, 401000]

fig = px.bar(x=quarters, y=revenue,
             labels={'x': 'Quarter', 'y': 'Revenue ($)'},
             title='Quarterly Revenue 2024',
             color=revenue,
             color_continuous_scale='Blues',
             text=revenue)

fig.update_traces(
    texttemplate='$%{text:,.0f}',
    textposition='outside',
    marker_line_color='rgb(8,48,107)',
    marker_line_width=1.5
)

fig.update_layout(
    title_font_size=20,
    title_x=0.5,
    xaxis_title_font_size=14,
    yaxis_title_font_size=14,
    showlegend=False,
    plot_bgcolor='rgba(0,0,0,0)',
    yaxis=dict(gridcolor='lightgray')
)

fig.show()

This example demonstrates several key customizations:

  • color parameter with a continuous scale creates a gradient based on values
  • text parameter adds data labels to bars
  • texttemplate formats labels with currency symbols and thousand separators
  • marker_line_color and marker_line_width add borders to bars
  • update_layout() controls overall chart styling including fonts, background, and grid

The result is a professional-looking chart ready for presentations or reports.

Horizontal and Grouped Bar Charts

Horizontal bar charts work better when category names are long or when you want to emphasize ranking:

import plotly.express as px

departments = ['Engineering', 'Sales', 'Marketing', 'Customer Success', 'Operations']
headcount = [45, 32, 18, 24, 15]

fig = px.bar(x=headcount, y=departments, 
             orientation='h',
             title='Headcount by Department',
             labels={'x': 'Employees', 'y': 'Department'},
             text=headcount)

fig.update_traces(textposition='outside')
fig.update_layout(yaxis={'categoryorder':'total ascending'})

fig.show()

The orientation='h' parameter creates horizontal bars. The categoryorder setting automatically sorts departments by headcount.

Grouped bar charts compare multiple data series side-by-side:

import plotly.graph_objects as go

departments = ['Engineering', 'Sales', 'Marketing', 'Customer Success']
current_year = [45, 32, 18, 24]
previous_year = [38, 29, 15, 20]

fig = go.Figure(data=[
    go.Bar(name='2024', x=departments, y=current_year),
    go.Bar(name='2023', x=departments, y=previous_year)
])

fig.update_layout(
    barmode='group',
    title='Headcount Comparison: 2024 vs 2023',
    xaxis_title='Department',
    yaxis_title='Employees',
    legend=dict(x=0.7, y=1.1, orientation='h')
)

fig.show()

The barmode='group' parameter places bars side-by-side. This layout makes year-over-year comparisons immediately obvious.

Stacked Bar Charts

Stacked bar charts show composition—how different components contribute to a total:

import plotly.graph_objects as go

months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
product_a = [23000, 25000, 28000, 31000, 29000, 33000]
product_b = [18000, 19000, 17000, 21000, 23000, 24000]
product_c = [12000, 13000, 15000, 14000, 16000, 18000]

fig = go.Figure(data=[
    go.Bar(name='Product A', x=months, y=product_a),
    go.Bar(name='Product B', x=months, y=product_b),
    go.Bar(name='Product C', x=months, y=product_c)
])

fig.update_layout(
    barmode='stack',
    title='Revenue by Product (Stacked)',
    xaxis_title='Month',
    yaxis_title='Revenue ($)',
    hovermode='x unified'
)

fig.show()

The barmode='stack' parameter stacks bars vertically. The hovermode='x unified' setting shows all series values when hovering over a month, making it easier to compare contributions.

Use stacked bars when the total matters as much as the individual components—market share analysis, budget breakdowns, or resource allocation.

Interactive Features & Export

Plotly’s interactivity is automatic, but you can enhance it with custom hover templates:

import plotly.express as px

products = ['Widget A', 'Widget B', 'Widget C', 'Widget D']
units_sold = [1250, 980, 1450, 1100]
revenue = [62500, 68600, 87000, 71500]

fig = px.bar(x=products, y=units_sold,
             title='Product Performance',
             custom_data=[revenue])

fig.update_traces(
    hovertemplate='<b>%{x}</b><br>' +
                  'Units Sold: %{y:,.0f}<br>' +
                  'Revenue: $%{customdata[0]:,.0f}<br>' +
                  '<extra></extra>'
)

fig.show()

The custom_data parameter passes additional data to hover tooltips. The hovertemplate formats how information appears on hover.

Export charts as HTML for embedding in web applications:

fig.write_html('chart.html')

Or export as static images (requires kaleido):

# Install: pip install kaleido
fig.write_image('chart.png', width=1200, height=600)

HTML exports preserve full interactivity. Static images work for PDFs, presentations, or email.

Real-World Example

Here’s a complete example analyzing customer survey responses across age groups:

import plotly.graph_objects as go
import pandas as pd

# Realistic survey data
data = {
    'age_group': ['18-25', '26-35', '36-45', '46-55', '56+'],
    'very_satisfied': [145, 203, 178, 156, 134],
    'satisfied': [98, 156, 201, 187, 178],
    'neutral': [67, 89, 112, 98, 87],
    'dissatisfied': [34, 41, 38, 47, 52],
    'very_dissatisfied': [12, 18, 15, 23, 31]
}

df = pd.DataFrame(data)

# Calculate percentages for better comparison
total_responses = df.iloc[:, 1:].sum(axis=1)
df_pct = df.iloc[:, 1:].div(total_responses, axis=0) * 100

# Create stacked percentage bar chart
fig = go.Figure(data=[
    go.Bar(name='Very Satisfied', x=df['age_group'], y=df_pct['very_satisfied'], 
           marker_color='#2ecc71'),
    go.Bar(name='Satisfied', x=df['age_group'], y=df_pct['satisfied'], 
           marker_color='#95a5a6'),
    go.Bar(name='Neutral', x=df['age_group'], y=df_pct['neutral'], 
           marker_color='#f39c12'),
    go.Bar(name='Dissatisfied', x=df['age_group'], y=df_pct['dissatisfied'], 
           marker_color='#e74c3c'),
    go.Bar(name='Very Dissatisfied', x=df['age_group'], y=df_pct['very_dissatisfied'], 
           marker_color='#c0392b')
])

fig.update_layout(
    barmode='stack',
    title='Customer Satisfaction by Age Group',
    xaxis_title='Age Group',
    yaxis_title='Percentage (%)',
    yaxis=dict(range=[0, 100]),
    legend=dict(orientation='h', y=-0.15),
    hovermode='x unified',
    plot_bgcolor='white',
    font=dict(size=12)
)

fig.update_traces(
    hovertemplate='%{y:.1f}%<extra></extra>'
)

fig.show()

# Export for reporting
fig.write_html('satisfaction_analysis.html')

This example shows data preparation, percentage calculations, custom color coding for sentiment, and professional formatting—everything you need for a production-ready visualization.

Plotly bar charts strike the perfect balance between ease of use and customization power. Start simple with Plotly Express, then layer in Graph Objects features as your requirements grow. The interactivity you get for free makes your visualizations immediately more valuable than static alternatives.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.