Visualization Backends
Pylinkage provides multiple visualization and export backends:
Matplotlib: Animations and static plots (default)
Plotly: Interactive HTML visualizations
drawsvg: Publication-quality SVG output
DXF: 2D CAD export for AutoCAD/CNC (requires
pylinkage[cad])STEP: 3D CAD interchange format (requires
pylinkage[cad])
This tutorial covers each backend with practical examples.
Comparison of the three visualization backends: Matplotlib (animations), Plotly (interactive HTML), and drawsvg (publication SVG).
Quick Reference
Backend |
Best For |
Output Formats |
|---|---|---|
Matplotlib |
Quick visualization, GIF animations |
PNG, GIF, PDF, interactive window |
Plotly |
Interactive exploration, web embedding |
HTML, PNG, PDF, SVG |
drawsvg |
Publications, precise vector graphics |
SVG, PNG, PDF |
DXF |
2D CAD, laser cutting, CNC |
DXF (AutoCAD compatible) |
STEP |
3D CAD, machining, 3D printing |
STEP/STP (ISO 10303) |
Matplotlib Backend
The default backend for quick visualization and animations.
Basic Visualization
import pylinkage as pl
from pylinkage.visualizer import show_linkage
# Create a four-bar linkage
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1, name="Crank")
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0),
distance0=3, distance1=1, name="Output")
linkage = pl.Linkage(joints=(crank, output), name="Four-bar")
# Quick visualization (opens matplotlib window)
show_linkage(linkage)
Static Frame Visualization
Show the linkage at a specific position:
from pylinkage.visualizer import show_linkage
import matplotlib.pyplot as plt
# Show without animation
fig, ax = show_linkage(linkage, animated=False)
# Customize the plot
ax.set_title("Four-bar Linkage - Initial Position")
ax.grid(True, alpha=0.3)
ax.set_aspect('equal')
plt.tight_layout()
plt.savefig("linkage_static.png", dpi=150)
plt.show()
Result: A static image showing the linkage in its initial configuration.
Animated GIF Output
Create animated GIFs for documentation or presentations:
from pylinkage.visualizer import show_linkage
# Create animated GIF
show_linkage(
linkage,
save_path="four_bar_animation.gif",
fps=24, # Frames per second
duration=3000, # Total duration in ms
loci=True, # Show joint paths
)
print("Animation saved to four_bar_animation.gif")
Result: An animated GIF showing the linkage cycling through its motion.
Customizing Appearance
from pylinkage.visualizer import show_linkage
import matplotlib.pyplot as plt
fig, ax = show_linkage(
linkage,
# Display options
loci=True, # Show joint trajectories
show_legend=True, # Add legend
title="Custom Four-bar",
# Style options
joint_color='#E63946', # Joint marker color
link_color='#1D3557', # Link line color
locus_color='#A8DADC', # Trajectory line color
joint_size=80, # Marker size
# Animation options (if animated=True)
animated=True,
interval=50, # ms between frames
)
plt.show()
Showing Multiple Linkages
Compare different configurations:
import pylinkage as pl
from pylinkage.visualizer import show_linkage
import matplotlib.pyplot as plt
# Create two different four-bars
def make_fourbar(d0, d1, name):
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1)
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0),
distance0=d0, distance1=d1)
return pl.Linkage(joints=(crank, output), name=name)
linkage1 = make_fourbar(3, 1, "Short rocker")
linkage2 = make_fourbar(3, 2, "Long rocker")
# Plot side by side
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
show_linkage(linkage1, ax=ax1, animated=False, loci=True)
ax1.set_title(linkage1.name)
show_linkage(linkage2, ax=ax2, animated=False, loci=True)
ax2.set_title(linkage2.name)
plt.tight_layout()
plt.savefig("comparison.png", dpi=150)
plt.show()
Plotly Backend
Interactive HTML visualizations ideal for web embedding and exploration.
Basic Interactive Plot
import pylinkage as pl
from pylinkage.visualizer import plot_linkage_plotly
# Create linkage
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1, name="Crank")
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0),
distance0=3, distance1=1, name="Output")
linkage = pl.Linkage(joints=(crank, output), name="Four-bar")
# Create interactive plot
fig = plot_linkage_plotly(linkage)
# Display in notebook or browser
fig.show()
# Save to HTML
fig.write_html("interactive_linkage.html")
Result: An interactive HTML page where you can:
Zoom and pan
Hover over joints for coordinates
Toggle visibility of elements
Rotate through animation frames
Animation with Slider
from pylinkage.visualizer import plot_linkage_plotly
fig = plot_linkage_plotly(
linkage,
show_loci=True, # Show joint trajectories
show_slider=True, # Add frame slider
frame_count=50, # Number of animation frames
title="Interactive Four-bar",
)
fig.write_html("animated_linkage.html")
Result: HTML with a slider to scrub through the animation manually.
Customizing Plotly Appearance
from pylinkage.visualizer import plot_linkage_plotly
import plotly.graph_objects as go
fig = plot_linkage_plotly(
linkage,
# Colors
joint_color='red',
link_color='blue',
locus_color='rgba(0, 255, 0, 0.5)',
# Sizes
joint_size=15,
link_width=4,
# Layout
title="Styled Four-bar",
width=800,
height=600,
)
# Further customization using plotly API
fig.update_layout(
plot_bgcolor='white',
paper_bgcolor='white',
font=dict(family="Arial", size=14),
)
fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='lightgray')
fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor='lightgray')
fig.show()
Embedding in Web Pages
from pylinkage.visualizer import plot_linkage_plotly
fig = plot_linkage_plotly(linkage, show_loci=True)
# Get HTML div for embedding
div_html = fig.to_html(include_plotlyjs='cdn', full_html=False)
# Write to file with custom wrapper
full_html = f"""
<!DOCTYPE html>
<html>
<head>
<title>My Linkage</title>
<style>
body {{ font-family: Arial; max-width: 800px; margin: auto; }}
h1 {{ text-align: center; }}
</style>
</head>
<body>
<h1>Four-bar Linkage Analysis</h1>
{div_html}
<p>Use the controls to explore the mechanism.</p>
</body>
</html>
"""
with open("embedded_linkage.html", "w") as f:
f.write(full_html)
drawsvg Backend
Publication-quality vector graphics for papers and documentation.
Basic SVG Output
import pylinkage as pl
from pylinkage.visualizer import save_linkage_svg
# Create linkage
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1, name="Crank")
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0),
distance0=3, distance1=1, name="Output")
linkage = pl.Linkage(joints=(crank, output), name="Four-bar")
# Save as SVG
save_linkage_svg(linkage, "linkage.svg")
Result: A crisp SVG file that scales perfectly at any resolution.
Customizing SVG Style
from pylinkage.visualizer import save_linkage_svg
save_linkage_svg(
linkage,
"styled_linkage.svg",
# Dimensions
width=400,
height=300,
margin=20,
# Colors (CSS color strings)
joint_color='#2E86AB',
link_color='#A23B72',
ground_color='#F18F01',
locus_color='#C73E1D',
# Stroke widths
link_width=3,
locus_width=1.5,
# Joint markers
joint_radius=8,
# Show elements
show_loci=True,
show_labels=True,
show_ground=True,
)
Multi-Frame SVG
Show multiple positions in one image:
from pylinkage.visualizer import save_linkage_svg_multiframe
import pylinkage as pl
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1)
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0), distance0=3, distance1=1)
linkage = pl.Linkage(joints=(crank, output))
# Show 5 evenly spaced positions
save_linkage_svg_multiframe(
linkage,
"multiframe.svg",
num_frames=5,
frame_opacity=0.3, # Transparency of intermediate frames
highlight_first=True, # Make first frame solid
highlight_last=True, # Make last frame solid
)
Result: SVG showing the linkage at multiple positions, ideal for illustrating motion.
SVG for LaTeX
Generate SVGs optimized for LaTeX documents:
from pylinkage.visualizer import save_linkage_svg
save_linkage_svg(
linkage,
"latex_figure.svg",
width=300, # Points (LaTeX-friendly)
height=200,
font_family="serif", # Match LaTeX fonts
font_size=10,
show_labels=True,
label_offset=12,
)
# Include in LaTeX:
# \begin{figure}
# \centering
# \includesvg{latex_figure}
# \caption{Four-bar linkage mechanism}
# \end{figure}
CAD Export
Export linkages to industry-standard CAD formats for fabrication and 3D modeling.
Note
CAD export requires optional dependencies. Install with:
pip install pylinkage[cad]
This installs ezdxf (for DXF) and build123d (for STEP).
DXF Export (2D CAD)
Export to DXF format for AutoCAD, CNC machines, and laser cutters:
import pylinkage as pl
from pylinkage.visualizer import save_linkage_dxf, plot_linkage_dxf
# Create linkage
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1, name="Crank")
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0),
distance0=3, distance1=1, name="Output")
linkage = pl.Linkage(joints=(crank, output), name="Four-bar")
# Save to DXF file
save_linkage_dxf(linkage, "linkage.dxf")
# Or get the ezdxf Drawing object for further customization
doc = plot_linkage_dxf(linkage)
doc.saveas("custom_linkage.dxf")
DXF Layers: The exported DXF contains organized layers:
LINKS- Link bar geometry (white)JOINTS- Joint symbols (red)GROUND- Ground/fixed support symbols (gray)CRANKS- Crank/motor symbols (green)
Customizing DXF Output
Control dimensions and export a specific frame:
from pylinkage.visualizer import save_linkage_dxf
# Run simulation to get all positions
loci = list(linkage.step())
# Export frame 25 with custom dimensions
save_linkage_dxf(
linkage,
"frame25.dxf",
loci=loci,
frame_index=25, # Export this frame (0 = first)
link_width=0.5, # Link bar width in world units
joint_radius=0.2, # Joint symbol radius
)
STEP Export (3D CAD)
Export to STEP format for 3D CAD applications (FreeCAD, SolidWorks, Fusion 360):
import pylinkage as pl
from pylinkage.visualizer import save_linkage_step, build_linkage_3d
# Create linkage
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1, name="Crank")
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0),
distance0=3, distance1=1, name="Output")
linkage = pl.Linkage(joints=(crank, output), name="Four-bar")
# Save to STEP file (dimensions auto-scaled to fit linkage)
save_linkage_step(linkage, "linkage.step")
# Or get the build123d Compound for further manipulation
model = build_linkage_3d(linkage)
model.export_step("custom_linkage.step")
3D Geometry: The STEP export creates:
Stadium-shaped link bars (rounded rectangles extruded in Z)
Holes at joint locations for pin connections
Cylindrical pins at each joint
Ground symbols for fixed supports
Customizing STEP Dimensions
Use LinkProfile and JointProfile to control 3D geometry:
from pylinkage.visualizer import (
save_linkage_step,
LinkProfile,
JointProfile,
)
# Define custom link cross-section
link_profile = LinkProfile(
width=10.0, # Link bar width (mm or your units)
thickness=3.0, # Extrusion depth in Z
fillet_radius=0.5, # Edge rounding (0 for sharp)
)
# Define custom joint pins
joint_profile = JointProfile(
radius=2.0, # Pin radius
length=5.0, # Pin length in Z
)
# Export with custom profiles
save_linkage_step(
linkage,
"machined_linkage.step",
link_profile=link_profile,
joint_profile=joint_profile,
frame_index=0, # Which position to export
include_pins=True, # Include joint pins
)
Exporting Multiple Frames
Export different positions of the mechanism:
from pylinkage.visualizer import save_linkage_step
# Pre-compute trajectory
loci = list(linkage.step())
# Export key positions
for i, frame_idx in enumerate([0, 25, 50, 75]):
save_linkage_step(
linkage,
f"linkage_position_{i}.step",
loci=loci,
frame_index=frame_idx,
)
print(f"Exported frame {frame_idx} to linkage_position_{i}.step")
CAD Export Workflow
A typical workflow from simulation to fabrication:
import pylinkage as pl
from pylinkage.visualizer import (
show_linkage,
save_linkage_svg,
save_linkage_dxf,
save_linkage_step,
LinkProfile,
)
# 1. Design and simulate
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1, name="Crank")
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0),
distance0=3, distance1=1, name="Output")
linkage = pl.Linkage(joints=(crank, output))
loci = list(linkage.step())
# 2. Quick visualization to verify
show_linkage(linkage, loci=loci)
# 3. Publication figure (SVG)
save_linkage_svg(linkage, "documentation/linkage.svg", show_loci=True)
# 4. 2D CAD for laser cutting (DXF)
save_linkage_dxf(linkage, "fabrication/linkage_2d.dxf", loci=loci)
# 5. 3D CAD for machining/printing (STEP)
profile = LinkProfile(width=10, thickness=3)
save_linkage_step(
linkage,
"fabrication/linkage_3d.step",
loci=loci,
link_profile=profile,
)
print("Export complete! Files ready for fabrication.")
PSO Visualization
Visualize particle swarm optimization progress:
import pylinkage as pl
from pylinkage.visualizer import (
plot_pso_convergence,
plot_pso_particles,
create_pso_dashboard,
)
# Create and optimize linkage
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1)
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0), distance0=3, distance1=1)
linkage = pl.Linkage(joints=(crank, output))
@pl.kinematic_minimization
def fitness(loci, **kwargs):
output_path = [step[-1] for step in loci]
bbox = pl.bounding_box(output_path)
return bbox[2] - bbox[0] # Minimize height
bounds = pl.generate_bounds(linkage.get_num_constraints())
# Run optimization with history tracking
results, history = pl.particle_swarm_optimization(
eval_func=fitness,
linkage=linkage,
bounds=bounds,
n_particles=30,
iters=50,
return_history=True,
)
# Plot convergence
fig = plot_pso_convergence(history)
fig.savefig("convergence.png")
# Plot particle distribution
fig = plot_pso_particles(history, iteration=25)
fig.savefig("particles_iter25.png")
# Create full dashboard
fig = create_pso_dashboard(linkage, history, results)
fig.savefig("pso_dashboard.png", dpi=150)
Visualization with Kinematics
Show velocity vectors alongside the linkage:
Linkage with velocity vectors shown at each joint, computed from the angular velocity of the input crank.
from pylinkage.visualizer import show_kinematics, animate_kinematics
import pylinkage as pl
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.1, distance=1)
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0), distance0=3, distance1=1)
linkage = pl.Linkage(joints=(crank, output))
# Set angular velocity
linkage.set_input_velocity(crank, omega=10.0)
# Show single frame with velocity vectors
fig = show_kinematics(
linkage,
frame_index=10,
show_velocity=True,
velocity_scale=0.05, # Scale factor for arrow length
velocity_color='red',
)
fig.savefig("velocities.png")
# Animated with velocities
animate_kinematics(
linkage,
show_velocity=True,
save_path="velocity_animation.gif",
)
Choosing the Right Backend
Use Matplotlib when:
You need quick visualization during development
You want animated GIFs for documentation
You’re working in Jupyter notebooks
You need PDF output for simple figures
Use Plotly when:
You want interactive exploration
You’re building web applications
You need to embed in HTML pages
Users need to zoom/pan/hover
Use drawsvg when:
You’re writing academic papers
You need precise vector graphics
You want to edit the output in Inkscape/Illustrator
You need consistent styling across figures
Use DXF when:
You need to import into AutoCAD or similar 2D CAD software
You’re preparing files for laser cutting or CNC machining
You need layered 2D technical drawings
You want to edit geometry in CAD software
Use STEP when:
You need to import into 3D CAD software (FreeCAD, SolidWorks, Fusion 360)
You’re preparing files for 3D printing or machining
You want to visualize the linkage as physical parts
You need to integrate with other 3D models
Example: Complete Visualization Workflow
import pylinkage as pl
from pylinkage.visualizer import (
show_linkage,
plot_linkage_plotly,
save_linkage_svg,
)
# Create an optimized linkage
crank = pl.Crank(0, 1, joint0=(0, 0), angle=0.31, distance=1, name="A")
output = pl.Revolute(3, 2, joint0=crank, joint1=(3, 0),
distance0=2.5, distance1=1.5, name="B")
linkage = pl.Linkage(joints=(crank, output), name="Optimized Four-bar")
# 1. Quick check with Matplotlib
show_linkage(linkage, loci=True)
# 2. Interactive exploration with Plotly
fig = plot_linkage_plotly(linkage, show_loci=True, show_slider=True)
fig.write_html("explore.html")
print("Open explore.html in browser for interactive view")
# 3. Publication figure with drawsvg
save_linkage_svg(
linkage,
"figure1.svg",
width=400,
height=300,
show_loci=True,
show_labels=True,
joint_color='black',
link_color='black',
locus_color='gray',
)
print("Publication figure saved to figure1.svg")
# 4. Animation for presentation
show_linkage(
linkage,
save_path="presentation.gif",
fps=30,
loci=True,
)
print("Animation saved to presentation.gif")
Next Steps
Getting Started - Basic linkage creation
Kinematics-Based Optimization - Velocity visualization
See
pylinkage.visualizerfor complete API reference