Custom Plot
Create custom visualizations using Python and Plotly code
Create fully customized visualizations by writing your own Python and Plotly code. This gives you complete control over your plots with access to the full Plotly library and your data.
When to Use
- Need a specific visualization not available in standard plots
- Want to combine multiple plot types in one figure
- Require advanced customization beyond standard options
- Have specific design requirements
- Need to implement complex data transformations
- Want to create specialized domain-specific visualizations
Available Variables
Your code has access to these pre-loaded libraries and variables:
Data
- df - Your Pandas DataFrame containing the data
- pd - Pandas library for data manipulation
- np - NumPy library for numerical operations
Plotting Libraries
- px - Plotly Express for quick, high-level plots
- go - Plotly Graph Objects for detailed, low-level control
- colors - Pre-defined color palette from your theme
Requirements
Your code must:
- Create a Plotly figure object
- Assign it to the variable
fig - Be valid Python code
Example:
fig = px.scatter(df, x='column1', y='column2', title='My Custom Plot')Basic Examples
Simple Scatter Plot
import plotly.express as px
fig = px.scatter(
df,
x='age',
y='salary',
title='Age vs Salary',
labels={'age': 'Age (years)', 'salary': 'Annual Salary'}
)Bar Chart with Aggregation
# Group and aggregate data
grouped = df.groupby('category')['value'].sum().reset_index()
fig = px.bar(
grouped,
x='category',
y='value',
title='Total Value by Category'
)Line Chart with Multiple Lines
fig = px.line(
df,
x='date',
y=['metric1', 'metric2', 'metric3'],
title='Multiple Metrics Over Time'
)Custom Colors
fig = px.scatter(
df,
x='x_col',
y='y_col',
color='category',
color_discrete_sequence=colors # Use theme colors
)Advanced Examples
Subplots with Multiple Chart Types
from plotly.subplots import make_subplots
import plotly.graph_objects as go
# Create subplots
fig = make_subplots(
rows=2, cols=1,
subplot_titles=('Sales Over Time', 'Profit Margin')
)
# Add line chart
fig.add_trace(
go.Scatter(x=df['date'], y=df['sales'], name='Sales'),
row=1, col=1
)
# Add bar chart
fig.add_trace(
go.Bar(x=df['date'], y=df['profit_margin'], name='Profit Margin'),
row=2, col=1
)
fig.update_layout(height=600, title_text="Sales Dashboard")Heatmap with Custom Styling
# Create pivot table
pivot = df.pivot_table(
values='value',
index='row_category',
columns='col_category',
aggfunc='mean'
)
fig = go.Figure(data=go.Heatmap(
z=pivot.values,
x=pivot.columns,
y=pivot.index,
colorscale='Viridis',
text=pivot.values,
texttemplate='%{text:.2f}',
textfont={"size": 10}
))
fig.update_layout(
title='Correlation Heatmap',
xaxis_title='Categories',
yaxis_title='Groups'
)3D Scatter Plot
fig = go.Figure(data=[go.Scatter3d(
x=df['x'],
y=df['y'],
z=df['z'],
mode='markers',
marker=dict(
size=5,
color=df['value'],
colorscale='Viridis',
showscale=True
)
)])
fig.update_layout(
title='3D Visualization',
scene=dict(
xaxis_title='X Axis',
yaxis_title='Y Axis',
zaxis_title='Z Axis'
)
)Animated Plot
fig = px.scatter(
df,
x='gdp_per_capita',
y='life_expectancy',
animation_frame='year',
animation_group='country',
size='population',
color='continent',
hover_name='country',
log_x=True,
range_x=[100, 100000],
range_y=[25, 90],
title='Gapminder Animation'
)Box Plot with Statistical Annotations
fig = go.Figure()
for category in df['category'].unique():
data = df[df['category'] == category]['value']
fig.add_trace(go.Box(
y=data,
name=category,
boxmean='sd' # Show mean and standard deviation
))
fig.update_layout(
title='Distribution by Category',
yaxis_title='Value',
showlegend=True
)Data Manipulation Examples
Filtering and Transforming
# Filter data
filtered_df = df[df['value'] > 100]
# Create new columns
filtered_df['log_value'] = np.log(filtered_df['value'])
# Create plot
fig = px.histogram(
filtered_df,
x='log_value',
title='Distribution of Log Values (filtered)'
)Rolling Averages
# Calculate 7-day rolling average
df_sorted = df.sort_values('date')
df_sorted['rolling_avg'] = df_sorted['value'].rolling(window=7).mean()
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df_sorted['date'],
y=df_sorted['value'],
name='Actual',
mode='lines',
line=dict(color='lightgray')
))
fig.add_trace(go.Scatter(
x=df_sorted['date'],
y=df_sorted['rolling_avg'],
name='7-Day Average',
mode='lines',
line=dict(color='blue', width=2)
))
fig.update_layout(title='Time Series with Rolling Average')Pivot and Reshape
# Reshape data
pivot_df = df.pivot_table(
values='sales',
index='month',
columns='product',
aggfunc='sum'
)
fig = px.imshow(
pivot_df,
labels=dict(x="Product", y="Month", color="Sales"),
title='Sales Heatmap'
)Styling and Layout
Custom Theme
fig = px.scatter(df, x='x', y='y', color='category')
fig.update_layout(
template='plotly_dark', # or 'plotly', 'seaborn', 'ggplot2', etc.
font=dict(family='Arial', size=12),
title=dict(text='Custom Styled Plot', x=0.5, xanchor='center'),
plot_bgcolor='#1e1e1e',
paper_bgcolor='#2e2e2e',
margin=dict(l=50, r=50, t=80, b=50)
)Custom Hover Templates
fig = px.scatter(df, x='x', y='y', color='category')
fig.update_traces(
hovertemplate='<b>%{fullData.name}</b><br>' +
'X: %{x:.2f}<br>' +
'Y: %{y:.2f}<br>' +
'<extra></extra>'
)Annotations and Shapes
fig = px.line(df, x='date', y='value')
# Add annotation
fig.add_annotation(
x='2023-06-15',
y=1000,
text='Peak Sales',
showarrow=True,
arrowhead=2
)
# Add horizontal line
fig.add_hline(
y=750,
line_dash='dash',
line_color='red',
annotation_text='Target'
)
# Add shaded region
fig.add_vrect(
x0='2023-01-01',
x1='2023-03-31',
fillcolor='green',
opacity=0.2,
annotation_text='Q1'
)Common Patterns
Conditional Coloring
# Add color column based on condition
df['color'] = df['value'].apply(
lambda x: 'green' if x > 0 else 'red'
)
fig = px.bar(df, x='category', y='value', color='color',
color_discrete_map={'green': '#00cc00', 'red': '#cc0000'})
fig.update_layout(showlegend=False)Multiple Y-Axes
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Scatter(x=df['date'], y=df['sales'], name='Sales'),
secondary_y=False
)
fig.add_trace(
go.Scatter(x=df['date'], y=df['profit_margin'], name='Profit %'),
secondary_y=True
)
fig.update_xaxes(title_text='Date')
fig.update_yaxes(title_text='Sales ($)', secondary_y=False)
fig.update_yaxes(title_text='Profit Margin (%)', secondary_y=True)Faceted / Small Multiples
fig = px.scatter(
df,
x='x',
y='y',
facet_col='category', # Create columns
facet_row='region', # Create rows
title='Faceted Scatter Plot'
)
fig.update_xaxes(matches=None) # Independent x-axes
fig.update_yaxes(matches=None) # Independent y-axesError Handling
Safe Data Access
# Check if columns exist
required_cols = ['x', 'y']
if all(col in df.columns for col in required_cols):
fig = px.scatter(df, x='x', y='y')
else:
# Create error message plot
fig = go.Figure()
fig.add_annotation(
text=f"Required columns not found: {required_cols}",
xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False,
font=dict(size=16, color="red")
)Handle Missing Data
# Remove or fill missing values
df_clean = df.dropna(subset=['x', 'y'])
# Or fill with mean
# df['y'] = df['y'].fillna(df['y'].mean())
fig = px.scatter(df_clean, x='x', y='y')Performance Tips
-
Filter data first - Work with smaller datasets when possible
df_sample = df.sample(n=1000) # Use sample for large datasets fig = px.scatter(df_sample, x='x', y='y') -
Use appropriate plot types - Scattergl for large scatter plots
fig = go.Figure(data=go.Scattergl(x=df['x'], y=df['y'], mode='markers')) -
Aggregate before plotting - Reduce data points
df_agg = df.groupby('date').agg({'value': 'mean'}).reset_index() fig = px.line(df_agg, x='date', y='value')
Best Practices
- Always assign to
fig- Your code must create and assign tofig - Test with small data - Verify logic before running on full dataset
- Add titles and labels - Make plots self-explanatory
- Use meaningful colors - Leverage the
colorsvariable for theme consistency - Handle edge cases - Check for empty data, missing columns, etc.
- Comment your code - Explain complex logic
- Keep it simple - Start basic, add complexity gradually
- Use built-in plots when possible - Custom code is for special cases
Debugging Tips
If your plot doesn't appear:
- Check that you assigned to
fig(notfigureor other name) - Verify column names exist in df
- Look for Python syntax errors
- Try a simple example first (e.g.,
fig = px.scatter(df))
Common errors:
- KeyError: Column name doesn't exist in DataFrame
- TypeError: Wrong data type for plot parameter
- ValueError: Data shape or format issue
Quick test:
# Minimal working example
print(df.columns) # See available columns
print(df.head()) # Preview data
fig = px.scatter(df, x=df.columns[0], y=df.columns[1])Resources
- Plotly Express Documentation
- Plotly Graph Objects Documentation
- Pandas Documentation
- NumPy Documentation
Limitations
- Pro tier required for custom code execution
- Code runs in a sandboxed environment
- Execution timeout after 30 seconds
- Maximum DataFrame size: 1M rows (sampling recommended for larger datasets)
- Cannot import additional libraries (only pre-loaded ones available)
- Cannot make external API calls or file system access
Remember: With great power comes great responsibility. Custom plots give you unlimited flexibility, but standard plots are optimized, tested, and often sufficient for most use cases. Use custom plots when you truly need the extra control.