add-chart
Renamed → /portaljs-add-chart. This alias will be removed next minor release.
Add a chart (line, bar, area, pie, or scatter) to a dataset's showcase in a PortalJS portal. Installs recharts, writes a reusable Chart component, and renders it in the showcase Views section.
> /plugin marketplace add datopian/portaljs > /plugin install portaljs@datopian-portaljs
How it fires
How this command gets triggered: by you, by Claude, or both.
/portaljs-add-chartContext preview
What this command does when you run it.
Add a chart (line, bar, area, pie, or scatter) to a dataset's showcase in a PortalJS portal. Installs recharts, writes a reusable Chart component, and renders it in the showcase Views section.
description: Add a chart (line, bar, area, pie, or scatter) to a dataset's showcase in a PortalJS portal. Installs recharts, writes a reusable Chart component, and renders it in the showcase Views section. allowed-tools: Read, Write, Edit, Bash
Add a visualization to a dataset's **showcase** in a `portaljs-catalog` portal. Installs `recharts` (added directly — **not** `@portaljs/components`), writes a reusable client-side `Chart` component into the portal's `components/`, and renders a `<Chart />` into the **Views** section of the showcase route `pages/[owner]/[slug].tsx` for the chosen dataset.
Use this after the dataset is registered in `datasets.json` (e.g. via `/portaljs-add-dataset`). The chart reads the same `/public/data/<file>` the showcase's `<Table />` already uses — no data is duplicated.
within a namespace. It must already be an entry in `datasets.json`.
or `imports,exports`).
**If the target dataset isn't specified, ask which one (by name/slug) — never dead-end with a missing-input error.**
Extract:
If the dataset (or X/Y) is missing, **ask** and wait. When the user doesn't know the slug, read `PORTAL_DIR/datasets.json` and list the available datasets (`name` → `slug`) so they can pick one:
To add a chart I need: 1. Which dataset? (slug — your catalog has: <name (slug)>, …) 2. X axis column (e.g. year) 3. Y axis column(s), comma-separated (e.g. population or imports,exports) 4. Chart type [line] (line|bar|area|pie|scatter) 5. Portal directory (Enter for current directory)
Validate `TYPE` is one of the five supported values. If not, tell the user and ask them to pick line, bar, area, pie, or scatter.
(if multiple namespaces share the slug, ask which `namespace`). Capture its `namespace`, `file`, and `format`.
may have meant a different one or need to run `/portaljs-add-dataset` first.
showcase route is `pages/[owner]/[slug].tsx`; the page rendered for this dataset is `/@<namespace>/<slug>`.
column wasn't found and list the available headers so they can correct it.
Note: column "COL" looks non-numeric — chart values are coerced with Number(); non-numeric cells render as gaps.
cd PORTAL_DIR && npm install recharts@^2.15.0
Do **not** install `@portaljs/components`. If the install fails, tell the user (check network and `package.json`) and retry.
Write `PORTAL_DIR/components/Chart.tsx` **only if it does not already exist** (idempotent — do not overwrite a customized component):
import React, { useEffect, useMemo, useState } from 'react'
import {
ResponsiveContainer,
LineChart, Line,
BarChart, Bar,
AreaChart, Area,
PieChart, Pie, Cell,
ScatterChart, Scatter,
XAxis, YAxis, ZAxis,
CartesianGrid, Tooltip, Legend,
} from 'recharts'
import { parseCsv } from './ui/parseCsv'
type Row = Record<string, string | number>
export interface ChartProps {
/** CSV file URL under /public, e.g. "/data/file.csv" */
url?: string
/** Pre-parsed rows (e.g. from an imported JSON array) */
data?: Row[]
type?: 'line' | 'bar' | 'area' | 'pie' | 'scatter'
/** X-axis / category column key */
x: string
/** One or more numeric column keys to plot */
y: string | string[]
height?: number
}
const PALETTE = ['#2563eb', '#16a34a', '#dc2626', '#d97706', '#7c3aed', '#0891b2', '#db2777', '#65a30d']
export function Chart({ url = '', data: initialData = [], type = 'line', x, y, height = 320 }: ChartProps) {
const yKeys = useMemo(() => (Array.isArray(y) ? y : [y]), [y])
const [raw, setRaw] = useState<Row[]>(initialData)
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
if (!url) {
setRaw(initialData)
return
}
setIsLoading(true)
setError(null)
fetch(url)
.then((r) => {
if (!r.ok) throw new Error(`HTTP ${r.status} — ${r.statusText}`)
return r.text()
})
.then((text) => setRaw(parseCsv(text).rows))
.catch((err: Error) => setError(err.message))
.finally(() => setIsLoading(false))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url, JSON.stringify(initialData)])
// Coerce y values to numbers; leave x untouched (categorical or numeric)
const rows = useMemo(
() =>
raw.map((row) => {
const out: Row = { [x]: ro🌀 AI-native framework for building data portals. Scaffold a full portal from a brief and load datasets in minutes with agentic skills — any backend (CKAN, GitHub, Frictionless).
Repo: datopian/portaljs
Renamed → /portaljs-add-chart. This alias will be removed next minor release.
Renamed → /portaljs-add-dataset. This alias will be removed next minor release.
Renamed → /portaljs-add-map. This alias will be removed next minor release.
Renamed → /portaljs-add-resource. This alias will be removed next minor release.
Migrate a whole ArcGIS Hub site (opendata.arcgis.com or a Hub Premium custom domain) into a PortalJS Arc portal end-to-end. Harvests the Hub /data.json…
Renamed → /portaljs-architect. This alias will be removed next minor release.