Visualization & Plotting
Ossify provides comprehensive 2D plotting capabilities for neuromorphological data with precise unit control, flexible styling, and publication-ready output.
Overview
| Function Category | Functions | Purpose |
|---|---|---|
| Cell Plotting | plot_cell_2d, plot_cell_multiview |
Integrated visualization of complete cells |
| Layer Plotting | plot_morphology_2d, plot_annotations_2d, plot_skeleton, plot_points |
Individual layer visualization |
| Figure Management | single_panel_figure, multi_panel_figure, add_scale_bar |
Layout and annotation utilities |
Cell Plotting
plot_cell_2d
plot_cell_2d
plot_cell_2d(cell: Cell, color: Optional[Union[str, ndarray, tuple]] = None, palette: Union[str, dict] = 'coolwarm', color_norm: Optional[Tuple[float, float]] = None, alpha: Optional[Union[str, ndarray, float]] = 1.0, alpha_norm: Optional[Tuple[float, float]] = None, linewidth: Optional[Union[str, ndarray, float]] = 1.0, linewidth_norm: Optional[Tuple[float, float]] = None, widths: Optional[tuple] = (1, 50), root_marker: bool = False, root_size: float = 100.0, root_color: Optional[Union[str, tuple]] = None, synapses: Literal['pre', 'post', 'both', True, False] = False, pre_anno: str = 'pre_syn', pre_color: Optional[Union[str, tuple]] = None, pre_palette: Union[str, dict] = None, pre_color_norm: Optional[Tuple[float, float]] = None, syn_alpha: float = 1, syn_size: Optional[Union[str, ndarray, float]] = None, syn_size_norm: Optional[Tuple[float, float]] = None, syn_sizes: Optional[ndarray] = (1, 30), post_anno: str = 'post_syn', post_color: Optional[Union[str, tuple]] = None, post_palette: Union[str, dict] = None, post_color_norm: Optional[Tuple[float, float]] = None, projection: Union[str, Callable] = 'xy', offset_h: float = 0.0, offset_v: float = 0.0, invert_y: bool = True, ax: Optional[Axes] = None, units_per_inch: Optional[float] = None, dpi: Optional[float] = None, despine: bool = True, **syn_kwargs) -> Tuple[Figure, Axes]
Comprehensive 2D visualization of complete cells with skeleton, annotations, and flexible styling.
Usage Examples
import ossify
import matplotlib.pyplot as plt
# Load cell with skeleton and synapses
cell = ossify.load_cell("neuron.osy")
# Basic plot with compartment coloring
fig, ax = ossify.plot_cell_2d(
cell,
color="compartment", # Color by axon/dendrite
projection="xy", # XY projection
synapses=True # Show both pre/post synapses
)
# Advanced styling with custom parameters
fig, ax = ossify.plot_cell_2d(
cell,
color="strahler_order", # Hierarchical coloring
palette="viridis", # Scientific colormap
linewidth="radius", # Width by branch radius
widths=(1, 20), # Min/max linewidth range
alpha=0.8, # Semi-transparent
root_as_sphere=True, # Mark root location
root_size=150, # Root marker size
synapses="pre", # Only presynaptic sites
pre_color="red", # Synapse color
syn_size=30, # Synapse marker size
projection="zy", # Side view
units_per_inch=50000, # 50,000 nm per inch
despine=True # Clean axes
)
plt.show()
Color and Style Options
# Discrete compartment coloring
plot_cell_2d(cell, color="compartment", palette={"axon": "red", "dendrite": "blue"})
# Continuous property coloring
plot_cell_2d(cell, color="distance_to_root", palette="plasma", color_norm=(0, 500000))
# Multi-property styling
plot_cell_2d(
cell,
color="strahler_order", # Color by hierarchy
alpha="confidence", # Transparency by confidence
linewidth="thickness", # Width by morphology
alpha_norm=(0.3, 1.0), # Alpha range
linewidth_norm=(0.5, 5.0), # Width range
widths=(2, 40) # Final width scaling
)
Synapse Visualization
# Separate pre/post synapse styling
plot_cell_2d(
cell,
synapses="both",
pre_anno="pre_syn", # Presynaptic annotation layer
pre_color="red", # Presynaptic color
pre_palette="Reds", # If coloring by property
post_anno="post_syn", # Postsynaptic annotation layer
post_color="blue", # Postsynaptic color
post_palette="Blues", # If coloring by property
syn_size="activity", # Size by synapse activity
syn_sizes=(10, 100), # Size range
syn_alpha=0.7 # Synapse transparency
)
plot_cell_multiview
plot_cell_multiview
plot_cell_multiview(cell: Cell, layout: Literal['stacked', 'side_by_side', 'three_panel'] = 'three_panel', color: Optional[Union[str, ndarray, tuple]] = None, palette: Union[str, dict] = 'coolwarm', color_norm: Optional[Tuple[float, float]] = None, alpha: Optional[Union[str, ndarray, float]] = 1.0, alpha_norm: Optional[Tuple[float, float]] = None, linewidth: Optional[Union[str, ndarray, float]] = 1.0, linewidth_norm: Optional[Tuple[float, float]] = None, widths: Optional[tuple] = (1, 50), root_marker: bool = False, root_size: float = 100.0, root_color: Optional[Union[str, tuple]] = None, synapses: Literal['pre', 'post', 'both', True, False] = False, pre_anno: str = 'pre_syn', pre_color: Optional[Union[str, tuple]] = None, pre_palette: Union[str, dict] = None, pre_color_norm: Optional[Tuple[float, float]] = None, syn_alpha: float = 1, syn_size: Optional[Union[str, ndarray, float]] = None, syn_size_norm: Optional[Tuple[float, float]] = None, syn_sizes: Optional[ndarray] = (1, 30), post_anno: str = 'post_syn', post_color: Optional[Union[str, tuple]] = None, post_palette: Union[str, dict] = None, post_color_norm: Optional[Tuple[float, float]] = None, invert_y: bool = True, despine: bool = True, units_per_inch: float = 100000, dpi: Optional[float] = None, **syn_kwargs) -> Tuple[Figure, dict]
Multi-panel visualization showing different anatomical projections.
Usage Examples
# Three-panel L-shaped layout (default)
fig, axes = ossify.plot_cell_multiview(
cell,
layout="three_panel", # xy (bottom-left), xz (top-left), zy (bottom-right)
color="compartment",
units_per_inch=100000, # Scale factor
gap_inches=0.3 # Panel spacing
)
# Side-by-side comparison (xy | zy)
fig, axes = ossify.plot_cell_multiview(
cell,
layout="side_by_side",
color="strahler_order",
palette="cmc.hawaii",
synapses=True,
units_per_inch=75000
)
# Stacked layout (xz over xy)
fig, axes = ossify.plot_cell_multiview(
cell,
layout="stacked",
color="distance_to_root",
palette="magma",
root_as_sphere=True
)
# Access individual axes
xy_ax = axes["xy"]
xz_ax = axes["xz"]
zy_ax = axes["zy"]
# Add titles or annotations
xy_ax.set_title("Horizontal View (XY)")
zy_ax.set_title("Side View (ZY)")
Layer Plotting
plot_morphology_2d
plot_morphology_2d
plot_morphology_2d(cell: Union[Cell, SkeletonLayer], color: Optional[Union[str, ndarray, tuple]] = None, palette: Union[str, dict] = 'coolwarm', color_norm: Optional[Tuple[float, float]] = None, alpha: Optional[Union[str, ndarray, float]] = 1.0, alpha_norm: Optional[Tuple[float, float]] = None, alpha_extent: Optional[Tuple[float, float]] = None, linewidth: Optional[Union[str, ndarray, float]] = 1.0, linewidth_norm: Optional[Tuple[float, float]] = None, widths: Optional[tuple] = (1, 50), projection: Union[str, Callable] = 'xy', offset_h: float = 0.0, offset_v: float = 0.0, root_marker: bool = False, root_size: float = 100.0, root_color: Optional[Union[str, tuple]] = None, zorder: int = 2, invert_y: bool = True, ax: Optional[Axes] = None) -> Axes
Plot 2D skeleton with flexible styling options.
Parameters:
-
cell(Cell or SkeletonLayer) –Cell or SkeletonLayer to plot
-
projection(str or Callable, default:"xy") –Projection function or string mapping 3d points to a 2d projection.
-
color(str, np.ndarray, or tuple, default:None) –Color specification - can be feature name, array of values, or matplotlib color
-
palette(str or dict, default:"coolwarm") –Colormap for mapping array values to colors
-
color_norm(tuple of float, default:None) –(min, max) tuple for color normalization
-
alpha(str, np.ndarray, or float, default:1.0) –Alpha specification - can be feature name, array, or single value
-
alpha_norm(tuple of float, default:None) –(min, max) tuple for alpha normalization
-
linewidth(str, np.ndarray, or float, default:1.0) –Linewidth specification - can be feature name, array, or single value
-
linewidth_norm(tuple of float, default:None) –(min, max) tuple for linewidth normalization
-
widths(tuple, default:(1, 50)) –(min, max) tuple for final linewidth scaling
-
ax(Axes, default:None) –Matplotlib axes
Returns:
-
Axes–Matplotlib axes with skeleton plotted
Flexible 2D plotting of skeleton morphology with advanced styling.
Usage Examples
# Basic skeleton plotting
ax = ossify.plot_morphology_2d(
cell.skeleton, # Can use Cell or SkeletonLayer
projection="xy"
)
# Advanced styling
ax = ossify.plot_morphology_2d(
cell,
color="branch_order", # Color by topological property
palette="Set1", # Discrete colormap
alpha="confidence", # Transparency by data quality
linewidth="diameter", # Width by branch diameter
linewidth_norm=(0.1, 10.0), # Diameter range (μm)
widths=(0.5, 25), # Plot width range (points)
projection="xz", # Sagittal view
offset_h=1000, # Horizontal offset (nm)
offset_v=500, # Vertical offset (nm)
zorder=3, # Drawing order
invert_y=True, # Invert Y axis
ax=existing_axis # Plot on existing axes
)
plot_annotations_2d
plot_annotations_2d
plot_annotations_2d(annotation: PointCloudLayer, color: Optional[Union[str, ndarray, tuple]] = None, palette: Union[str, dict] = 'coolwarm', color_norm: Optional[Tuple[float, float]] = None, alpha: float = 1, size: Optional[Union[str, ndarray, float]] = None, size_norm: Optional[Tuple[float, float]] = None, sizes: Optional[ndarray] = (1, 30), projection: Union[str, Callable] = 'xy', offset_h: float = 0.0, offset_v: float = 0.0, invert_y: bool = True, ax: Optional[Axes] = None, **kwargs) -> Axes
Scatter plots for point cloud annotations with flexible styling.
Usage Examples
# Basic annotation plotting
ax = ossify.plot_annotations_2d(
cell.annotations["pre_syn"],
projection="xy"
)
# Advanced styling
ax = ossify.plot_annotations_2d(
cell.annotations["synapses"],
color="activity_level", # Color by annotation property
palette="plasma", # Continuous colormap
color_norm=(0, 1), # Value range for coloring
size="strength", # Size by property
size_norm=(0.1, 2.0), # Property range
sizes=(5, 80), # Marker size range (points²)
alpha=0.8, # Transparency
projection="zy", # Side projection
offset_h=500, # Position offset
offset_v=0,
ax=ax, # Add to existing plot
edgecolors='black', # Marker edge color
linewidths=0.5 # Edge width
)
plot_skeleton & plot_points
Lower-level functions for precise control:
plot_skeleton
plot_skeleton(skel: SkeletonLayer, projection: Union[str, Callable] = 'xy', colors: Optional[ndarray] = None, alpha: Optional[ndarray] = None, linewidths: Optional[ndarray] = None, offset_h: float = 0.0, offset_v: float = 0.0, zorder: int = 2, invert_y: bool = True, ax: Optional[Axes] = None) -> Axes
Plot skeleton with explicit arrays for styling.
Parameters:
-
skel(SkeletonLayer) –SkeletonLayer to plot
-
projection(str or Callable, default:"xy") –Projection function or string
-
colors(ndarray, default:None) –(N, 3) or (N, 4) RGB/RGBA color array for vertices
-
alpha(ndarray, default:None) –(N,) alpha values for vertices
-
linewidths(ndarray, default:None) –(N,) linewidth values for vertices
-
offset_h(float, default:0.0) –Horizontal offset for projection
-
offset_v(float, default:0.0) –Vertical offset for projection
-
zorder(int, default:2) –Drawing order for line collection
-
invert_y(bool, default:True) –Whether to automatically invert y-axis for projections containing 'y'
-
ax(Axes, default:None) –Matplotlib axes
Returns:
-
Axes–Matplotlib axes with skeleton plotted
plot_points
plot_points(points: ndarray, sizes: Optional[ndarray] = None, colors: Optional[ndarray] = None, palette: Optional[Union[str, Dict]] = None, color_norm: Optional[Tuple[float, float]] = None, projection: Union[str, Callable] = 'xy', offset_h: float = 0.0, offset_v: float = 0.0, invert_y: bool = True, ax: Optional[Axes] = None, zorder: int = 2, **scatter_kws) -> Axes
Direct Array Styling
# Direct control with pre-computed arrays
skeleton = cell.skeleton
# Prepare styling arrays
colors = ossify.strahler_number(skeleton) # Color values
alphas = np.ones(skeleton.n_vertices) * 0.8 # Uniform transparency
widths = skeleton.get_feature("radius") * 2 # Width by radius
# Plot with explicit arrays
ax = ossify.plot_skeleton(
skeleton,
projection="xy",
colors=colors, # (N, 3) RGB or (N, 4) RGBA array
alpha=alphas, # (N,) alpha values
linewidths=widths, # (N,) linewidth values
zorder=2
)
# Plot points with arrays
points = cell.annotations["pre_syn"].vertices
sizes = np.random.uniform(10, 50, len(points))
colors = np.random.choice(['red', 'blue'], len(points))
ax = ossify.plot_points(
points=points,
sizes=sizes,
colors=colors,
projection="xy",
ax=ax,
zorder=3
)
Figure Management
single_panel_figure
single_panel_figure
single_panel_figure(data_bounds_min: ndarray, data_bounds_max: ndarray, units_per_inch: float, despine: bool = True, dpi: Optional[float] = None) -> Tuple[Figure, Axes]
Create a single panel figure with precise unit-based sizing.
Parameters:
-
data_bounds_min(ndarray) –2-element array [x_min, y_min] of data bounds
-
data_bounds_max(ndarray) –2-element array [x_max, y_max] of data bounds
-
units_per_inch(float) –Number of data units per inch for scaling
-
despine(bool, default:True) –Whether to remove axis spines and ticks for clean appearance
-
dpi(float, default:None) –Dots per inch for figure resolution. If None, uses matplotlib default.
Returns:
-
tuple of (plt.Figure, plt.Axes)–Figure and axes objects with correct unit scaling
Examples:
Create figures with precise unit-based sizing for consistent scaling.
Usage Examples
# Calculate data bounds
bounds_min = cell.skeleton.bbox[0] # [x_min, y_min, z_min]
bounds_max = cell.skeleton.bbox[1] # [x_max, y_max, z_max]
# Create figure with specific scale
fig, ax = ossify.single_panel_figure(
data_bounds_min=bounds_min[:2], # [x_min, y_min]
data_bounds_max=bounds_max[:2], # [x_max, y_max]
units_per_inch=50000, # 50,000 nm per inch
despine=True, # Remove axes
dpi=300 # High resolution
)
# Plot data on precisely-sized axes
ossify.plot_morphology_2d(cell, ax=ax)
# The figure size automatically matches data aspect ratio
print(f"Figure size: {fig.get_size_inches()}")
multi_panel_figure
multi_panel_figure
multi_panel_figure(data_bounds_min: ndarray, data_bounds_max: ndarray, units_per_inch: float, layout: Literal['side_by_side', 'stacked', 'three_panel'], gap_inches: float = 0.5, despine: bool = True, dpi: Optional[float] = None) -> Tuple[Figure, Dict[str, Axes]]
Create multi-panel figure with precise unit-based sizing and alignment.
Parameters:
-
data_bounds_min(ndarray) –3-element array [x_min, y_min, z_min] of data bounds
-
data_bounds_max(ndarray) –3-element array [x_max, y_max, z_max] of data bounds
-
units_per_inch(float) –Number of data units per inch for scaling
-
layout((side_by_side, stacked, three_panel), default:"side_by_side") –Layout configuration: - "side_by_side": xy | zy (horizontal) - "stacked": xz over xy (vertical) - "three_panel": L-shaped (xy bottom-left, xz top-left, zy bottom-right)
-
gap_inches(float, default:0.5) –Gap between panels in inches
-
despine(bool, default:True) –Whether to remove axis spines and ticks for clean appearance
-
dpi(float, default:None) –Dots per inch for figure resolution. If None, uses matplotlib default.
Returns:
-
tuple of (plt.Figure, dict of plt.Axes)–Figure and dictionary of axes keyed by projection. - "side_by_side": {"xy": xy_ax, "zy": zy_ax} - "stacked": {"xz": xz_ax, "xy": xy_ax} - "three_panel": {"xy": xy_ax, "xz": xz_ax, "zy": zy_ax}
Examples:
Create aligned multi-panel layouts with consistent scaling.
Usage Examples
# Three-panel layout with precise alignment
fig, axes = ossify.multi_panel_figure(
data_bounds_min=cell.skeleton.bbox[0],
data_bounds_max=cell.skeleton.bbox[1],
units_per_inch=75000,
layout="three_panel",
gap_inches=0.4, # Panel spacing
despine=True,
dpi=300
)
# Plot different projections
for projection, ax in axes.items():
ossify.plot_morphology_2d(
cell,
projection=projection,
color="compartment",
ax=ax
)
ax.set_title(f"{projection.upper()} View")
plt.suptitle("Multi-View Neuron Analysis")
add_scale_bar
add_scale_bar
add_scale_bar(ax: Axes, length: float, position: Tuple[float, float] = (0.05, 0.05), color: str = 'black', linewidth: float = 10.0, orientation: Literal['h', 'v', 'horizontal', 'vertical'] = 'h', feature: Optional[str] = None, feature_offset: float = 0.01, fontsize: float = 10) -> None
Add a scale bar to an axis with precise positioning.
Parameters:
-
ax(Axes) –Matplotlib axes to add scale bar to
-
length(float) –Length of scale bar in data units
-
position(tuple of float, default:(0.05, 0.05)) –Starting position as fraction of axis dimensions (x_frac, y_frac). (0, 0) is bottom-left, (1, 1) is top-right.
-
color(str, default:"black") –Color of the scale bar line
-
linewidth(float, default:3.0) –Width of the scale bar line in points
-
feature(str, default:None) –Text feature for the scale bar (e.g., "100 μm")
-
feature_offset(float, default:0.01) –Vertical offset for feature as fraction of axis height
-
fontsize(float, default:10) –Font size for scale bar feature
Examples:
Add calibrated scale bars to plots.
Usage Examples
# Add scale bars to plots
fig, ax = ossify.single_panel_figure(
bounds_min, bounds_max,
units_per_inch=100000 # 100,000 nm per inch
)
ossify.plot_morphology_2d(cell, ax=ax)
# Horizontal scale bar (bottom-left)
ossify.add_scale_bar(
ax,
length=50000, # 50 μm in nm
position=(0.05, 0.05), # Fractional position
feature="50 μm", # Text feature
color="black",
linewidth=8,
fontsize=12
)
# Vertical scale bar (top-right)
ossify.add_scale_bar(
ax,
length=25000, # 25 μm
position=(0.9, 0.7),
orientation="vertical", # or "v"
feature="25 μm",
feature_offset=0.02, # feature spacing
color="white", # For dark backgrounds
linewidth=6
)
Advanced Plotting Workflows
Publication Figure Pipeline
def create_publication_figure(cell, output_path="figure.pdf"):
\"\"\"Create a publication-ready multi-panel figure\"\"\"
# Calculate compartmentalization
is_axon = ossify.label_axon_from_synapse_flow(cell)
compartment = np.where(is_axon, "Axon", "Dendrite")
cell.skeleton.add_feature(compartment, "compartment")
# Create multi-panel layout
fig, axes = ossify.plot_cell_multiview(
cell,
layout="three_panel",
color="compartment",
palette={"Axon": "#d62728", "Dendrite": "#1f77b4"}, # Red/Blue
linewidth="radius",
widths=(1, 15),
synapses="both",
pre_color="#ff7f0e", # Orange presynaptic
post_color="#2ca02c", # Green postsynaptic
syn_size=25,
units_per_inch=100000, # 100k nm/inch
gap_inches=0.3,
despine=True,
dpi=300
)
# Add scale bars
for proj, ax in axes.items():
if proj == "xy":
ossify.add_scale_bar(ax, 100000, (0.05, 0.05), "100 μm", fontsize=14)
elif proj == "xz":
ossify.add_scale_bar(ax, 50000, (0.05, 0.05), "50 μm", fontsize=12)
elif proj == "zy":
ossify.add_scale_bar(ax, 75000, (0.05, 0.05), "75 μm", fontsize=12)
# Add panel features
axes["xy"].text(0.02, 0.98, "A", transform=axes["xy"].transAxes,
fontsize=20, fontweight='bold', va='top')
axes["xz"].text(0.02, 0.98, "B", transform=axes["xz"].transAxes,
fontsize=20, fontweight='bold', va='top')
axes["zy"].text(0.02, 0.98, "C", transform=axes["zy"].transAxes,
fontsize=20, fontweight='bold', va='top')
# Add figure title and save
fig.suptitle("Neuronal Compartmentalization Analysis", fontsize=16, y=0.95)
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight')
return fig
# Generate publication figure
fig = create_publication_figure(cell, "neuron_analysis.pdf")
Interactive Analysis Workflow
def plot_analysis_comparison(cell, algorithms=['flow', 'spectral']):
\"\"\"Compare different analysis algorithms visually\"\"\"
results = {}
# Run different algorithms
if 'flow' in algorithms:
results['flow'] = ossify.label_axon_from_synapse_flow(cell)
if 'spectral' in algorithms:
results['spectral'] = ossify.label_axon_from_spectral_split(cell)
# Create comparison plot
n_methods = len(results)
fig, axes = plt.subplots(1, n_methods, figsize=(6*n_methods, 6))
if n_methods == 1:
axes = [axes]
for i, (method, is_axon) in enumerate(results.items()):
compartment = np.where(is_axon, "Axon", "Dendrite")
ossify.plot_morphology_2d(
cell,
color=compartment,
palette={"Axon": "red", "Dendrite": "blue"},
ax=axes[i]
)
axes[i].set_title(f"{method.capitalize()} Method")
axes[i].set_aspect('equal')
plt.tight_layout()
return fig, results
# Compare methods
fig, results = plot_analysis_comparison(cell)
# Calculate agreement
if len(results) > 1:
methods = list(results.keys())
agreement = (results[methods[0]] == results[methods[1]]).mean()
print(f"Agreement between methods: {agreement:.1%}")
Custom Styling Functions
def create_custom_colormap():
\"\"\"Create custom colormap for morphological data\"\"\"
from matplotlib.colors import LinearSegmentedColormap
colors = ['#440154', '#31688e', '#35b779', '#fde725'] # Viridis-like
n_bins = 256
cmap = LinearSegmentedColormap.from_list('custom', colors, N=n_bins)
return cmap
def style_by_distance_to_branch(cell, ax):
\"\"\"Style skeleton by distance to nearest branch point\"\"\"
skeleton = cell.skeleton
branch_points = skeleton.branch_points
# Calculate distance to nearest branch for each vertex
distances = []
for vertex in skeleton.vertex_index:
dist_to_branches = skeleton.distance_between(
[vertex], branch_points, limit=100000
)
distances.append(dist_to_branches.min() if len(dist_to_branches) > 0 else np.inf)
distances = np.array(distances)
# Plot with custom styling
ossify.plot_morphology_2d(
cell,
color=distances,
palette=create_custom_colormap(),
color_norm=(0, np.percentile(distances[distances < np.inf], 95)),
linewidth=2,
ax=ax
)
return distances
# Apply custom styling
fig, ax = plt.subplots(figsize=(10, 8))
distances = style_by_distance_to_branch(cell, ax)
ax.set_title("Distance to Nearest Branch Point")
Plotting Design Principles
Unit Consistency: All plotting functions support precise unit control for consistent scaling across figures.
Flexible Styling: Multiple ways to specify colors, sizes, and transparency - from simple constants to complex property mappings.
Layer Integration: Seamless integration between different data layers in combined plots.
Publication Ready: Built-in support for high-DPI output, precise scaling, and clean styling.
Best Practices
- Scale Bars: Always include scale bars for spatial data
- Color Schemes: Use perceptually uniform colormaps (viridis, plasma, cividis) for continuous data
- Resolution: Set
dpi=300for publication figures - Aspect Ratios: Use
units_per_inchfor consistent scaling across different data sizes - Layering: Use
zorderto control drawing order when combining multiple plot elements