plotly
Definitive guidelines for writing maintainable, performant, and reproducible Plotly visualizations using modern Python best practices, especially for AI/ML workflows.
स्किल
# Plotly Best Practices
Plotly 6.5.0 is a powerful tool for interactive, publication-quality visualizations, crucial for modern AI/ML workflows. These rules ensure your Plotly code is maintainable, reproducible, and production-ready, leveraging the latest features including AI-assisted Studio tools.
## Code Organization and Structure
### 1. Separate Data Preparation from Visualization
Keep data preprocessing, model outputs, and metric calculations distinct from plotting logic. This improves debugging and reusability.
❌ BAD:
```python
import pandas as pd
import plotly.express as px
def analyze_and_plot_data(raw_data: pd.DataFrame):
# Data processing mixed with plotting
processed_df = raw_data[raw_data['value'] > 0]
processed_df['normalized'] = processed_df['value'] / processed_df['value'].max()
fig = px.scatter(processed_df, x='timestamp', y='normalized', title='Normalized Data')
fig.show()
```
✅ GOOD:
```python
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
def preprocess_data(raw_data: pd.DataFrame) -> pd.DataFrame:
"""Processes raw data for visualization."""
processed_df = raw_data[raw_data['value'] > 0]
processed_df['normalized'] = processed_df['value'] / processed_df['value'].max()
return processed_df
def create_normalized_scatter_plot(data: pd.DataFrame) -> go.Figure:
"""Creates a scatter plot from processed data."""
fig = px.scatter(data, x='timestamp', y='normalized', title='Normalized Data Over Time')
return fig
# Usage example:
# raw_df = pd.read_csv('my_data.csv')
# clean_df = preprocess_data(raw_df)
# plot_fig = create_normalized_scatter_plot(clean_df)
# plot_fig.show()
```
### 2. Modular Figure Construction
Treat the `Figure` object as a modular data structure. Build traces, then define the layout. This mirrors Plotly's internal design and enhances readability.
❌ BAD:
```python
import plotly.graph_objects as go
# Hard-to-read, deeply nested dictionary for figure definition
fig = go.Figure(
data=[{'type': 'bar', 'x': [1, 2, 3], 'y': [10, 15, 13]}],
layout={'title': {'text': 'Sales Data'}, 'xaxis': {'title': {'text': 'Month'}}}
)
```
✅ GOOD:
```python
import plotly.graph_objects as go
# Separate data (traces) and layout definition
trace1 = go.Bar(x=[1, 2, 3], y=[10, 15, 13], name='Product A')
trace2 = go.Bar(x=[1, 2, 3], y=[12, 10, 18], name='Product B')
fig = go.Figure(data=[trace1, trace2])
fig.update_layout(
title_text='Monthly Sales Data',
xaxis_title_text='Month',
yaxis_title_text='Revenue ($)',
legend_title_text='Product'
)
```
## Common Patterns and Anti-patterns
### 3. Prefer Plotly Express for Most Charts
Use `plotly.express` for common chart types. It's terse, consistent, and returns a full `go.Figure` object, allowing easy customization with `graph_objects` methods.
❌ BAD:
```python
import plotly.graph_objects as go
import pandas as pd
df = pd.DataFrame({'x': [1, 2, 3], 'y': [4, 1, 2], 'category': ['A', 'B', 'A']})
# Manually creating a scatter plot with graph_objects for a simple case
fig = go.Figure(data=[
go.Scatter(x=df['x'], y=df['y'], mode='markers', marker=dict(color=df['category'].map({'A': 'red', 'B': 'blue'})))
])
fig.update_layout(title_text='Custom Scatter Plot')
```
✅ GOOD:
```python
import plotly.express as px
import pandas as pd
df = pd.DataFrame({'x': [1, 2, 3], 'y': [4, 1, 2], 'category': ['A', 'B', 'A']})
# Plotly Express handles common mappings automatically
fig = px.scatter(df, x='x', y='y', color='category', title='Simple Scatter Plot')
# Further customization is still possible
fig.update_traces(marker_size=10)
```
### 4. Apply Consistent Labeling and Theming
Ensure all plots meet publication-quality standards with clear titles, descriptive axis labels, and consistent fonts. Leverage `labels` in `px` and `update_layout` for global styling.
❌ BAD:
```python
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x='sepal_length', y='sepal_width') # No title, default labels
fig.show()
```
✅ GOOD:
```python
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df,
x='sepal_length',
y='sepal_width',
color='species',
labels={
'sepal_length': 'Sepal Length (cm)',
'sepal_width': 'Sepal Width (cm)',
'species': 'Iris Species'
},
title='Iris Sepal Dimensions by Species')
fig.update_layout(
font_family="Arial",
font_color="darkblue",
title_font_size=20,
hoverlabel_font_family="monospace"
)
fig.show()
```
## Performance Considerations
### 5. Optimize for Large Datasets
For extremely large datasets, consider data aggregation or sampling before plotting to maintain interactivity. Plotly.js can handle many points, but browser rendering has limits. Use `go.Scattergl` for hardware-accelerated rendering of large scatter plots.
❌ BAD:
```python
import plotly.express as px
import numpy as np
import pandas as pd
# Plotting 10 million points directly, which might be slow
large_df = pd.DataFrame({'x': np.random.rand(10_000_000), 'y': np.random.rand(10_000_000)})
fig = px.scatter(large_df, x='x', y='y')
fig.show() # Might freeze browser or be very sluggish
```
✅ GOOD:
```python
import plotly.graph_objects as go # Use go for Scattergl
import numpy as np
import pandas as pd
# For very large scatter plots, use go.Scattergl for WebGL acceleration
large_df = pd.DataFrame({'x': np.random.rand(10_000_000), 'y': np.random.rand(10_000_000)})
fig = go.Figure(data=[go.Scattergl(x=large_df['x'], y=large_df['y'], mode='markers')])
fig.update_layout(title_text='Large Data Scatter Plot (WebGL)')
fig.show()
# Alternatively, for other chart types, consider sampling or aggregation
# sampled_df = large_df.sample(n=100_000)
# fig = px.scatter(sampled_df, x='x', y='y', title='Sampled Data Scatter Plot')
# fig.show()
```
### 6. Choose Appropriate Output Format
For static reports or non-interactive embedding, export figures as images. For interactive dashboards, use `fig.show()` or integrate with Dash.
```python
import plotly.express as px
import pandas as pd
df = px.data.iris()
fig = px.scatter(df, x='sepal_length', y='sepal_width', color='species')
# ✅ GOOD: For interactive display in notebooks/scripts
fig.show()
# ✅ GOOD: For static image export (requires kaleido: pip install kaleido)
fig.write_image("iris_scatter.png", width=800, height=600)
# ✅ GOOD: For interactive HTML export
fig.write_html("iris_scatter.html")
```
## Common Pitfalls and Gotchas
### 7. Avoid Direct Dictionary Manipulation for Figures
While figures can be represented as dictionaries, directly building or modifying them this way bypasses Plotly's validation and convenience methods. Always use `plotly.graph_objects.Figure` or `plotly.express`.
❌ BAD:
```python
# No validation, easy to make typos
fig = {
"data": [{"type": "bar", "x": [1, 2], "y": [3, 4]}],
"layout": {"title": {"text": "My Bar Chart"}}
}
import plotly.io as pio
pio.show(fig)
```
✅ GOOD:
```python
import plotly.graph_objects as go
# Benefits from validation, docstrings, and update methods
fig = go.Figure(data=[go.Bar(x=[1, 2], y=[3, 4])])
fig.update_layout(title_text="My Bar Chart")
fig.show()
```
### 8. Leverage `update_layout` and `update_traces`
These methods provide a clean, efficient way to modify existing figures without recreating them. Use "magic underscores" for concise attribute setting.
❌ BAD:
```python
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x='sepal_length', y='sepal_width')
# Reassigning individual attributes directly is verbose and less robust
fig.layout.title.text = 'Iris Data'
fig.layout.xaxis.title.text = 'Length'
fig.layout.yaxis.title.text = 'Width'
```
✅ GOOD:
```python
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x='sepal_length', y='sepal_width')
# Use update methods with magic underscores for clarity and efficiency
fig.update_layout(
title_text='Iris Sepal Measurements',
xaxis_title_text='Sepal Length (cm)',
yaxis_title_text='Sepal Width (cm)',
font_size=12
)
fig.update_traces(marker_opacity=0.7, selector=dict(type='scatter')) # Apply to all scatter traces
```
## Type Hints
### 9. Use Type Hints for Clarity and Maintainability
Explicitly type hint Plotly `Figure` objects and related data structures (`pd.DataFrame`) in function signatures. This improves code readability and enables static analysis.
❌ BAD:
```python
import plotly.express as px
def create_plot(data): # Untyped input and output
fig = px.line(data, x='date', y='value')
return fig
```
✅ GOOD:
```python
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
def create_time_series_plot(data: pd.DataFrame) -> go.Figure:
"""Generates a time series line plot."""
fig = px.line(data, x='date', y='value', title='Time Series Analysis')
return fig
```
## Virtual Environments
### 10. Always Use Virtual Environments
Isolate your project dependencies. This is a fundamental Python best practice, critical for reproducibility, especially in AI/ML where library versions can significantly impact results.
✅ GOOD:
```bash
# Create a virtual environment
python -m venv .venv
# Activate it
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
# Install dependencies
pip install plotly pandas kaleido
```
## Packaging
### 11. Package Visualization Code
When sharing or deploying your visualization logic, package it properly (e.g., using `pyproject.toml` and `setuptools`). This ensures consistent installation and dependency management.
✅ GOOD:
```toml
# pyproject.toml example
[project]
name = "my_ml_viz"
version = "0.1.0"
dependencies = [
"plotly>=6.5.0",
"pandas",
"kaleido"
]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
```
## Testing Approaches
### 12. Implement Testing for Visualization Logic
Test functions that generate figures, focusing on data input validation and layout configuration. For complex visual changes, consider visual regression testing.
✅ GOOD:
```python
import pytest
import pandas as pd
import plotly.graph_objects as go
# Assuming create_time_series_plot is in a module named my_viz_module
# from my_viz_module import create_time_series_plot
def create_time_series_plot(data: pd.DataFrame) -> go.Figure:
"""Generates a time series line plot (for testing purposes)."""
fig = px.line(data, x='date', y='value', title='Time Series Analysis')
return fig
def test_create_time_series_plot():
# Test data
test_data = pd.DataFrame({
'date': pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-03']),
'value': [10, 12, 8]
})
fig = create_time_series_plot(test_data)
# Assertions about the figure structure and content
assert isinstance(fig, go.Figure)
assert len(fig.data) == 1
assert fig.data[0].type == 'scatter' # px.line creates scatter traces
assert fig.layout.title.text == 'Time Series Analysis'
assert fig.data[0].x.tolist() == test_data['date'].tolist()
assert fig.data[0].y.tolist() == test_data['value'].tolist()
# For visual regression, you'd compare fig.to_json() or a generated
इसे कैसे लगाएं
1. Open the tool and start a new conversation, project or template. 2. Paste the text below wherever the tool keeps standing instructions — usually called system prompt, instructions, or persona. 3. Save it so it applies to every run rather than a single message.