| name | create-2d-composition |
| locale | caveman |
| source_locale | en |
| source_commit | 75ded7a1 |
| translator | Julius Brussee homage — caveman |
| translation_date | 2026-04-19 |
| description | Compose 2D graphics programmatically using SVG generation, diagram layout algorithms, image compositing, and batch processing workflows. Use when generating diagrams, flowcharts, or infographics programmatically, creating reproducible scientific figures, automating production of badges or visual assets, building custom chart types not in standard libraries, or batch generating graphics with parameter variations.
|
| license | MIT |
| allowed-tools | Read Write Edit Bash Grep Glob |
| metadata | {"author":"Philipp Thoss","version":"1.0","domain":"visualization","complexity":"intermediate","language":"Python","tags":"svg, 2d, graphics, composition, diagrams, scripting, batch-processing"} |
Create 2D Composition
Make 2D graphics by code. SVG building, diagram layout, image compositing, batch workflows. Covers vector, raster, typography, auto-production of charts, diagrams, infographics.
When Use
- Making diagrams, flowcharts, infographics by code
- Building reproducible scientific figures
- Auto-producing badges, icons, assets
- Compositing images or data visualizations
- Building custom chart types not in standard libs
- Batch graphics with param variations
- SVG templates for web or print
Inputs
| Input | Type | Description | Example |
|---|
| Layout specification | Configuration | Dimensions, margins, grid layout | Canvas 800x600px, 20px margins |
| Visual elements | Data/Assets | Shapes, text, images, data points | Rectangle coordinates, labels, icons |
| Style parameters | CSS/Attributes | Colors, fonts, stroke widths, opacity | fill="#3366cc", stroke-width="2" |
| Data sources | Files/Arrays | Values to visualize or annotate | CSV data, JSON configuration |
| Output format | String | SVG, PNG, PDF, composite formats | output.svg, 300 DPI PNG |
Steps
1. Set Up Python Environment
Install libs for 2D composition:
pip install svgwrite pillow cairosvg
pip install drawsvg reportlab pycairo
pip install matplotlib numpy pandas
Got: Libraries installed fine. If fail: Check Python version (3.7+). Use virtual env
2. Create Basic SVG Graphics
Generate SVG with svgwrite:
import svgwrite
from svgwrite import cm, mm
def create_basic_svg(output_path):
"""Create a simple SVG graphic."""
dwg = svgwrite.Drawing(output_path, size=('180mm', '120mm'), profile='full')
dwg.add(dwg.rect(
insert=(0, 0),
size=('100%', '100%'),
fill='white'
))
dwg.add(dwg.circle(
center=(90*mm, 60*mm),
r=30*mm,
fill='lightblue',
stroke='navy',
stroke_width=2
))
dwg.add(dwg.rect(
insert=(30*mm, 30*mm),
size=(60*mm, 40*mm),
fill='lightgreen',
stroke='darkgreen',
stroke_width=2,
rx=5,
ry=5
))
dwg.add(dwg.text(
'Example Graphic',
insert=(90*mm, 20*mm),
text_anchor='middle',
font_size='18pt',
font_family='Arial',
fill='black'
))
dwg.save()
print(f"Saved: {output_path}")
Got: SVG file made with shapes and text. If fail: Check svgwrite version. Confirm output dir writable
3. Build Diagrams with Layout Logic
Build structured diagrams with calculated positions:
def create_flowchart(steps, output_path):
"""Generate a flowchart from list of steps."""
dwg = svgwrite.Drawing(output_path, size=('800px', '600px'))
box_width = 120
box_height = 60
spacing_y = 100
start_x = 340
start_y = 50
for i, step in enumerate(steps):
y_pos = start_y + i * spacing_y
box = dwg.add(dwg.g(id=f'step_{i}'))
box.add(dwg.rect(
insert=(start_x, y_pos),
size=(box_width, box_height),
fill='lightblue',
stroke='navy',
stroke_width=2,
rx=5,
ry=5
))
text_lines = wrap_text(step, max_width=16)
text_y = y_pos + box_height/2 - (len(text_lines)-1) * 7
for j, line in enumerate(text_lines):
box.add(dwg.text(
line,
insert=(start_x + box_width/2, text_y + j*14),
text_anchor='middle',
font_size='12pt',
font_family='Arial',
fill='black'
))
if i < len(steps) - 1:
arrow_start_y = y_pos + box_height
arrow_end_y = y_pos + spacing_y
dwg.add(dwg.line(
start=(start_x + box_width/2, arrow_start_y),
end=(start_x + box_width/2, arrow_end_y),
stroke='black',
stroke_width=2,
marker_end=dwg.marker(
id='arrow',
viewBox='0 0 10 10',
refX=5,
refY=5,
markerWidth=6,
markerHeight=6,
orient='auto'
)
))
dwg.save()
def wrap_text(text, max_width=20):
"""Simple text wrapping."""
words = text.split()
lines = []
current_line = []
for word in words:
test_line = ' '.join(current_line + [word])
if len(test_line) <= max_width:
current_line.append(word)
else:
if current_line:
lines.append(' '.join(current_line))
current_line = [word]
if current_line:
lines.append(' '.join(current_line))
return lines
Got: Flowchart with connected boxes and arrows. If fail: Tune layout math. Verify arrow marker definitions
4. Composite Raster Images
Combine many images with Pillow:
Full Pillow composite example (grid, horizontal, vertical layout + image annotate) live in references/EXAMPLES.md.
Got: Composite image made with right layout. If fail: Check all input images exist. Verify image modes match
5. Generate Data-Driven Graphics
Make visualizations from data:
import numpy as np
def create_bar_chart_svg(data, labels, output_path):
"""Generate SVG bar chart from data."""
dwg = svgwrite.Drawing(output_path, size=('600px', '400px'))
margin = 50
chart_width = 500
chart_height = 300
bar_spacing = 10
n_bars = len(data)
bar_width = (chart_width - (n_bars - 1) * bar_spacing) / n_bars
max_value = max(data)
scale = chart_height / max_value
dwg.add(dwg.line(
start=(margin, margin),
end=(margin, margin + chart_height),
stroke='black',
stroke_width=2
))
dwg.add(dwg.line(
start=(margin, margin + chart_height),
end=(margin + chart_width, margin + chart_height),
stroke='black',
stroke_width=2
))
for i, (value, label) in enumerate(zip(data, labels)):
x = margin + i * (bar_width + bar_spacing)
bar_height = value * scale
y = margin + chart_height - bar_height
dwg.add(dwg.rect(
insert=(x, y),
size=(bar_width, bar_height),
fill='steelblue',
stroke='navy',
stroke_width=1
))
dwg.add(dwg.text(
f'{value:.1f}',
insert=(x + bar_width/2, y - 5),
text_anchor='middle',
font_size='10pt',
fill='black'
))
dwg.add(dwg.text(
label,
insert=(x + bar_width/2, margin + chart_height + 20),
text_anchor='middle',
font_size='10pt',
fill='black'
))
dwg.save()
Got: SVG bar chart with scaled data. If fail: Handle edge cases (empty data, negatives). Add validation
6. Batch Generate Graphics
Auto-make many graphics:
def batch_generate_badges(users, template_path, output_dir):
"""Generate badge for each user."""
os.makedirs(output_dir, exist_ok=True)
for user in users:
output_path = os.path.join(output_dir, f"{user['id']}_badge.svg")
dwg = svgwrite.Drawing(output_path, size=('300px', '100px'))
dwg.add(dwg.rect(
insert=(0, 0),
size=('100%', '100%'),
fill='#3366cc',
rx=10,
ry=10
))
dwg.add(dwg.text(
user['name'],
insert=(150, 40),
text_anchor='middle',
font_size='20pt',
font_weight='bold',
fill='white'
))
dwg.add(dwg.text(
user['role'],
insert=(150, 70),
text_anchor='middle',
font_size='14pt',
fill='lightblue'
))
dwg.save()
print(f"Generated badge: {output_path}")
Got: Individual graphic made for each data item
If fail: Check data structure. Handle missing fields with defaults
7. Convert SVG to Raster
Export SVG to PNG/PDF for many uses:
import cairosvg
def svg_to_png(svg_path, png_path, dpi=300):
"""Convert SVG to PNG with specified DPI."""
width_inches = 8.27
height_inches = 11.69
width_px = int(width_inches * dpi)
height_px = int(height_inches * dpi)
cairosvg.svg2png(
url=svg_path,
write_to=png_path,
output_width=width_px,
output_height=height_px
)
print(f"Converted to PNG: {png_path}")
def svg_to_pdf(svg_path, pdf_path):
"""Convert SVG to PDF."""
cairosvg.svg2pdf(url=svg_path, write_to=pdf_path)
print(f"Converted to PDF: {pdf_path}")
Got: Raster output at right resolution
If fail: Install cairo system library if missing. Check SVG validity
Checks
Pitfalls
- Unit confusion: SVG units (px, mm, cm) vs screen pixels vs print DPI
- Text overflow: Text past shape boundaries. Wrap it
- Font availability: System fonts differ. Embed or use web-safe fonts
- Coordinate math: Off-by-one errors in grid layouts
- Color format: SVG uses hex strings (
#rrggbb), not tuples
- SVG validity: Check XML. Close all tags
- File paths: Handle special chars, spaces in filenames
- Memory usage: Big batch jobs may need chunking
- Aspect ratio: Keep proportions when resizing
- Transparency: PNG supports alpha. JPEG does not
See Also
render-publication-graphic — publication output
create-3d-scene — similar programmatic approach for 3D
generate-quarto-report — integrating graphics into reports