[ s ] ai-skill-library hub.krojer.net
Authentik: LocalAdmin
← Zurück zur Übersicht

chart-data-storytelling

own v1.0.0
Pfad: skills/own/chart-data-storytelling  •  Clients: codex claude-code gemini-cli
🛡️ Sicherheitsaudit: Freigegeben
Gate: PASSED | Scanner: skillspector 2.12.0 | Netzwerk: none | LLM: False
Geprüft & Freigegeben
Vollständige Anweisungen (SKILL.md)
---
name: chart-data-storytelling
description: Data visualization and visual storytelling for elevation profiles, charts, and dashboards using Python and Observable Plot.
---

# Chart Data Storytelling & Elevation Profiles

Guidelines, code recipes, and visual best practices for creating publication-ready charts, hiking elevation profiles, and interactive web visualisations.

## When to Use

- Generating elevation profiles from GPS/GPX tracks for hiking stages (distance vs. elevation, slope gradients).
- Designing clean, high-craft charts for blog articles (`etappenweise`) and dashboards without default spreadsheet aesthetics.
- Converting complex data tables into visual comparisons (bar charts, scatter plots, sparklines).
- Exporting publication-ready SVG, PNG, or interactive HTML widgets.

---

## 1. Hiking Elevation Profile (Python / Matplotlib)

Generate a high-contrast, beautiful stage profile from distance and elevation data:

```python
import matplotlib.pyplot as plt
import numpy as np

def generate_elevation_profile(distances_km, elevations_m, stage_title, output_png="profile.png"):
    # Style setup
    plt.style.use('seaborn-v0_8-whitegrid' if 'seaborn-v0_8-whitegrid' in plt.style.available else 'default')
    fig, ax = plt.subplots(figsize=(10, 4), dpi=300)
    
    # Gradient area fill under elevation line
    ax.plot(distances_km, elevations_m, color='#1e3a8a', linewidth=2.5, label='Höhe (m)')
    ax.fill_between(distances_km, elevations_m, color='#3b82f6', alpha=0.25)
    
    # Calculate stats
    min_elev, max_elev = min(elevations_m), max(elevations_m)
    gain = sum(max(0, b - a) for a, b in zip(elevations_m[:-1], elevations_m[1:]))
    
    # Annotations & styling
    ax.set_title(f"{stage_title} — Höhenprofil (Aufstieg: +{int(gain)}m)", fontsize=13, fontweight='bold', pad=12, color='#0f172a')
    ax.set_xlabel("Distanz (km)", fontsize=10, fontweight='medium', color='#334155')
    ax.set_ylabel("Höhe über Adria (m)", fontsize=10, fontweight='medium', color='#334155')
    
    # Dynamic axis padding
    ax.set_ylim(min_elev - 100, max_elev + 150)
    ax.set_xlim(distances_km[0], distances_km[-1])
    
    # Subdued grid
    ax.grid(True, linestyle='--', alpha=0.5, color='#cbd5e1')
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    
    plt.tight_layout()
    plt.savefig(output_png, bbox_inches='tight')
    plt.close()
    print(f"Profile saved to {output_png}")
```

---

## 2. Interactive Web Charts with Observable Plot

When rendering interactive charts in Next.js / HTML:

```html
<div id="elevation-chart"></div>

<script type="module">
import * as Plot from "https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6/+esm";

const trackData = [
  {km: 0, alt: 650, note: "Startort"},
  {km: 4.2, alt: 1120, note: "Alm"},
  {km: 8.5, alt: 1780, note: "Gipfelkreuz"},
  {km: 12.1, alt: 1420, note: "Schutzhütte"}
];

const plot = Plot.plot({
  width: 720,
  height: 280,
  marginTop: 30,
  x: {label: "Distanz (km)"},
  y: {label: "Höhe (m)", grid: true},
  marks: [
    Plot.areaY(trackData, {x: "km", y: "alt", fill: "#3b82f6", fillOpacity: 0.2}),
    Plot.lineY(trackData, {x: "km", y: "alt", stroke: "#1d4ed8", strokeWidth: 2.5}),
    Plot.dot(trackData, {x: "km", y: "alt", fill: "#1d4ed8", r: 4}),
    Plot.text(trackData, {x: "km", y: "alt", text: "note", dy: -12, fontSize: 11})
  ]
});

document.querySelector("#elevation-chart").append(plot);
</script>
```

---

## 3. Core Principles of Visual Data Storytelling

1. **One Core Message per Chart:** Eliminate chart junk (heavy 3D bevels, bright borders, redundant legends). Every visual element must serve comprehension.
2. **Intentional Color Palettes:**
   - Sequential: Single hue fading from light to dark for magnitudes (e.g. elevation, population density).
   - Diverging: Two opposing hues for positive/negative changes.
   - Categorical: Distinct, colorblind-safe hues (e.g., Okabe-Ito palette).
3. **Direct Data Labelling:** Prefer direct labels next to lines or bars over separate detached legend boxes that force eye travel.
4. **Contextual Reference Points:** Always provide a baseline or landmark (e.g., "Passhöhe 1.820 m", "Durchschnitt").