political-data-visualization

Political Data Visualization

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "political-data-visualization" with this command: npx skills add hack23/riksdagsmonitor/hack23-riksdagsmonitor-political-data-visualization

Political Data Visualization

Purpose

Create compelling, accessible data visualizations using pure HTML/CSS (no JavaScript) to display political metrics, voting patterns, parliamentary activity, and democratic accountability indicators for riksdagsmonitor.

Core Principles

  • CSS-Only: No JavaScript frameworks - pure HTML/CSS for reliability and security

  • Accessibility First: WCAG 2.1 AA compliant, screen reader friendly

  • Semantic Markup: Use <table> with ARIA for complex data

  • Progressive Disclosure: Show summary, reveal details on interaction

  • Color-Blind Safe: Multiple visual cues beyond color (patterns, labels, icons)

  • Responsive Design: Adapt visualizations to mobile/tablet/desktop

  • Performance: Minimal CSS, no external libraries, fast rendering

Visualization Types

Progress Bars (Voting Discipline, Party Cohesion)

/* Semantic HTML */ <div class="progress" role="progressbar" aria-valuenow="87" aria-valuemin="0" aria-valuemax="100"> <span class="progress-label">Party Cohesion: 87%</span> <div class="progress-bar" style="--value: 87%"></div> </div>

/* CSS implementation */ .progress { position: relative; width: 100%; height: 2rem; background: var(--dark-bg); border-radius: 0.5rem; overflow: hidden; border: 2px solid var(--primary-cyan); }

.progress-bar { height: 100%; width: var(--value); background: linear-gradient(90deg, var(--primary-magenta), var(--primary-cyan)); transition: width 0.5s ease-in-out; }

.progress-label { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: var(--light-text); font-weight: bold; z-index: 1; }

Bar Charts (MPs by Party, Committee Activity)

/* Horizontal bar chart */ <div class="bar-chart"> <div class="bar-row"> <span class="bar-label">S (Social Democrats)</span> <div class="bar" style="--value: 30%; --color: var(--party-s)"> <span class="bar-value">107 MPs</span> </div> </div> <div class="bar-row"> <span class="bar-label">M (Moderates)</span> <div class="bar" style="--value: 19%; --color: var(--party-m)"> <span class="bar-value">68 MPs</span> </div> </div> </div>

/* CSS */ .bar-chart { display: grid; gap: 1rem; }

.bar-row { display: grid; grid-template-columns: 200px 1fr; align-items: center; gap: 1rem; }

.bar { position: relative; height: 2.5rem; width: var(--value); max-width: 100%; background: var(--color); border-radius: 0.25rem; display: flex; align-items: center; padding: 0 0.5rem; }

.bar-value { color: white; font-weight: bold; font-size: 0.875rem; }

/* Responsive */ @media (max-width: 767px) { .bar-row { grid-template-columns: 1fr; }

.bar-label { font-size: 0.875rem; } }

Heat Maps (Voting Patterns, Committee Attendance)

/* Grid-based heat map */ <div class="heat-map"> <div class="heat-cell" style="--intensity: 1.0" title="100% attendance"> <span class="sr-only">100% attendance</span> </div> <div class="heat-cell" style="--intensity: 0.75" title="75% attendance"> <span class="sr-only">75% attendance</span> </div> <div class="heat-cell" style="--intensity: 0.5" title="50% attendance"> <span class="sr-only">50% attendance</span> </div> </div>

/* CSS */ .heat-map { display: grid; grid-template-columns: repeat(auto-fill, minmax(2rem, 1fr)); gap: 0.25rem; }

.heat-cell { aspect-ratio: 1; background: color-mix( in srgb, var(--primary-magenta) calc(var(--intensity) * 100%), var(--dark-bg) ); border: 1px solid var(--mid-bg); border-radius: 0.25rem; cursor: help; transition: transform 0.2s; }

.heat-cell:hover, .heat-cell:focus { transform: scale(1.2); z-index: 1; outline: 2px solid var(--primary-cyan); }

Donut Charts (Coalition Breakdown, Vote Distribution)

/* CSS-only donut chart using conic-gradient */ <div class="donut-chart" style=" --s: 107; --m: 68; --sd: 73; --total: 349; --s-pct: calc(var(--s) / var(--total) * 100); --m-pct: calc(var(--m) / var(--total) * 100); --sd-pct: calc(var(--sd) / var(--total) * 100); " role="img" aria-label="Coalition distribution: S 107, M 68, SD 73 of 349 MPs"> <div class="donut-hole"> <span class="donut-total">349</span> <span class="donut-label">MPs</span> </div> </div>

/* CSS */ .donut-chart { width: 200px; height: 200px; border-radius: 50%; background: conic-gradient( from 0deg, var(--party-s) 0% var(--s-pct), var(--party-m) var(--s-pct) calc(var(--s-pct) + var(--m-pct)), var(--party-sd) calc(var(--s-pct) + var(--m-pct)) 100% ); display: flex; align-items: center; justify-content: center; position: relative; }

.donut-hole { width: 60%; height: 60%; border-radius: 50%; background: var(--dark-bg); display: flex; flex-direction: column; align-items: center; justify-content: center; }

.donut-total { font-size: 2rem; font-weight: bold; color: var(--primary-cyan); }

.donut-label { font-size: 0.875rem; color: var(--light-text); }

Timeline Visualizations (Legislative Process, MP Career)

/* Vertical timeline */ <ol class="timeline"> <li class="timeline-item"> <time datetime="2024-09-15">2024-09-15</time> <div class="timeline-content"> <h3>Motion Submitted</h3> <p>MP submitted motion to committee</p> </div> </li> <li class="timeline-item"> <time datetime="2024-10-20">2024-10-20</time> <div class="timeline-content"> <h3>Committee Review</h3> <p>Committee issued report</p> </div> </li> </ol>

/* CSS */ .timeline { list-style: none; padding: 0; margin: 0; position: relative; }

.timeline::before { content: ''; position: absolute; left: 2rem; top: 0; bottom: 0; width: 2px; background: var(--primary-cyan); }

.timeline-item { position: relative; padding-left: 5rem; padding-bottom: 2rem; }

.timeline-item::before { content: ''; position: absolute; left: 1.5rem; top: 0.25rem; width: 1rem; height: 1rem; border-radius: 50%; background: var(--primary-magenta); border: 3px solid var(--dark-bg); box-shadow: 0 0 0 3px var(--primary-cyan); }

.timeline-item time { position: absolute; left: 0; top: 0; font-size: 0.875rem; color: var(--primary-cyan); }

Party Color Palette

:root { /* Swedish political parties (official colors) / --party-s: #E8112d; / Socialdemokraterna (Red) / --party-m: #52BDEC; / Moderaterna (Blue) / --party-sd: #DDDD00; / Sverigedemokraterna (Yellow) / --party-c: #009933; / Centerpartiet (Green) / --party-v: #DA291C; / Vänsterpartiet (Red) / --party-kd: #000077; / Kristdemokraterna (Dark Blue) / --party-l: #006AB3; / Liberalerna (Blue) / --party-mp: #83CF39; / Miljöpartiet (Green) */ }

Accessibility Requirements

Screen Reader Support

<!-- Always include sr-only labels for data --> <div class="progress-bar" style="--value: 87%"> <span class="sr-only">87% party cohesion</span> </div>

<!-- Data tables for complex visualizations --> <table class="data-table" role="table"> <caption>MPs by Party Distribution</caption> <thead> <tr> <th scope="col">Party</th> <th scope="col">MPs</th> <th scope="col">Percentage</th> </tr> </thead> <tbody> <tr> <th scope="row">Socialdemokraterna (S)</th> <td>107</td> <td>30.7%</td> </tr> </tbody> </table>

<!-- Hide visual chart from screen readers, show data table --> <div aria-hidden="true" class="visual-chart">...</div>

Color Contrast

/* Ensure 4.5:1 contrast ratio minimum / .bar-label { color: var(--light-text); / #e0e0e0 on #0a0e27 = 12.6:1 ✅ */ }

/* Use patterns for color-blind accessibility */ .bar-striped { background-image: repeating-linear-gradient( 45deg, transparent, transparent 10px, rgba(255,255,255,0.1) 10px, rgba(255,255,255,0.1) 20px ); }

Keyboard Navigation

/* Make interactive elements focusable */ .heat-cell { cursor: pointer; position: relative; }

.heat-cell:focus { outline: 2px solid var(--primary-cyan); outline-offset: 2px; z-index: 1; }

/* Tooltip on focus/hover */ .heat-cell::after { content: attr(title); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--dark-bg); color: var(--light-text); padding: 0.5rem; border-radius: 0.25rem; white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity 0.2s; }

.heat-cell:hover::after, .heat-cell:focus::after { opacity: 1; }

When to Use

  • Dashboard Design: Political metrics overview

  • Party Analysis: MP distribution, voting patterns, coalition strength

  • Voting Records: Vote outcomes, party discipline, cross-party votes

  • Committee Activity: Productivity metrics, attendance rates

  • MP Profiles: Career timeline, voting record, committee assignments

  • Electoral Analysis: Historical results, trends, forecasts

  • Risk Assessment: 45 risk rules visualization, severity indicators

  • Transparency Metrics: Democratic accountability scores

Examples

Good Pattern: Responsive Voting Discipline Dashboard

<section class="voting-dashboard"> <h2>Voting Discipline by Party (2024/25)</h2>

<div class="party-grid"> <div class="party-card"> <h3>Socialdemokraterna (S)</h3> <div class="progress" role="progressbar" aria-valuenow="89" aria-valuemin="0" aria-valuemax="100"> <span class="progress-label">89% Cohesion</span> <div class="progress-bar" style="--value: 89%; --color: var(--party-s)"></div> </div> <p class="stat">92 unanimous votes, 8 rebels</p> </div>

&#x3C;!-- Repeat for other parties -->

</div> </section>

<style> .party-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 1.5rem; margin-top: 2rem; }

.party-card { background: var(--mid-bg); padding: 1.5rem; border-radius: 0.5rem; border-left: 4px solid var(--primary-cyan); } </style>

Anti-Pattern: JavaScript-Dependent Charts

<!-- ❌ BAD: Requires JavaScript library --> <script src="https://cdn.example.com/charts.js">&#x3C;/script> <canvas id="chart"></canvas> <script> new Chart(document.getElementById('chart'), {...}); </script>

<!-- ✅ GOOD: Pure CSS visualization --> <div class="bar-chart" role="img" aria-label="MPs by party"> <!-- CSS-only bars --> </div>

Anti-Pattern: Inaccessible Visualizations

<!-- ❌ BAD: No screen reader support --> <div class="donut" style="background: conic-gradient(...)"></div>

<!-- ✅ GOOD: Full accessibility --> <div class="donut" role="img" aria-label="Coalition: S 107, M 68, SD 73 MPs"> <!-- Visual chart --> </div> <table class="sr-only"> <caption>Coalition Distribution</caption> <!-- Data table for screen readers --> </table>

Remember

  • CSS-only - no JavaScript libraries

  • Accessibility mandatory - WCAG 2.1 AA, screen reader support

  • Semantic HTML - use <table> for data, proper ARIA roles

  • Responsive - adapt to mobile/tablet/desktop

  • Color-blind safe - use patterns, labels, icons beyond color

  • Performance - minimal CSS, fast rendering

  • Party colors - use official colors for Swedish parties

  • Progressive disclosure - summary view, details on interaction

  • Data tables - always provide for screen readers

  • Tooltip support - title attribute + CSS hover/focus

References

  • CSS-Tricks: Chart.css

  • A11Y: Accessible Data Visualizations

  • MDN: conic-gradient()

  • Web.dev: Building an accessible progress bar

  • WCAG 2.1: Level AA

Version: 1.0

Last Updated: 2026-02-06

Maintained by: Hack23 AB

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

nist-csf-mapping

No summary provided by upstream source.

Repository SourceNeeds Review
General

riksdag-regering-mcp

No summary provided by upstream source.

Repository SourceNeeds Review
General

gh-aw-mcp-gateway

No summary provided by upstream source.

Repository SourceNeeds Review
General

secrets-management

No summary provided by upstream source.

Repository SourceNeeds Review