{
  "schemaVersion": "1.0",
  "item": {
    "slug": "data-visualization-2",
    "name": "Data Visualization",
    "source": "tencent",
    "type": "skill",
    "category": "数据分析",
    "sourceUrl": "https://clawhub.ai/okaris/data-visualization-2",
    "canonicalUrl": "https://clawhub.ai/okaris/data-visualization-2",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/data-visualization-2",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=data-visualization-2",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "data-visualization-2",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-29T08:49:14.070Z",
      "expiresAt": "2026-05-06T08:49:14.070Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=data-visualization-2",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=data-visualization-2",
        "contentDisposition": "attachment; filename=\"data-visualization-2-0.1.5.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "data-visualization-2"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/data-visualization-2"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/data-visualization-2",
    "agentPageUrl": "https://openagent3.xyz/skills/data-visualization-2/agent",
    "manifestUrl": "https://openagent3.xyz/skills/data-visualization-2/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/data-visualization-2/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Data Visualization",
        "body": "Create clear, effective data visualizations via inference.sh CLI."
      },
      {
        "title": "Quick Start",
        "body": "curl -fsSL https://cli.inference.sh | sh && infsh login\n\n# Generate a chart with Python\ninfsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\nmonths = [\\\"Jan\\\", \\\"Feb\\\", \\\"Mar\\\", \\\"Apr\\\", \\\"May\\\", \\\"Jun\\\"]\\nrevenue = [42, 48, 55, 61, 72, 89]\\n\\nfig, ax = plt.subplots(figsize=(10, 6))\\nax.bar(months, revenue, color=\\\"#3b82f6\\\", width=0.6)\\nax.set_ylabel(\\\"Revenue ($K)\\\")\\nax.set_title(\\\"Monthly Revenue Growth\\\", fontweight=\\\"bold\\\")\\nfor i, v in enumerate(revenue):\\n    ax.text(i, v + 1, f\\\"${v}K\\\", ha=\\\"center\\\", fontweight=\\\"bold\\\")\\nplt.tight_layout()\\nplt.savefig(\\\"revenue.png\\\", dpi=150)\\nprint(\\\"Saved\\\")\"\n}'\n\nInstall note: The install script only detects your OS/architecture, downloads the matching binary from dist.inference.sh, and verifies its SHA-256 checksum. No elevated permissions or background processes. Manual install & verification available."
      },
      {
        "title": "Which Chart for Which Data?",
        "body": "Data RelationshipBest ChartNever UseChange over timeLine chartPie chartComparing categoriesBar chart (horizontal for many categories)Line chartPart of a wholeStacked bar, treemapPie chart (controversial but: bar is always clearer)DistributionHistogram, box plotBar chartCorrelationScatter plotBar chartRankingHorizontal bar chartVertical bar, pieGeographicChoropleth mapBar chartComposition over timeStacked area chartMultiple pie chartsSingle metricBig number (KPI card)Any chart (overkill)Flow / processSankey diagramBar chart"
      },
      {
        "title": "The Pie Chart Problem",
        "body": "Pie charts are almost always the wrong choice:\n\n❌ Pie chart problems:\n   - Hard to compare similar-sized slices\n   - Can't show more than 5-6 categories\n   - 3D pie charts are always wrong\n   - Impossible to read exact values\n\n✅ Use instead:\n   - Horizontal bar chart (easy comparison)\n   - Stacked bar (part of whole)\n   - Treemap (hierarchical parts)\n   - Just a table (if precision matters)"
      },
      {
        "title": "Axes",
        "body": "RuleWhyAlways start Y-axis at 0 (bar charts)Prevents misleading visualLine charts CAN start above 0When showing change, not absolute valuesLabel both axesReader shouldn't have to guess unitsRemove unnecessary gridlinesReduce visual noiseUse horizontal labelsVertical text is hard to readSort bar charts by valueDon't use alphabetical order unless there's a reason"
      },
      {
        "title": "Color",
        "body": "PrincipleApplicationMax 5-7 colors per chartMore becomes unreadableHighlight one thingGrey everything else, color the focusSequential for magnitudeLight → dark for low → highDiverging for positive/negativeRed ← neutral → blueCategorical for groupsDistinct hues, similar brightnessColorblind-safeAvoid red/green only — add shapes or labelsConsistent meaningIf blue = revenue, keep it blue everywhere"
      },
      {
        "title": "Good Color Palettes",
        "body": "# Sequential (low to high)\nsequential = [\"#eff6ff\", \"#bfdbfe\", \"#60a5fa\", \"#2563eb\", \"#1d4ed8\"]\n\n# Diverging (negative to positive)\ndiverging = [\"#ef4444\", \"#f87171\", \"#d1d5db\", \"#34d399\", \"#10b981\"]\n\n# Categorical (distinct groups)\ncategorical = [\"#3b82f6\", \"#f59e0b\", \"#10b981\", \"#8b5cf6\", \"#ef4444\"]\n\n# Colorblind-safe\ncb_safe = [\"#0077BB\", \"#33BBEE\", \"#009988\", \"#EE7733\", \"#CC3311\"]"
      },
      {
        "title": "Text and Labels",
        "body": "ElementRuleTitleStates the insight, not the data type. \"Revenue doubled in Q2\" not \"Q2 Revenue Chart\"AnnotationsCall out key data points directly on the chartLegendAvoid if possible — label directly on chart lines/barsFont sizeMinimum 12px, 14px+ for presentationsNumber formatUse K, M, B for large numbers (42K not 42,000)Data labelsAdd to bars/points when exact values matter"
      },
      {
        "title": "Line Chart (Time Series)",
        "body": "infsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\nfig, ax = plt.subplots(figsize=(12, 6))\\nfig.patch.set_facecolor(\\\"white\\\")\\n\\nmonths = [\\\"Jan\\\", \\\"Feb\\\", \\\"Mar\\\", \\\"Apr\\\", \\\"May\\\", \\\"Jun\\\", \\\"Jul\\\", \\\"Aug\\\", \\\"Sep\\\", \\\"Oct\\\", \\\"Nov\\\", \\\"Dec\\\"]\\nthis_year = [120, 135, 148, 162, 178, 195, 210, 228, 245, 268, 290, 320]\\nlast_year = [95, 102, 108, 115, 122, 130, 138, 145, 155, 165, 178, 190]\\n\\nax.plot(months, this_year, color=\\\"#3b82f6\\\", linewidth=2.5, marker=\\\"o\\\", markersize=6, label=\\\"2024\\\")\\nax.plot(months, last_year, color=\\\"#94a3b8\\\", linewidth=2, linestyle=\\\"--\\\", label=\\\"2023\\\")\\nax.fill_between(range(len(months)), last_year, this_year, alpha=0.1, color=\\\"#3b82f6\\\")\\n\\nax.annotate(\\\"$320K\\\", xy=(11, 320), fontsize=14, fontweight=\\\"bold\\\", color=\\\"#3b82f6\\\")\\nax.annotate(\\\"$190K\\\", xy=(11, 190), fontsize=12, color=\\\"#94a3b8\\\")\\n\\nax.set_ylabel(\\\"Revenue ($K)\\\", fontsize=12)\\nax.set_title(\\\"Revenue grew 68% year-over-year\\\", fontsize=16, fontweight=\\\"bold\\\")\\nax.legend(fontsize=12)\\nax.spines[\\\"top\\\"].set_visible(False)\\nax.spines[\\\"right\\\"].set_visible(False)\\nax.grid(axis=\\\"y\\\", alpha=0.3)\\nplt.tight_layout()\\nplt.savefig(\\\"line-chart.png\\\", dpi=150)\\nprint(\\\"Saved\\\")\"\n}'"
      },
      {
        "title": "Horizontal Bar Chart (Comparison)",
        "body": "infsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\nfig, ax = plt.subplots(figsize=(10, 6))\\n\\ncategories = [\\\"Email\\\", \\\"Social\\\", \\\"SEO\\\", \\\"Paid Ads\\\", \\\"Referral\\\", \\\"Direct\\\"]\\nvalues = [12, 18, 35, 22, 8, 5]\\ncolors = [\\\"#94a3b8\\\"] * len(values)\\ncolors[2] = \\\"#3b82f6\\\"  # Highlight the winner\\n\\n# Sort by value\\nsorted_pairs = sorted(zip(values, categories, colors))\\nvalues, categories, colors = zip(*sorted_pairs)\\n\\nax.barh(categories, values, color=colors, height=0.6)\\nfor i, v in enumerate(values):\\n    ax.text(v + 0.5, i, f\\\"{v}%\\\", va=\\\"center\\\", fontsize=12, fontweight=\\\"bold\\\")\\n\\nax.set_xlabel(\\\"% of Total Traffic\\\", fontsize=12)\\nax.set_title(\\\"SEO drives the most traffic\\\", fontsize=16, fontweight=\\\"bold\\\")\\nax.spines[\\\"top\\\"].set_visible(False)\\nax.spines[\\\"right\\\"].set_visible(False)\\nplt.tight_layout()\\nplt.savefig(\\\"bar-chart.png\\\", dpi=150)\\nprint(\\\"Saved\\\")\"\n}'"
      },
      {
        "title": "KPI / Big Number Card",
        "body": "infsh app run infsh/html-to-image --input '{\n  \"html\": \"<div style=\\\"display:flex;gap:20px;padding:20px;background:white;font-family:system-ui\\\"><div style=\\\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\\\"><p style=\\\"color:#64748b;font-size:14px;margin:0\\\">Monthly Revenue</p><p style=\\\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\\\">$89K</p><p style=\\\"color:#22c55e;font-size:14px;margin:0\\\">↑ 23% vs last month</p></div><div style=\\\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\\\"><p style=\\\"color:#64748b;font-size:14px;margin:0\\\">Active Users</p><p style=\\\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\\\">12.4K</p><p style=\\\"color:#22c55e;font-size:14px;margin:0\\\">↑ 8% vs last month</p></div><div style=\\\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\\\"><p style=\\\"color:#64748b;font-size:14px;margin:0\\\">Churn Rate</p><p style=\\\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\\\">2.1%</p><p style=\\\"color:#ef4444;font-size:14px;margin:0\\\">↑ 0.3% vs last month</p></div></div>\"\n}'"
      },
      {
        "title": "Heatmap",
        "body": "infsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport numpy as np\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\nfig, ax = plt.subplots(figsize=(10, 6))\\n\\ndays = [\\\"Mon\\\", \\\"Tue\\\", \\\"Wed\\\", \\\"Thu\\\", \\\"Fri\\\", \\\"Sat\\\", \\\"Sun\\\"]\\nhours = [\\\"9AM\\\", \\\"10AM\\\", \\\"11AM\\\", \\\"12PM\\\", \\\"1PM\\\", \\\"2PM\\\", \\\"3PM\\\", \\\"4PM\\\", \\\"5PM\\\"]\\ndata = np.random.randint(10, 100, size=(len(hours), len(days)))\\ndata[2][1] = 95  # Tuesday 11AM peak\\ndata[2][3] = 88  # Thursday 11AM\\n\\nim = ax.imshow(data, cmap=\\\"Blues\\\", aspect=\\\"auto\\\")\\nax.set_xticks(range(len(days)))\\nax.set_yticks(range(len(hours)))\\nax.set_xticklabels(days, fontsize=12)\\nax.set_yticklabels(hours, fontsize=12)\\n\\nfor i in range(len(hours)):\\n    for j in range(len(days)):\\n        color = \\\"white\\\" if data[i][j] > 60 else \\\"black\\\"\\n        ax.text(j, i, data[i][j], ha=\\\"center\\\", va=\\\"center\\\", fontsize=10, color=color)\\n\\nax.set_title(\\\"Website Traffic by Day & Hour\\\", fontsize=16, fontweight=\\\"bold\\\")\\nplt.colorbar(im, label=\\\"Visitors\\\")\\nplt.tight_layout()\\nplt.savefig(\\\"heatmap.png\\\", dpi=150)\\nprint(\\\"Saved\\\")\"\n}'"
      },
      {
        "title": "The Narrative Arc",
        "body": "StepWhat to DoExample1. ContextSet up what the reader needs to know\"We track customer acquisition cost monthly\"2. TensionShow the problem or change\"CAC increased 40% in Q3\"3. ResolutionShow the insight or solution\"But LTV increased 80%, so unit economics improved\""
      },
      {
        "title": "Title as Insight",
        "body": "❌ Descriptive titles (what the chart shows):\n   \"Q3 Revenue by Product Line\"\n   \"Monthly Active Users 2024\"\n   \"Customer Satisfaction Survey Results\"\n\n✅ Insight titles (what the chart means):\n   \"Enterprise product drives 70% of revenue growth\"\n   \"User growth accelerated after the free tier launch\"\n   \"Support response time is the #1 satisfaction driver\""
      },
      {
        "title": "Annotation Techniques",
        "body": "TechniqueWhen to UseCall-out labelHighlight a specific data point (\"Peak: 320K\")Reference lineShow target/benchmark (\"Goal: 100K\")Shaded regionMark a time period (\"Product launch window\")Arrow + textDraw attention to trend changeBefore/after lineShow impact of an event"
      },
      {
        "title": "Dark Mode Charts",
        "body": "infsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\n# Dark theme\\nplt.rcParams.update({\\n    \\\"figure.facecolor\\\": \\\"#0f172a\\\",\\n    \\\"axes.facecolor\\\": \\\"#0f172a\\\",\\n    \\\"axes.edgecolor\\\": \\\"#334155\\\",\\n    \\\"axes.labelcolor\\\": \\\"white\\\",\\n    \\\"text.color\\\": \\\"white\\\",\\n    \\\"xtick.color\\\": \\\"white\\\",\\n    \\\"ytick.color\\\": \\\"white\\\",\\n    \\\"grid.color\\\": \\\"#1e293b\\\"\\n})\\n\\nfig, ax = plt.subplots(figsize=(12, 6))\\nmonths = [\\\"Jan\\\", \\\"Feb\\\", \\\"Mar\\\", \\\"Apr\\\", \\\"May\\\", \\\"Jun\\\"]\\nvalues = [45, 52, 58, 72, 85, 98]\\n\\nax.plot(months, values, color=\\\"#818cf8\\\", linewidth=3, marker=\\\"o\\\", markersize=8)\\nax.fill_between(range(len(months)), values, alpha=0.15, color=\\\"#818cf8\\\")\\nax.set_title(\\\"MRR Growth: On track for $100K\\\", fontsize=18, fontweight=\\\"bold\\\")\\nax.set_ylabel(\\\"MRR ($K)\\\", fontsize=13)\\nax.spines[\\\"top\\\"].set_visible(False)\\nax.spines[\\\"right\\\"].set_visible(False)\\nax.grid(axis=\\\"y\\\", alpha=0.2)\\n\\nfor i, v in enumerate(values):\\n    ax.annotate(f\\\"${v}K\\\", (i, v), textcoords=\\\"offset points\\\", xytext=(0, 12), ha=\\\"center\\\", fontsize=11, fontweight=\\\"bold\\\")\\n\\nplt.tight_layout()\\nplt.savefig(\\\"dark-chart.png\\\", dpi=150, facecolor=\\\"#0f172a\\\")\\nprint(\\\"Saved\\\")\"\n}'"
      },
      {
        "title": "Common Mistakes",
        "body": "MistakeProblemFixPie chartsHard to compare, always misleadingUse bar charts or treemapsY-axis not starting at 0 (bar charts)Exaggerates differencesStart at 0 for bars, OK to truncate for linesToo many colorsVisual noise, confusingMax 5-7 colors, highlight only what mattersNo title or generic titleReader doesn't know the insightTitle = the takeaway, not the data type3D chartsDistorts data, looks unprofessionalAlways use 2DDual Y-axesMisleading, hard to readUse two separate chartsAlphabetical sort on bar chartsHides the storySort by value (largest first)No labels on axesReader can't interpretAlways label with unitsChartjunk (decorative elements)Distracts from dataRemove everything that doesn't convey informationRed/green only for color codingColorblind users can't readUse shapes, patterns, or colorblind-safe palettes"
      },
      {
        "title": "Related Skills",
        "body": "npx skills add inference-sh/skills@pitch-deck-visuals\nnpx skills add inference-sh/skills@technical-blog-writing\nnpx skills add inference-sh/skills@competitor-teardown\n\nBrowse all apps: infsh app list"
      }
    ],
    "body": "Data Visualization\n\nCreate clear, effective data visualizations via inference.sh CLI.\n\nQuick Start\ncurl -fsSL https://cli.inference.sh | sh && infsh login\n\n# Generate a chart with Python\ninfsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\nmonths = [\\\"Jan\\\", \\\"Feb\\\", \\\"Mar\\\", \\\"Apr\\\", \\\"May\\\", \\\"Jun\\\"]\\nrevenue = [42, 48, 55, 61, 72, 89]\\n\\nfig, ax = plt.subplots(figsize=(10, 6))\\nax.bar(months, revenue, color=\\\"#3b82f6\\\", width=0.6)\\nax.set_ylabel(\\\"Revenue ($K)\\\")\\nax.set_title(\\\"Monthly Revenue Growth\\\", fontweight=\\\"bold\\\")\\nfor i, v in enumerate(revenue):\\n    ax.text(i, v + 1, f\\\"${v}K\\\", ha=\\\"center\\\", fontweight=\\\"bold\\\")\\nplt.tight_layout()\\nplt.savefig(\\\"revenue.png\\\", dpi=150)\\nprint(\\\"Saved\\\")\"\n}'\n\n\nInstall note: The install script only detects your OS/architecture, downloads the matching binary from dist.inference.sh, and verifies its SHA-256 checksum. No elevated permissions or background processes. Manual install & verification available.\n\nChart Selection Guide\nWhich Chart for Which Data?\nData Relationship\tBest Chart\tNever Use\nChange over time\tLine chart\tPie chart\nComparing categories\tBar chart (horizontal for many categories)\tLine chart\nPart of a whole\tStacked bar, treemap\tPie chart (controversial but: bar is always clearer)\nDistribution\tHistogram, box plot\tBar chart\nCorrelation\tScatter plot\tBar chart\nRanking\tHorizontal bar chart\tVertical bar, pie\nGeographic\tChoropleth map\tBar chart\nComposition over time\tStacked area chart\tMultiple pie charts\nSingle metric\tBig number (KPI card)\tAny chart (overkill)\nFlow / process\tSankey diagram\tBar chart\nThe Pie Chart Problem\n\nPie charts are almost always the wrong choice:\n\n❌ Pie chart problems:\n   - Hard to compare similar-sized slices\n   - Can't show more than 5-6 categories\n   - 3D pie charts are always wrong\n   - Impossible to read exact values\n\n✅ Use instead:\n   - Horizontal bar chart (easy comparison)\n   - Stacked bar (part of whole)\n   - Treemap (hierarchical parts)\n   - Just a table (if precision matters)\n\nDesign Rules\nAxes\nRule\tWhy\nAlways start Y-axis at 0 (bar charts)\tPrevents misleading visual\nLine charts CAN start above 0\tWhen showing change, not absolute values\nLabel both axes\tReader shouldn't have to guess units\nRemove unnecessary gridlines\tReduce visual noise\nUse horizontal labels\tVertical text is hard to read\nSort bar charts by value\tDon't use alphabetical order unless there's a reason\nColor\nPrinciple\tApplication\nMax 5-7 colors per chart\tMore becomes unreadable\nHighlight one thing\tGrey everything else, color the focus\nSequential for magnitude\tLight → dark for low → high\nDiverging for positive/negative\tRed ← neutral → blue\nCategorical for groups\tDistinct hues, similar brightness\nColorblind-safe\tAvoid red/green only — add shapes or labels\nConsistent meaning\tIf blue = revenue, keep it blue everywhere\nGood Color Palettes\n# Sequential (low to high)\nsequential = [\"#eff6ff\", \"#bfdbfe\", \"#60a5fa\", \"#2563eb\", \"#1d4ed8\"]\n\n# Diverging (negative to positive)\ndiverging = [\"#ef4444\", \"#f87171\", \"#d1d5db\", \"#34d399\", \"#10b981\"]\n\n# Categorical (distinct groups)\ncategorical = [\"#3b82f6\", \"#f59e0b\", \"#10b981\", \"#8b5cf6\", \"#ef4444\"]\n\n# Colorblind-safe\ncb_safe = [\"#0077BB\", \"#33BBEE\", \"#009988\", \"#EE7733\", \"#CC3311\"]\n\nText and Labels\nElement\tRule\nTitle\tStates the insight, not the data type. \"Revenue doubled in Q2\" not \"Q2 Revenue Chart\"\nAnnotations\tCall out key data points directly on the chart\nLegend\tAvoid if possible — label directly on chart lines/bars\nFont size\tMinimum 12px, 14px+ for presentations\nNumber format\tUse K, M, B for large numbers (42K not 42,000)\nData labels\tAdd to bars/points when exact values matter\nChart Recipes\nLine Chart (Time Series)\ninfsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\nfig, ax = plt.subplots(figsize=(12, 6))\\nfig.patch.set_facecolor(\\\"white\\\")\\n\\nmonths = [\\\"Jan\\\", \\\"Feb\\\", \\\"Mar\\\", \\\"Apr\\\", \\\"May\\\", \\\"Jun\\\", \\\"Jul\\\", \\\"Aug\\\", \\\"Sep\\\", \\\"Oct\\\", \\\"Nov\\\", \\\"Dec\\\"]\\nthis_year = [120, 135, 148, 162, 178, 195, 210, 228, 245, 268, 290, 320]\\nlast_year = [95, 102, 108, 115, 122, 130, 138, 145, 155, 165, 178, 190]\\n\\nax.plot(months, this_year, color=\\\"#3b82f6\\\", linewidth=2.5, marker=\\\"o\\\", markersize=6, label=\\\"2024\\\")\\nax.plot(months, last_year, color=\\\"#94a3b8\\\", linewidth=2, linestyle=\\\"--\\\", label=\\\"2023\\\")\\nax.fill_between(range(len(months)), last_year, this_year, alpha=0.1, color=\\\"#3b82f6\\\")\\n\\nax.annotate(\\\"$320K\\\", xy=(11, 320), fontsize=14, fontweight=\\\"bold\\\", color=\\\"#3b82f6\\\")\\nax.annotate(\\\"$190K\\\", xy=(11, 190), fontsize=12, color=\\\"#94a3b8\\\")\\n\\nax.set_ylabel(\\\"Revenue ($K)\\\", fontsize=12)\\nax.set_title(\\\"Revenue grew 68% year-over-year\\\", fontsize=16, fontweight=\\\"bold\\\")\\nax.legend(fontsize=12)\\nax.spines[\\\"top\\\"].set_visible(False)\\nax.spines[\\\"right\\\"].set_visible(False)\\nax.grid(axis=\\\"y\\\", alpha=0.3)\\nplt.tight_layout()\\nplt.savefig(\\\"line-chart.png\\\", dpi=150)\\nprint(\\\"Saved\\\")\"\n}'\n\nHorizontal Bar Chart (Comparison)\ninfsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\nfig, ax = plt.subplots(figsize=(10, 6))\\n\\ncategories = [\\\"Email\\\", \\\"Social\\\", \\\"SEO\\\", \\\"Paid Ads\\\", \\\"Referral\\\", \\\"Direct\\\"]\\nvalues = [12, 18, 35, 22, 8, 5]\\ncolors = [\\\"#94a3b8\\\"] * len(values)\\ncolors[2] = \\\"#3b82f6\\\"  # Highlight the winner\\n\\n# Sort by value\\nsorted_pairs = sorted(zip(values, categories, colors))\\nvalues, categories, colors = zip(*sorted_pairs)\\n\\nax.barh(categories, values, color=colors, height=0.6)\\nfor i, v in enumerate(values):\\n    ax.text(v + 0.5, i, f\\\"{v}%\\\", va=\\\"center\\\", fontsize=12, fontweight=\\\"bold\\\")\\n\\nax.set_xlabel(\\\"% of Total Traffic\\\", fontsize=12)\\nax.set_title(\\\"SEO drives the most traffic\\\", fontsize=16, fontweight=\\\"bold\\\")\\nax.spines[\\\"top\\\"].set_visible(False)\\nax.spines[\\\"right\\\"].set_visible(False)\\nplt.tight_layout()\\nplt.savefig(\\\"bar-chart.png\\\", dpi=150)\\nprint(\\\"Saved\\\")\"\n}'\n\nKPI / Big Number Card\ninfsh app run infsh/html-to-image --input '{\n  \"html\": \"<div style=\\\"display:flex;gap:20px;padding:20px;background:white;font-family:system-ui\\\"><div style=\\\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\\\"><p style=\\\"color:#64748b;font-size:14px;margin:0\\\">Monthly Revenue</p><p style=\\\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\\\">$89K</p><p style=\\\"color:#22c55e;font-size:14px;margin:0\\\">↑ 23% vs last month</p></div><div style=\\\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\\\"><p style=\\\"color:#64748b;font-size:14px;margin:0\\\">Active Users</p><p style=\\\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\\\">12.4K</p><p style=\\\"color:#22c55e;font-size:14px;margin:0\\\">↑ 8% vs last month</p></div><div style=\\\"background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:24px;width:200px;text-align:center\\\"><p style=\\\"color:#64748b;font-size:14px;margin:0\\\">Churn Rate</p><p style=\\\"font-size:48px;font-weight:900;margin:8px 0;color:#1e293b\\\">2.1%</p><p style=\\\"color:#ef4444;font-size:14px;margin:0\\\">↑ 0.3% vs last month</p></div></div>\"\n}'\n\nHeatmap\ninfsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport numpy as np\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\nfig, ax = plt.subplots(figsize=(10, 6))\\n\\ndays = [\\\"Mon\\\", \\\"Tue\\\", \\\"Wed\\\", \\\"Thu\\\", \\\"Fri\\\", \\\"Sat\\\", \\\"Sun\\\"]\\nhours = [\\\"9AM\\\", \\\"10AM\\\", \\\"11AM\\\", \\\"12PM\\\", \\\"1PM\\\", \\\"2PM\\\", \\\"3PM\\\", \\\"4PM\\\", \\\"5PM\\\"]\\ndata = np.random.randint(10, 100, size=(len(hours), len(days)))\\ndata[2][1] = 95  # Tuesday 11AM peak\\ndata[2][3] = 88  # Thursday 11AM\\n\\nim = ax.imshow(data, cmap=\\\"Blues\\\", aspect=\\\"auto\\\")\\nax.set_xticks(range(len(days)))\\nax.set_yticks(range(len(hours)))\\nax.set_xticklabels(days, fontsize=12)\\nax.set_yticklabels(hours, fontsize=12)\\n\\nfor i in range(len(hours)):\\n    for j in range(len(days)):\\n        color = \\\"white\\\" if data[i][j] > 60 else \\\"black\\\"\\n        ax.text(j, i, data[i][j], ha=\\\"center\\\", va=\\\"center\\\", fontsize=10, color=color)\\n\\nax.set_title(\\\"Website Traffic by Day & Hour\\\", fontsize=16, fontweight=\\\"bold\\\")\\nplt.colorbar(im, label=\\\"Visitors\\\")\\nplt.tight_layout()\\nplt.savefig(\\\"heatmap.png\\\", dpi=150)\\nprint(\\\"Saved\\\")\"\n}'\n\nStorytelling with Data\nThe Narrative Arc\nStep\tWhat to Do\tExample\n1. Context\tSet up what the reader needs to know\t\"We track customer acquisition cost monthly\"\n2. Tension\tShow the problem or change\t\"CAC increased 40% in Q3\"\n3. Resolution\tShow the insight or solution\t\"But LTV increased 80%, so unit economics improved\"\nTitle as Insight\n❌ Descriptive titles (what the chart shows):\n   \"Q3 Revenue by Product Line\"\n   \"Monthly Active Users 2024\"\n   \"Customer Satisfaction Survey Results\"\n\n✅ Insight titles (what the chart means):\n   \"Enterprise product drives 70% of revenue growth\"\n   \"User growth accelerated after the free tier launch\"\n   \"Support response time is the #1 satisfaction driver\"\n\nAnnotation Techniques\nTechnique\tWhen to Use\nCall-out label\tHighlight a specific data point (\"Peak: 320K\")\nReference line\tShow target/benchmark (\"Goal: 100K\")\nShaded region\tMark a time period (\"Product launch window\")\nArrow + text\tDraw attention to trend change\nBefore/after line\tShow impact of an event\nDark Mode Charts\ninfsh app run infsh/python-executor --input '{\n  \"code\": \"import matplotlib.pyplot as plt\\nimport matplotlib\\nmatplotlib.use(\\\"Agg\\\")\\n\\n# Dark theme\\nplt.rcParams.update({\\n    \\\"figure.facecolor\\\": \\\"#0f172a\\\",\\n    \\\"axes.facecolor\\\": \\\"#0f172a\\\",\\n    \\\"axes.edgecolor\\\": \\\"#334155\\\",\\n    \\\"axes.labelcolor\\\": \\\"white\\\",\\n    \\\"text.color\\\": \\\"white\\\",\\n    \\\"xtick.color\\\": \\\"white\\\",\\n    \\\"ytick.color\\\": \\\"white\\\",\\n    \\\"grid.color\\\": \\\"#1e293b\\\"\\n})\\n\\nfig, ax = plt.subplots(figsize=(12, 6))\\nmonths = [\\\"Jan\\\", \\\"Feb\\\", \\\"Mar\\\", \\\"Apr\\\", \\\"May\\\", \\\"Jun\\\"]\\nvalues = [45, 52, 58, 72, 85, 98]\\n\\nax.plot(months, values, color=\\\"#818cf8\\\", linewidth=3, marker=\\\"o\\\", markersize=8)\\nax.fill_between(range(len(months)), values, alpha=0.15, color=\\\"#818cf8\\\")\\nax.set_title(\\\"MRR Growth: On track for $100K\\\", fontsize=18, fontweight=\\\"bold\\\")\\nax.set_ylabel(\\\"MRR ($K)\\\", fontsize=13)\\nax.spines[\\\"top\\\"].set_visible(False)\\nax.spines[\\\"right\\\"].set_visible(False)\\nax.grid(axis=\\\"y\\\", alpha=0.2)\\n\\nfor i, v in enumerate(values):\\n    ax.annotate(f\\\"${v}K\\\", (i, v), textcoords=\\\"offset points\\\", xytext=(0, 12), ha=\\\"center\\\", fontsize=11, fontweight=\\\"bold\\\")\\n\\nplt.tight_layout()\\nplt.savefig(\\\"dark-chart.png\\\", dpi=150, facecolor=\\\"#0f172a\\\")\\nprint(\\\"Saved\\\")\"\n}'\n\nCommon Mistakes\nMistake\tProblem\tFix\nPie charts\tHard to compare, always misleading\tUse bar charts or treemaps\nY-axis not starting at 0 (bar charts)\tExaggerates differences\tStart at 0 for bars, OK to truncate for lines\nToo many colors\tVisual noise, confusing\tMax 5-7 colors, highlight only what matters\nNo title or generic title\tReader doesn't know the insight\tTitle = the takeaway, not the data type\n3D charts\tDistorts data, looks unprofessional\tAlways use 2D\nDual Y-axes\tMisleading, hard to read\tUse two separate charts\nAlphabetical sort on bar charts\tHides the story\tSort by value (largest first)\nNo labels on axes\tReader can't interpret\tAlways label with units\nChartjunk (decorative elements)\tDistracts from data\tRemove everything that doesn't convey information\nRed/green only for color coding\tColorblind users can't read\tUse shapes, patterns, or colorblind-safe palettes\nRelated Skills\nnpx skills add inference-sh/skills@pitch-deck-visuals\nnpx skills add inference-sh/skills@technical-blog-writing\nnpx skills add inference-sh/skills@competitor-teardown\n\n\nBrowse all apps: infsh app list"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/okaris/data-visualization-2",
    "publisherUrl": "https://clawhub.ai/okaris/data-visualization-2",
    "owner": "okaris",
    "version": "0.1.5",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/data-visualization-2",
    "downloadUrl": "https://openagent3.xyz/downloads/data-visualization-2",
    "agentUrl": "https://openagent3.xyz/skills/data-visualization-2/agent",
    "manifestUrl": "https://openagent3.xyz/skills/data-visualization-2/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/data-visualization-2/agent.md"
  }
}