Chart Image

v2.6.35

Generate publication-quality chart images from data. Supports line, bar, area, point, histogram, candlestick, pie/donut, heatmap, multi-series, and stacked c...

15· 9.5k·62 current·65 all-time
byDanny Shmueli@dannyshmueli

Install

OpenClaw Prompt Flow

Install with OpenClaw

Best for remote or guided setup. Copy the exact prompt, then paste it into OpenClaw for dannyshmueli/chart-image.

Previewing Install & Setup.
Prompt PreviewInstall & Setup
Install the skill "Chart Image" (dannyshmueli/chart-image) from ClawHub.
Skill page: https://clawhub.ai/dannyshmueli/chart-image
Keep the work scoped to this skill only.
After install, inspect the skill metadata and help me finish setup.
Use only the metadata you can verify from ClawHub; do not invent missing requirements.
Ask before making any broader environment changes.

Command Line

CLI Commands

Use the direct CLI path if you want to install manually and keep every step visible.

OpenClaw CLI

Canonical install target

openclaw skills install dannyshmueli/chart-image

ClawHub CLI

Package manager switcher

npx clawhub@latest install chart-image
Security Scan
Capability signals
Crypto
These labels describe what authority the skill may exercise. They are separate from suspicious or malicious moderation verdicts.
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name/description (chart-image) align with included files and dependencies: scripts/chart.mjs implements chart generation using vega, vega-lite, and sharp (packages declared in package.json/package-lock.json). No unrelated credentials, binaries, or config paths are requested.
Instruction Scope
SKILL.md/CAPABILITY.md instruct the runtime to run `npm install` in the skill folder and then invoke `node scripts/chart.mjs` with JSON/CSV/stdin input. That scope is appropriate for chart generation. Caveats: examples show piping curl output into the script and passing JSON on the CLI — callers should avoid building shell commands with untrusted JSON/labels/paths (CAPABILITY.md explicitly warns about this). The code reads stdin and filesystem (expected for this tool) and writes image files to the given --output path.
Install Mechanism
This is an instruction-only skill with bundled package.json and package-lock.json; installation requires running `npm install` which fetches packages from the npm registry (vega, vega-lite, sharp and their prebuilt/binary packages). This is a common, expected install path but does pull code from public registries at install time (moderate risk compared with no-install skills). No arbitrary download URLs or shorteners are used.
Credentials
The skill requests no environment variables, no credentials, and no special config paths. The dependencies and CLI options are proportional to a chart/image generator.
Persistence & Privilege
Skill does not request always:true and does not modify other skills or system-wide settings. It runs as-needed and only writes output files under the provided --output path (normal for a CLI tool).
Assessment
This skill appears internally consistent and implements what it promises, but take the following precautions before installing or running it: - Run npm install in an isolated/sandboxed environment (container) the first time so packages from the npm registry can't access sensitive host state during install. - Inspect or pin package-lock.json and dependency versions if you require stronger supply-chain guarantees; sharp brings prebuilt binaries and optional libvips artifacts (licenses like LGPL are present for libvips components). - Avoid constructing shell commands by interpolating user-provided JSON, titles, or file paths; follow the CAPABILITY.md guidance and pass data via argv or trusted temporary files to prevent command-injection risks. - Be cautious with examples that pipe external URLs (curl | node chart.mjs): ensure the data source is trusted before accepting or embedding remote data. - Verify Node.js version compatibility in your environment (package-lock specifies engine ranges for some optional packages). If you need higher assurance about provenance, ask the publisher for a homepage or canonical repository (the registry metadata shows no homepage/source URL).

Like a lobster shell, security has layers — review code before you run it.

latestvk97738apvzs4gcp6ec25myth5s84hh6f
9.5kdownloads
15stars
15versions
Updated 2w ago
v2.6.35
MIT-0

Chart Image Generator

Generate PNG chart images from data using Vega-Lite. Perfect for headless server environments.

Why This Skill?

Built for Fly.io / VPS / Docker deployments:

  • No native compilation - Uses Sharp with prebuilt binaries (unlike canvas which requires build tools)
  • No Puppeteer/browser - Pure Node.js, no Chrome download, no headless browser overhead
  • Lightweight - ~15MB total dependencies vs 400MB+ for Puppeteer-based solutions
  • Fast cold starts - No browser spinup delay, generates charts in <500ms
  • Works offline - No external API calls (unlike QuickChart.io)

Setup (one-time)

cd /data/clawd/skills/chart-image/scripts && npm install

Quick Usage

node /data/clawd/skills/chart-image/scripts/chart.mjs \
  --type line \
  --data '[{"x":"10:00","y":25},{"x":"10:30","y":27},{"x":"11:00","y":31}]' \
  --title "Price Over Time" \
  --output chart.png

Chart Types

Line Chart (default)

node chart.mjs --type line --data '[{"x":"A","y":10},{"x":"B","y":15}]' --output line.png

Quantitative X-domain clamp

Useful when you want a fixed numeric or temporal window without editing Vega-Lite by hand:

node chart.mjs --type line \
  --data '[{"minute":0,"value":12},{"minute":1,"value":18},{"minute":2,"value":14},{"minute":3,"value":20}]' \
  --x-field minute --y-field value --x-type quantitative \
  --x-domain 0,2 --title "First 3 Minutes" \
  --output x-domain.png

Bar Chart

node chart.mjs --type bar --data '[{"x":"A","y":10},{"x":"B","y":15}]' --output bar.png

Area Chart

node chart.mjs --type area --data '[{"x":"A","y":10},{"x":"B","y":15}]' --output area.png

Histogram

Use this for numeric distributions instead of pre-binned bar charts:

node chart.mjs --type histogram \
  --data '[{"value":12},{"value":18},{"value":19},{"value":24},{"value":31}]' \
  --x-field value --x-title "Response Time (ms)" --y-title "Count" \
  --bins 8 --tick-min-step-y 1 --x-label-angle -30 \
  --output hist.png

Pie / Donut Chart

# Pie
node chart.mjs --type pie --data '[{"category":"A","value":30},{"category":"B","value":70}]' \
  --category-field category --y-field value --output pie.png

# Donut (with hole)
node chart.mjs --type donut --data '[{"category":"A","value":30},{"category":"B","value":70}]' \
  --category-field category --y-field value --output donut.png

Candlestick Chart (OHLC)

node chart.mjs --type candlestick \
  --data '[{"x":"Mon","open":100,"high":110,"low":95,"close":105}]' \
  --open-field open --high-field high --low-field low --close-field close \
  --title "Stock Price" --output candle.png

Heatmap

node chart.mjs --type heatmap \
  --data '[{"x":"Mon","y":"Week1","value":5},{"x":"Tue","y":"Week1","value":8}]' \
  --color-value-field value --color-scheme viridis \
  --y-label-overlap greedy \
  --title "Activity Heatmap" --output heatmap.png

Multi-Series Line Chart

Compare multiple trends on one chart:

node chart.mjs --type line --series-field "market" \
  --data '[{"x":"Jan","y":10,"market":"A"},{"x":"Jan","y":15,"market":"B"}]' \
  --title "Comparison" --output multi.png

Stacked Bar Chart

node chart.mjs --type bar --stacked --color-field "category" \
  --data '[{"x":"Mon","y":10,"category":"Work"},{"x":"Mon","y":5,"category":"Personal"}]' \
  --title "Hours by Category" --output stacked.png

Volume Overlay (Dual Y-axis)

Price line with volume bars:

node chart.mjs --type line --volume-field volume \
  --data '[{"x":"10:00","y":100,"volume":5000},{"x":"11:00","y":105,"volume":3000}]' \
  --title "Price + Volume" --output volume.png

Sparkline (mini inline chart)

node chart.mjs --sparkline --data '[{"x":"1","y":10},{"x":"2","y":15}]' --output spark.png

Sparklines are 80x20 by default, transparent, no axes.

Options Reference

Basic Options

OptionDescriptionDefault
--typeChart type: line, bar, area, point, histogram, pie, donut, candlestick, heatmapline
--dataJSON array of data points-
--outputOutput file pathchart.png
--titleChart title-
--widthWidth in pixels600
--heightHeight in pixels300

Axis Options

OptionDescriptionDefault
--x-fieldField name for X axisx
--y-fieldField name for Y axisy
--x-titleX axis labelfield name
--y-titleY axis labelfield name
--x-typeX axis type: ordinal, temporal, quantitativeordinal
--x-domainClamp/zoom the X scale with min,max bounds for quantitative or temporal chartsauto
--x-formatTemporal X axis label format (d3-time-format, e.g. %b %d, %H:%M)auto
--x-sortX axis order: ascending, descending, or none (preserve input order)auto
--series-order CSVExplicit series/category order for multi-series and stacked legends (e.g. Critical,High,Medium)data order
--x-label-limit PXMax pixel width for X axis labels before Vega truncates themauto
--y-label-limit PXMax pixel width for Y axis labels before Vega truncates themauto
--x-ticks NTarget X-axis tick count for dense or sparse chartsauto
--y-ticks NTarget primary/left Y-axis tick count for dense or sparse chartsauto
--bins NHistogram bin count (--type histogram only)Vega auto
--tick-min-step NMinimum step between ticks on quantitative axes (great for counts / whole-number charts)Vega auto
--tick-min-step-x NMinimum step between ticks on quantitative X axes onlyVega auto
--tick-min-step-y NMinimum step between ticks on quantitative Y axes onlyVega auto
--x-label-angle NRotate X-axis labels (for dense categories / timestamps)-45
--y-label-angle NRotate Y-axis labels (useful for horizontal bars / heatmaps)0 / Vega default
--x-label-overlap MODEForce Vega X-axis overlap handling (parity, greedy, true, false) for crowded labelsVega auto
--y-label-overlap MODEForce Vega Y-axis overlap handling (parity, greedy, true, false) for crowded labelsVega auto
--y2-ticks NTarget secondary/right Y-axis tick count for dual-axis and volume chartsauto
--y-domainY scale as "min,max"auto
--y-padAdd vertical padding as a fraction of range (e.g. 0.1 = 10%)0

Visual Options

OptionDescriptionDefault
--colorLine/bar color#e63946
--darkDark mode themefalse
--svgOutput SVG instead of PNGfalse
--font-familyCSS font-family string for chart text/legend/title themingHelvetica, Arial, sans-serif
--title-alignTitle alignment: start, middle, endstart
--title-size NTitle font size override in pxauto
--subtitle-size NSubtitle font size override in pxauto
--title-weight WTitle font weight override (normal, bold, 100-900)auto
--subtitle-weight WSubtitle font weight override (normal, bold, 100-900)auto
--title-colorTitle text color overridetheme text
--subtitle-colorSubtitle text color overridetheme grid
--grid-dash A,BDash pattern for gridlines (for example 4,2)solid

Font examples: "Inter, Helvetica, Arial, sans-serif", "Georgia, serif", "JetBrains Mono, Consolas, monospace" | --no-points | Hide point markers on line charts | false | | --line-width N | Set line thickness in pixels for line charts | 2 | | --point-size N | Set point marker size for line/point charts | 60 | | --bar-radius N | Round bar corners in pixels for bar-based charts | 0 | | --color-scheme | Vega color scheme (category10, viridis, etc.) | - | | --legend-columns N | Wrap legend entries into N columns for crowded multi-series/pie charts | auto | | --legend-label-limit PX | Max pixel width for legend labels before Vega truncates them | auto |

Alert/Monitor Options

OptionDescriptionDefault
--show-changeShow +/-% change annotation at last pointfalse
--focus-changeZoom Y-axis to 2x data rangefalse
--focus-recent NShow only last N data pointsall
--show-valuesLabel min/max peak pointsfalse
--last-valueLabel the final data point valuefalse

Multi-Series/Stacked Options

OptionDescriptionDefault
--series-fieldField for multi-series line charts-
--stackedEnable stacked bar modefalse
--color-fieldField for stack/color categories-

Candlestick Options

OptionDescriptionDefault
--open-fieldOHLC open fieldopen
--high-fieldOHLC high fieldhigh
--low-fieldOHLC low fieldlow
--close-fieldOHLC close fieldclose

Pie/Donut Options

OptionDescriptionDefault
--category-fieldField for pie slice categoriesx
--donutRender as donut (with center hole)false

Heatmap Options

OptionDescriptionDefault
--color-value-fieldField for heatmap intensityvalue
--y-category-fieldY axis category fieldy

Dual-Axis Options (General)

OptionDescriptionDefault
--y2-fieldSecond Y axis field (independent right axis)-
--y2-titleTitle for second Y axisfield name
--y2-colorColor for second series#60a5fa (dark) / #2563eb (light)
--y2-typeChart type for second axis: line, bar, arealine
--y2-formatRight-axis format: percent, dollar, compact, integer, decimal4, or d3-format stringauto

Example: Revenue bars (left) + Churn area (right):

node chart.mjs \
  --data '[{"month":"Jan","revenue":12000,"churn":4.2},...]' \
  --x-field month --y-field revenue --type bar \
  --y2-field churn --y2-type area --y2-color "#60a5fa" --y2-format ".1f" \
  --y-title "Revenue ($)" --y2-title "Churn (%)" \
  --x-sort none --dark --title "Revenue vs Churn"

Volume Overlay Options (Candlestick)

OptionDescriptionDefault
--volume-fieldField for volume bars (enables dual-axis)-
--volume-colorColor for volume bars#4a5568

Formatting Options

OptionDescriptionDefault
--y-formatY axis format: percent, dollar, compact, decimal4, integer, scientific, or d3-format stringauto
--subtitleSubtitle text below chart title-
--hlineHorizontal reference line: "value" or "value,color" or "value,color,label" (repeatable)-

Annotation Options

OptionDescriptionDefault
--annotationStatic text annotation-
--annotationsJSON array of event markers-

Alert-Style Chart (recommended for monitors)

node chart.mjs --type line --data '[...]' \
  --title "Iran Strike Odds (48h)" \
  --show-change --focus-change --show-values --dark \
  --output alert.png

For recent action only:

node chart.mjs --type line --data '[hourly data...]' \
  --focus-recent 4 --show-change --focus-change --dark \
  --output recent.png

Timeline Annotations

Mark events on the chart:

node chart.mjs --type line --data '[...]' \
  --annotations '[{"x":"14:00","label":"News broke"},{"x":"16:30","label":"Press conf"}]' \
  --output annotated.png

Temporal X-Axis

For proper time series with date gaps:

node chart.mjs --type line --x-type temporal \
  --data '[{"x":"2026-01-01","y":10},{"x":"2026-01-15","y":20}]' \
  --output temporal.png

Use --x-type temporal when X values are ISO dates and you want spacing to reflect actual time gaps (not evenly spaced).

Y-Axis Formatting

Format axis values for readability:

# Dollar amounts
node chart.mjs --data '[...]' --y-format dollar --output revenue.png
# → $1,234.56

# Percentages (values as decimals 0-1)
node chart.mjs --data '[...]' --y-format percent --output rates.png
# → 45.2%

# Compact large numbers
node chart.mjs --data '[...]' --y-format compact --output users.png
# → 1.2K, 3.4M

# Crypto prices (4 decimal places)
node chart.mjs --data '[...]' --y-format decimal4 --output molt.png
# → 0.0004

# Custom d3-format string
node chart.mjs --data '[...]' --y-format ',.3f' --output custom.png

Available shortcuts: percent, dollar/usd, compact, integer, decimal2, decimal4, scientific

Chart Subtitle

Add context below the title:

node chart.mjs --title "MOLT Price" --subtitle "20,668 MOLT held" --data '[...]' --output molt.png

--subtitle works across standard charts plus pie/donut, heatmap, candlestick, stacked, multi-series, volume-overlay, and dual-axis layouts.

Theme Selection

Use --dark for dark mode. Auto-select based on time:

  • Night (20:00-07:00 local): --dark
  • Day (07:00-20:00 local): light mode (default)

Social Size Presets

Use --output-size when the chart is meant for a specific surface:

# Bluesky / OG-style landscape post
node chart.mjs --type line --data '[...]' --output-size bluesky --output bluesky-chart.png

# Instagram / Threads portrait post
node chart.mjs --type line --data '[...]' --output-size portrait --output portrait-chart.png

Available presets include twitter, discord, slack, linkedin, bluesky (bsky alias), youtube, instagram, portrait, story, thumbnail, wide, and square.

Piping Data

echo '[{"x":"A","y":1},{"x":"B","y":2}]' | node chart.mjs --output out.png

Custom Vega-Lite Spec

For advanced charts:

node chart.mjs --spec my-spec.json --output custom.png

⚠️ IMPORTANT: Always Send the Image!

After generating a chart, always send it back to the user's channel. Don't just save to a file and describe it — the whole point is the visual.

# 1. Generate the chart
node chart.mjs --type line --data '...' --output /data/clawd/tmp/my-chart.png

# 2. Send it! Use message tool with filePath:
#    action=send, target=<channel_id>, filePath=/data/clawd/tmp/my-chart.png

Tips:

  • Save to /data/clawd/tmp/ (persistent) not /tmp/ (may get cleaned)
  • Use action=send with filePaththread-reply does NOT support file attachments
  • Include a brief caption in the message text
  • Auto-use --dark between 20:00-07:00 Israel time

Updated: 2026-04-06 - added --y-label-angle for crowded categorical/heatmap charts and documented per-axis label rotation; version bumped to 2.6.33

Comments

Loading comments...