--- name: blog-chart description: > Generate dark-mode-compatible inline SVG data visualization charts for blog posts. Supports horizontal bar, grouped bar, donut, line, lollipop, area, and radar charts with automatic platform detection (HTML vs JSX/MDX). Enforces chart type diversity, accessible markup (role=img, aria-label), source attribution, and transparent backgrounds. Use when user says "blog chart", "generate chart", "data visualization", "svg chart", "blog graph", "visualize data", or when the blog-write workflow identifies chart-worthy data points (3+ comparable metrics, trends, before/after data). --- # Blog Chart -- Built-In SVG Data Visualization Generates dark-mode-compatible inline SVG charts for blog posts. Invoked internally by `blog-write` and `blog-rewrite` when chart-worthy data is identified. Not a standalone user-facing command. **Styling source of truth:** `../blog/references/visual-media.md` ## Input Format The writer or researcher passes a chart request: ``` Chart Request: - Type: horizontal bar - Title: "AI Citation Sources by Platform" - Data: ChatGPT 43.8%, Perplexity 6.6%, Google AI Overviews 2.2%, Reddit 7.15% - Source: Ahrefs, December 2025 - Platform: mdx (or html) ``` ## Chart Type Selection Select based on the data pattern. Diversity is mandatory — never repeat a type within one post. | Data Pattern | Best Chart Type | |-------------|-----------------| | Before/after comparison | Grouped bar chart | | Ranked factors / correlations | Lollipop chart | | Parts of whole / market share | Donut chart | | Trend over time | Line chart | | Percentage improvement | Horizontal bar chart | | Distribution / range | Area chart | | Multi-dimensional scoring | Radar chart | ## Styling Rules (Non-Negotiable) All charts must work on both dark and light backgrounds: ``` Text elements: fill="currentColor" Grid lines: stroke="currentColor" opacity="0.08" Axis lines: stroke="currentColor" opacity="0.3" Background: transparent (no fill on root SVG) Subtitle text: fill="currentColor" opacity="0.45" Source text: fill="currentColor" opacity="0.35" Label text: fill="currentColor" opacity="0.8" ``` ### Color Palette | Color | Hex | Use Case | |-------|-----|----------| | Orange | `#f97316` | Primary / highest value | | Sky Blue | `#38bdf8` | Secondary / comparison | | Purple | `#a78bfa` | Tertiary / special category | | Green | `#22c55e` | Quaternary / positive indicator | For text inside colored elements: `fill="white"` with `fontWeight="800"`. ## Standard SVG Shell (HTML) ```xml Chart Title Description for screen readers with all key data points and source Source: Source Name (Year) ``` ## JSX/MDX Shell (camelCase attributes) ```jsx Chart Title Description for screen readers {/* Chart content */} Source: Source Name (Year) ``` ## JSX Attribute Conversion (Required for MDX) | HTML | JSX | |------|-----| | `stroke-width` | `strokeWidth` | | `stroke-dasharray` | `strokeDasharray` | | `stroke-linecap` | `strokeLinecap` | | `text-anchor` | `textAnchor` | | `font-size` | `fontSize` | | `font-weight` | `fontWeight` | | `font-family` | `fontFamily` | | `class` | `className` | | `style="..."` | `style={{...}}` | ## Chart Type Construction ### Horizontal Bar Chart Best for: percentage improvements, single-metric comparisons. 1. Define chart area: x=80, y=40, width=440, height=280 2. Calculate bar height: `chartHeight / dataCount - gap` (gap=8) 3. Calculate bar width: `(value / maxValue) * chartWidth` 4. Position bars: `y = chartY + index * (barHeight + gap)` 5. Label on left (right-aligned at x=75): category name 6. Value label at end of bar: percentage or number 7. Source text at bottom center ### Grouped Bar Chart Best for: before/after, A vs B comparisons. 1. Define groups along Y axis, bars within each group 2. Use 2 colors (primary + secondary) for the two series 3. Add legend at top: colored square + label for each series 4. Gap between groups > gap within groups ### Donut Chart Best for: parts of whole, market share. 1. Center: cx=280, cy=180, outer radius=140, inner radius=80 2. Calculate arc segments using cumulative angles 3. Each segment: `` 4. Center text: total or key label 5. Legend below chart with color squares + labels + values ### Line Chart Best for: trends over time. 1. X axis: time periods, evenly spaced 2. Y axis: value range with 4-5 grid lines 3. Draw grid lines: `stroke="currentColor" opacity="0.08"` 4. Plot data points: `` 5. Connect with: `` 6. Optional: area fill below line with `opacity="0.1"` ### Lollipop Chart Best for: ranked factors, correlations. 1. Horizontal orientation (like bar chart but with circles) 2. Thin line from axis to data point: `stroke="currentColor" opacity="0.15" strokeWidth="1"` 3. Circle at data point: `r="6"` with fill color 4. Value label next to circle 5. Categories on Y axis (left-aligned) ### Area Chart Best for: distribution, cumulative data. 1. Same as line chart but with filled area below 2. Area fill: `` 3. Line on top: `stroke="color" strokeWidth="2" fill="none"` 4. Grid lines behind the area ### Radar Chart Best for: multi-dimensional scoring (5-7 axes). 1. Center: cx=280, cy=190 2. Draw concentric polygons for grid (3-4 levels) 3. Calculate axis endpoints at equal angles 4. Plot data points on each axis proportional to value 5. Connect data points with filled polygon: `fill="color" opacity="0.2" stroke="color"` 6. Label each axis at the outer edge ## Output Format Wrap every chart in a `
` element: **HTML:** ```html
[Chart Title] [Full description with data points for screen readers] Source: [Source Name] ([Year])
``` **MDX:** ```mdx
[Chart Title] [Full description] {/* chart content with camelCase attributes */} Source: [Source Name] ([Year])
``` ## Quality Checklist (Verify Before Returning) - [ ] No hardcoded text colors (all use `currentColor`) - [ ] No white/light backgrounds (transparent or none) - [ ] Source attribution text present at bottom - [ ] `role="img"` and `aria-label` present on `` - [ ] `` and `` present inside `` - [ ] Chart type not already used in this post - [ ] If MDX: all attributes camelCased (no hyphens in attribute names) - [ ] Data values match the source data exactly - [ ] Color palette uses only approved colors - [ ] ViewBox is `0 0 560 380` (standard) or justified alternative