These examples use Jinja2 (a templating engine) or Pillow (image manipulation) to inject data into a layout.


🎨 Template-Based Data Graphics

1. SVG Templating (Vector Graphics)

Best for: High-quality graphics where you need to swap icons, change colors, or update text dynamically without losing resolution. We treat the SVG file as text and replace placeholders using Jinja2.

File: template.svg

<svg width="400" height="200" xmlns="<http://www.w3.org/2000/svg>">
  <rect width="100%" height="100%" fill="#f0f0f0"/>
  
  <image href="{{ user_avatar }}" x="20" y="50" height="100" width="100"/>
  
  <text x="140" y="100" font-family="Arial" font-size="24" fill="#333">
    {{ user_name }}
  </text>
  <text x="140" y="130" font-family="Arial" font-size="16" fill="#666">
    Score: {{ user_score }}
  </text>
</svg>

File: generate_svg.py

from jinja2 import Template

# 1. Load the SVG template
with open("template.svg", "r") as f:
    svg_content = f.read()

# 2. Create the Jinja2 Template
template = Template(svg_content)

# 3. Define your variables (Text and Image URLs)
data = {
    "user_name": "Alice Johnson",
    "user_score": "9,450",
    "user_avatar": "<https://via.placeholder.com/100>" # URL or local path
}

# 4. Render the template with data
output_svg = template.render(data)

# 5. Save the final graphic
with open("output_card.svg", "w") as f:
    f.write(output_svg)

print("Generated output_card.svg")

2. Pillow (Raster Image Compositing)

Best for: Editing standard images (JPG/PNG). You load a base "background" image and draw text or paste other images on top of it at specific coordinates.

File: generate_badge.py

from PIL import Image, ImageDraw, ImageFont
import requests
from io import BytesIO

# 1. Define Variables
bg_path = "base_template.png" # Ideally a 500x300 blank image
avatar_url = "<https://via.placeholder.com/100>"
user_text = "Employee of the Month"
name_text = "Jane Doe"

# 2. Load the Template (Background)
# For this example, we create a blank one if file doesn't exist
img = Image.new('RGB', (500, 300), color=(73, 109, 137))

# 3. Fetch and Paste Dynamic Image
response = requests.get(avatar_url)
avatar = Image.open(BytesIO(response.content)).resize((100, 100))
img.paste(avatar, (50, 50)) # Paste at coordinates (50, 50)

# 4. Draw Dynamic Text
draw = ImageDraw.Draw(img)

# Optional: Load a custom font (using default here for simplicity)
# font = ImageFont.truetype("arial.ttf", 36) 
draw.text((170, 60), name_text, fill=(255, 255, 255))
draw.text((170, 100), user_text, fill=(200, 200, 200))

# 5. Save Result
img.save("final_badge.png")
print("Generated final_badge.png")

3. HTML to Image (Complex Layouts)

Best for: When the design is complicated (tables, grids, wrapping text). You design in HTML/CSS, inject variables with Jinja2, and convert the result to an image using imgkit.

Note: Requires pip install imgkit jinja2 and wkhtmltoimage installed on your system.

File: report_template.html

<!DOCTYPE html>
<html>
<head>
<style>
  body { font-family: sans-serif; width: 600px; padding: 20px; background: #fff; }
  .header { display: flex; align-items: center; border-bottom: 2px solid #333; }
  .logo { width: 50px; height: 50px; margin-right: 20px; }
  .stat-box { background: #eee; padding: 15px; margin-top: 20px; border-radius: 8px; }
  h1 { color: #2c3e50; }
</style>
</head>
<body>
  <div class="header">
    <img src="{{ logo_path }}" class="logo">
    <h1>{{ company_name }} Report</h1>
  </div>
  
  <div class="stat-box">
    <h3>Monthly Revenue</h3>
    <p style="font-size: 24px; font-weight: bold;">{{ revenue_amount }}</p>
  </div>
</body>
</html>