code icon Code

Generate Political Compass SVG

Generate an SVG visualization of the political compass with the user's position plotted and save to file

Source Code

import fs from "fs";

const args = process.argv.slice(2);
const economicScore = parseFloat(args[0]);
const socialScore = parseFloat(args[1]);
const outputPath = args[2];

if (isNaN(economicScore) || economicScore < -10 || economicScore > 10) {
  console.error("Error: economicScore must be a number between -10 and 10");
  process.exit(1);
}

if (isNaN(socialScore) || socialScore < -10 || socialScore > 10) {
  console.error("Error: socialScore must be a number between -10 and 10");
  process.exit(1);
}

if (!outputPath) {
  console.error("Error: outputPath is required");
  process.exit(1);
}

// SVG dimensions
const size = 400;
const padding = 50;
const gridSize = size - padding * 2;
const center = size / 2;

// Convert scores to pixel coordinates
// Economic: -10 (left) to +10 (right) → padding to (size - padding)
// Social: -10 (libertarian/bottom) to +10 (authoritarian/top) → (size - padding) to padding
const userX = center + (economicScore / 10) * (gridSize / 2);
const userY = center - (socialScore / 10) * (gridSize / 2);

// Generate SVG
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${size}" height="${size}">
  <defs>
    <!-- Quadrant gradients -->
    <linearGradient id="authLeft" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:#dc2626;stop-opacity:0.4"/>
      <stop offset="100%" style="stop-color:#dc2626;stop-opacity:0.15"/>
    </linearGradient>
    <linearGradient id="authRight" x1="100%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" style="stop-color:#2563eb;stop-opacity:0.4"/>
      <stop offset="100%" style="stop-color:#2563eb;stop-opacity:0.15"/>
    </linearGradient>
    <linearGradient id="libLeft" x1="0%" y1="100%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:#16a34a;stop-opacity:0.4"/>
      <stop offset="100%" style="stop-color:#16a34a;stop-opacity:0.15"/>
    </linearGradient>
    <linearGradient id="libRight" x1="100%" y1="100%" x2="0%" y2="0%">
      <stop offset="0%" style="stop-color:#eab308;stop-opacity:0.4"/>
      <stop offset="100%" style="stop-color:#eab308;stop-opacity:0.15"/>
    </linearGradient>
  </defs>

  <!-- Background -->
  <rect width="${size}" height="${size}" fill="#fafafa"/>

  <!-- Quadrants -->
  <rect x="${padding}" y="${padding}" width="${gridSize / 2}" height="${gridSize / 2}" fill="url(#authLeft)"/>
  <rect x="${center}" y="${padding}" width="${gridSize / 2}" height="${gridSize / 2}" fill="url(#authRight)"/>
  <rect x="${padding}" y="${center}" width="${gridSize / 2}" height="${gridSize / 2}" fill="url(#libLeft)"/>
  <rect x="${center}" y="${center}" width="${gridSize / 2}" height="${gridSize / 2}" fill="url(#libRight)"/>

  <!-- Grid lines (light) -->
  ${[1, 2, 3, 4]
    .map(
      (i) => `
  <line x1="${padding + (gridSize / 5) * i}" y1="${padding}" x2="${padding + (gridSize / 5) * i}" y2="${size - padding}" stroke="#d1d5db" stroke-width="0.5"/>
  <line x1="${padding}" y1="${padding + (gridSize / 5) * i}" x2="${size - padding}" y2="${padding + (gridSize / 5) * i}" stroke="#d1d5db" stroke-width="0.5"/>`
    )
    .join("")}

  <!-- Axes -->
  <line x1="${padding}" y1="${center}" x2="${size - padding}" y2="${center}" stroke="#374151" stroke-width="2"/>
  <line x1="${center}" y1="${padding}" x2="${center}" y2="${size - padding}" stroke="#374151" stroke-width="2"/>

  <!-- Axis labels -->
  <text x="${center}" y="${padding - 15}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="12" font-weight="600" fill="#374151">AUTHORITARIAN</text>
  <text x="${center}" y="${size - padding + 25}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="12" font-weight="600" fill="#374151">LIBERTARIAN</text>
  <text x="${padding - 10}" y="${center}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="12" font-weight="600" fill="#374151" transform="rotate(-90 ${padding - 10} ${center})">ECONOMIC LEFT</text>
  <text x="${size - padding + 10}" y="${center}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="12" font-weight="600" fill="#374151" transform="rotate(90 ${size - padding + 10} ${center})">ECONOMIC RIGHT</text>

  <!-- Quadrant ideology labels -->
  <text x="${padding + gridSize / 4}" y="${padding + gridSize / 4 - 10}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="#991b1b" opacity="0.8">Authoritarian</text>
  <text x="${padding + gridSize / 4}" y="${padding + gridSize / 4 + 5}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="#991b1b" opacity="0.8">Left</text>

  <text x="${center + gridSize / 4}" y="${padding + gridSize / 4 - 10}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="#1e40af" opacity="0.8">Authoritarian</text>
  <text x="${center + gridSize / 4}" y="${padding + gridSize / 4 + 5}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="#1e40af" opacity="0.8">Right</text>

  <text x="${padding + gridSize / 4}" y="${center + gridSize / 4 - 10}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="#166534" opacity="0.8">Libertarian</text>
  <text x="${padding + gridSize / 4}" y="${center + gridSize / 4 + 5}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="#166534" opacity="0.8">Left</text>

  <text x="${center + gridSize / 4}" y="${center + gridSize / 4 - 10}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="#a16207" opacity="0.8">Libertarian</text>
  <text x="${center + gridSize / 4}" y="${center + gridSize / 4 + 5}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" fill="#a16207" opacity="0.8">Right</text>

  <!-- User position dot -->
  <circle cx="${userX}" cy="${userY}" r="12" fill="#1f2937" stroke="#ffffff" stroke-width="3"/>
  <circle cx="${userX}" cy="${userY}" r="5" fill="#ffffff"/>

  <!-- Coordinates label -->
  <text x="${userX}" y="${userY + 25}" text-anchor="middle" font-family="system-ui, sans-serif" font-size="10" font-weight="600" fill="#1f2937">(${economicScore.toFixed(1)}, ${socialScore.toFixed(1)})</text>

  <!-- Border -->
  <rect x="${padding}" y="${padding}" width="${gridSize}" height="${gridSize}" fill="none" stroke="#374151" stroke-width="2"/>
</svg>`;

// Save SVG to file
fs.writeFileSync(outputPath, svg);

console.log("Generated political compass SVG visualization");
console.log(`User position: Economic ${economicScore.toFixed(1)}, Social ${socialScore.toFixed(1)}`);
console.log(`Saved to: ${outputPath}`);
console.log(JSON.stringify({
  success: true,
  path: outputPath,
  economicScore: economicScore,
  socialScore: socialScore
}));