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
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").