Generate interactive charts & maps from CSV data using plotly.
viz smartcreates a "neuro-symbolic" dashboard/visual data dictionary, picking appropriate visualizations using the dataset's statistics, frequency distributions, data dictionary & optional LLM metadata inferencing/classification, with automatic geocoding enrichment. Outputs self-contained, interactive HTML or static PNG/SVG/PDF/JPEG/WebP with theviz_staticfeature. (Gallery)
Table of Contents | Source: src/cmd/viz.rs | 🪄📇🏎️👆🤖🌐🌎
Description | Examples | Usage | Viz Options | Map Options | Geo Options | Choropleth Options | Smart Options | Common Options
Description ↩
Generate charts/maps from CSV data using the plotly charting library.
Produces a self-contained, interactive HTML chart (the plotly.js runtime is embedded,
so charts work offline; map basemaps fetch their tiles over the network at view time
unless the white-bg style is used). Set the QSV_VIZ_CDN environment variable to load
plotly.js from its CDN instead, shrinking the page by ~1.9MB at the cost of needing
network access to view it. By default the embedded plotly.js is gzip-compressed
(~1.9MB vs ~4.8MB) and inflated in-browser, which requires a browser with
DecompressionStream support (Chrome/Edge 80+, Firefox 113+, or Safari 16.4+);
set QSV_VIZ_NO_COMPRESS for plain-text, uncompressed HTML that also works on
older browsers.
Titles and labels are rendered as plain text - LaTeX (e.g. $\alpha$) is not typeset.
With a qsv build that includes the viz_static feature, charts can also be exported as
static PNG/SVG/PDF/JPEG/WebP images (this requires a Chromium/Firefox browser at
runtime - a webdriver is auto-managed by plotly).
The output format is inferred from the --output file extension (.html is the default). Interactive HTML is written to stdout when --output is not given; image formats always require --output. Use --open to view the result in your default browser/viewer.
Progress is shown on stderr by default: a spinner with per-phase status messages (loading statistics, inferring the data dictionary, computing correlations, rendering, etc.). It is auto-hidden when stderr is not a terminal (e.g. piped or redirected). Set the QSV_PROGRESSBAR environment variable to a falsy value (0/false/off) to disable it.
Chart types (subcommands):
smart Auto-dashboard. Picks an appropriate chart per column from the
dataset's statistics & frequency distribution (no --x/--y needed).
bar Bar chart. --x = category column, --y = value column.
line Line chart. --x = x column, --y = y column.
scatter Scatter plot. --x = x column, --y = y column.
scatter3d 3D scatter plot. --x, --y, --z = three numeric columns.
histogram Distribution. --x = numeric column to bin.
box Box plot. --y = value column, optional --x = group column.
violin Violin plot: a box plot plus a KDE density curve revealing the
distribution's shape (modes, shoulders). Same inputs as box
(--y = value column, optional --x = group column).
pie Proportions. --x = label column, optional --y = value column.
funnel Stage-by-stage drop-off. --x = stage column, optional --y = value
column (counts stage occurrences when omitted). Stages keep the
order they first appear in the file, so the rows define the
pipeline; plotly labels each band with its conversion from the
previous stage.
heatmap Color grid. Correlation matrix of numeric columns (default; an
optional column subset via --cols), or a category x category pivot
with --x/--y/--z.
contour 2D density contour of two numeric columns (--x and --y), binned
into a grid (--bins controls the grid resolution).
candlestick Financial OHLC. --x = date column, plus --ohlc-open/--high/--low/--close.
ohlc Financial OHLC bars (same inputs as candlestick).
sankey Flow diagram. --source, --target, optional --value column.
radar Polar/radar chart of numeric --cols, optional --series per trace.
treemap Part-to-whole hierarchy as nested tiles. --cols = 2+ dimension
columns (levels), optional --value and --agg.
sunburst Part-to-whole hierarchy as concentric rings (same inputs as
treemap). Better for deeper hierarchies.
icicle Part-to-whole hierarchy as stacked bars per level (same inputs as
treemap). Level-aligned; good for deep, wide hierarchies.
splom Scatter-plot matrix: every pair of numeric --cols plotted against
each other in a grid, with each column's distribution on the
diagonal. Good for spotting correlations across many numeric
columns at once (default: all numeric columns).
parcats Parallel categories: ribbons showing how rows flow across the
categorical --cols (best with 3-4). Complements sankey (which
takes 2 columns) for higher-dimensional categorical relationships.
map Geographic point map (or --density heatmap) on tile basemaps.
Pick the coordinate columns with the lat/lon options below.
geo Geographic point map on a projection basemap (coastlines/land/
countries; no tiles, no token). Uses the same lat/lon options
as `map`, plus --projection. Good for global/country-scale data.
choropleth Filled-region map: color whole regions (countries, US states, or
custom GeoJSON areas) by a value. --locations names the region-code
column, --value/--agg the measure (row counts if omitted). Defaults
to a token-free projection basemap; --map switches to MapLibre tiles.
qsv viz smart builds a one-page dashboard of subplots, reusing qsv's stats and
frequency caches (the first run computes & caches stats; later runs are fast). It
auto-picks panels, so no --x/--y is needed:
Per-column panels (flow in the grid below the overview rows, see --grid-cols):
- continuous numeric -> box plot (quartiles from the stats cache; sample points overlaid by a size heuristic, see --box-points)
- low-cardinality / boolean -> frequency bar chart
- ID-like (near-unique) and all-empty columns are skipped
Overview panels (each leads the dashboard on its own full-width row):
- KPI overview row (leads the dashboard when the dataset has headline numeric
measures): a strip of "big number" tiles, one per headline measure (summed
for extensive quantities, averaged for intensive ones). A measure tile
becomes a GAUGE when the dictionary supplies a validated
x-qsv.gauge_rangethat contains the value, and gains a "vs target" DELTA when it supplies anx-qsv.target(see --dictionary). Omitted for image exports and for datasets with no headline measure. (Overall dataset completeness - the share of non-empty cells - is a quiet "Completeness:" line in the header metadata table, not a KPI tile.) - pipeline funnel, when the dictionary DECLARES one (see --dictionary). Which
columns are process stages, and in which direction, is semantics rather than
a statistic - no column-name vocabulary settles it and no statistic does
either - so a funnel is drawn ONLY from an explicit declaration, never
guessed. Both encodings are supported: stages held in separate measure
columns, and stages held as values of one category column. Costs one extra
data pass over the declared stages only.
Stage order is the declared order and is never re-sorted by size. For the
column encoding, row-wise containment (does each stage nest inside the one
before it?) is MEASURED and disclosed in the subtitle, but never refuses the
panel: a pipeline whose stages overrun is a finding to name, not a reason to
show nothing. Totals sum over the rows complete across every declared stage,
so they do NOT match
stats.sum; the subtitle always discloses that denominator. See also the standaloneqsv viz funnelchart type, which takes its stage order from the file and needs no dictionary. - correlation heatmap, when 2+ continuous numeric columns exist (one extra data pass for Pearson correlations). If the strongest pair is at least moderately correlated, a drill-down is added beside it: a scatter (or a 2D density contour for large, overplotting datasets); with 3+ numeric columns, a 3D scatter of the strongest triple is added too.
- time-series line, when an auto-detected date/datetime column and a continuous numeric column both exist.
- geographic map, when a latitude/longitude pair is detected:
- HTML uses a MapLibre tile map for a local extent, or an offline ScatterGeo projection world-overview for continental/global data.
- static image export uses an offline ScatterGeo fit to the data extent (US-spanning data uses albers-usa); tile maps and 3D panels stay HTML-only, as tile maps need network tiles.
- geographic outliers (points beyond the Tukey far-out fence of distances from the cluster centroid) get a distinct marker and are excluded from the spatial extent; the map zooms to the core, with a dotted no-fill box marking the full extent and (in HTML) Core/Full extent buttons. Outliers within the core's jurisdiction don't trigger the extent call-out.
- with the
geocodefeature, the core extent (4 corners + center) is reverse-geocoded against the local Geonames index and drawn as a labeled bounding box with a location summary (e.g. "New York & New Jersey, United States"); outliers are called out with their count and jurisdiction. HTML points reveal city/state/country on hover (static exports omit it). The first run may download the index (~13MB, cached in ~/.qsv-cache); offline, the map renders without the overlay. - extents spanning the antimeridian (>180 degrees of longitude) are skipped.
Examples ↩
Auto-dashboard for a dataset, opened in the browser
qsv viz smart data.csv --openAuto-dashboard, at most 6 panels in a 3-column grid, top-5 categories per bar
qsv viz smart data.csv --max-charts 6 --grid-cols 3 --limit 5 -o dashboard.htmlBar chart of fruit prices, opened in the browser
qsv viz bar fruits.csv --x Fruit --y Price --title "Fruit prices" --openAggregate (sum) sales by region into a bar chart
qsv viz bar sales.csv --x region --y amount --agg sum -o sales.htmlScatter plot with a separate series (trace) per category
qsv viz scatter data.csv --x age --y income --series gender -o scatter.htmlBubble scatter: marker size by population, marker color by a numeric score
qsv viz scatter data.csv --x gdp --y life_exp --size population --color score -o bubble.htmlHistogram of a numeric column with 30 bins
qsv viz histogram data.csv --x value --bins 30 -o hist.htmlBox plot of a value column grouped by a category, exported to PNG (needs viz_static)
qsv viz box data.csv --y measurement --x group -o box.pngBox plot with every sample point overlaid (jittered) instead of just the outliers
qsv viz box data.csv --y measurement --box-points all -o box.htmlViolin plot (KDE density curve + inner box) of a value column grouped by a category
qsv viz violin data.csv --y measurement --x group -o violin.htmlPie chart of category proportions (counts), as a donut
qsv viz pie data.csv --x category --donut -o pie.htmlFunnel of a pipeline whose stages are ROWS (stage column + amount column)
qsv viz funnel pipeline.csv --x stage --y amount -o funnel.htmlCorrelation heatmap over all numeric columns
qsv viz heatmap data.csv -o corr.htmlHeatmap pivot: average value per (region x product)
qsv viz heatmap sales.csv --x region --y product --z amount -o pivot.htmlCandlestick chart from a date column and OHLC price columns
qsv viz candlestick prices.csv --x date --ohlc-open open --high high --low low --close close -o ohlc.htmlSankey flow diagram of source -> target weighted by value
qsv viz sankey flows.csv --source from --target to --value weight -o sankey.htmlRadar chart comparing numeric metrics, one trace per team
qsv viz radar teams.csv --cols speed,power,range,accuracy --series team -o radar.htmlPoint map of earthquakes, marker color by magnitude and size by depth
qsv viz map quakes.csv --lat lat --lon lon --color magnitude --size depth -o map.htmlDensity heatmap of the same points, on a light Carto basemap
qsv viz map quakes.csv --lat lat --lon lon --density --style carto-positron -o heat.html3D scatter of three numeric columns, colored by a fourth
qsv viz scatter3d data.csv --x length --y width --z height --color weight -o scatter3d.html2D density contour of two numeric columns with a 40x40 grid
qsv viz contour data.csv --x height --y weight --bins 40 -o contour.htmlProjection map of earthquakes (token-free), marker color by magnitude
qsv viz geo quakes.csv --lat lat --lon lon --color magnitude --projection natural-earth -o geo.htmlTreemap of part-to-whole sales by region then category, sized by amount
qsv viz treemap sales.csv --cols region,category --value amount --agg sum -o treemap.htmlSunburst of a deep 3-level web-traffic hierarchy, sized by row count
qsv viz sunburst web.csv --cols source,campaign,landing_page -o sunburst.htmlChoropleth coloring countries (ISO-3 codes) by a summed measure
qsv viz choropleth gdp.csv --locations iso3 --value gdp --agg sum -o choropleth.htmlUS-state choropleth of row counts per state (2-letter state codes)
qsv viz choropleth orders.csv --locations state --location-mode usa-states -o states.htmlCustom GeoJSON regions on a MapLibre basemap, matched by a feature id
qsv viz choropleth counties.csv --locations fips --value pop --map --geojson counties.json --feature-id-key id -o counties.htmlReverse-geocode lat/lon points to ISO-3 codes, then count per country (needs geocode feature)
qsv viz choropleth stops.csv --geocode --lat lat --lon lon -o by_country.htmlPoint-in-polygon: bin lat/lon points into custom GeoJSON regions by count (no geocode)
qsv viz choropleth quakes.csv --lat lat --lon lon --geojson prefectures.geojson --feature-id-key properties.id -o by_pref.htmlFor more examples, see tests.
See also https://github.com/dathere/qsv/wiki/Visualization
Usage ↩
qsv viz smart [options] <input>
qsv viz bar [options] <input>
qsv viz line [options] <input>
qsv viz scatter [options] <input>
qsv viz scatter3d [options] <input>
qsv viz histogram [options] <input>
qsv viz box [options] <input>
qsv viz violin [options] <input>
qsv viz pie [options] <input>
qsv viz funnel [options] <input>
qsv viz heatmap [options] <input>
qsv viz contour [options] <input>
qsv viz candlestick [options] <input>
qsv viz ohlc [options] <input>
qsv viz sankey [options] <input>
qsv viz radar [options] <input>
qsv viz map [options] <input>
qsv viz geo [options] <input>
qsv viz choropleth [options] <input>
qsv viz treemap [options] <input>
qsv viz sunburst [options] <input>
qsv viz icicle [options] <input>
qsv viz splom [options] <input>
qsv viz parcats [options] <input>
qsv viz --helpViz Options ↩
| Option | Type | Description | Default |
|---|---|---|---|
‑x,‑‑x |
string | Column for the x-axis / category / bin / group. | |
‑y,‑‑y |
string | Column for the y-axis / value. | |
‑z,‑‑z |
string | The z column: a heatmap pivot value (with --x and --y), or the third numeric axis for scatter3d. | |
‑‑cols |
string | Columns to use. For heatmap: numeric columns for the correlation matrix (default: all numeric). For radar: the numeric axes to plot. For treemap/sunburst/icicle: the categorical dimensions that form the hierarchy levels, outermost first (e.g. region,category,subcategory). For splom: the numeric columns to cross-plot (default: all numeric). For parcats: the categorical dimensions to flow across (best with 3-4). | |
‑‑series |
string | Column to split into multiple series (one trace per distinct value). Applies to bar, line, scatter, scatter3d, radar, map and geo. | |
‑‑color |
string | For scatter/scatter3d/map/geo: a numeric column to encode as marker color (a continuous colorscale with a colorbar). For categorical coloring, use the --series option instead. Cannot be combined with --series. In map density mode, this column is the heatmap weight. | |
‑‑size |
string | For scatter/scatter3d/map/geo: a numeric column to encode as marker size, producing a bubble chart (values are rescaled to a readable pixel range). Cannot be combined with --series. In map density mode, this column is the heatmap weight. | |
‑‑donut |
flag | Render a pie chart as a donut (with a center hole). | |
‑‑ohlc‑open |
string | Open-price column for candlestick/ohlc charts. | |
‑‑high |
string | High-price column for candlestick/ohlc charts. | |
‑‑low |
string | Low-price column for candlestick/ohlc charts. | |
‑‑close |
string | Close-price column for candlestick/ohlc charts. | |
‑‑source |
string | Source node column for a sankey diagram. | |
‑‑target |
string | Target node column for a sankey diagram. | |
‑‑value |
string | Flow value column for a sankey diagram. When omitted, each row counts as a flow of 1. For treemap/sunburst/icicle: a numeric measure summed per sector (when omitted, each row counts as 1). | |
‑‑sankey‑value‑order |
flag | Order sankey nodes by total flow (largest at the top of each column). By DEFAULT nodes use plotly's crossing-minimizing "snap" order, which packs the diagram more compactly; this opts into the flow-ranked initial ordering instead. Either way the rendered chart carries an on-screen "node order" button to flip between the two layouts, and link ribbons are always colored by their source node. Applies to the sankey chart and the smart dashboard flow panel. |
|
‑‑bins |
integer | Number of bins. For histogram: bins along the x-axis (default: auto). For contour: the per-axis resolution of the density grid (default: 20). | |
‑‑agg |
string | For bar/line, aggregate the y values when the x value repeats. One of: sum, mean, count, min, max. For treemap/sunburst/icicle, only additive aggregations apply: count (default) or sum (requires --value). | |
‑‑box‑points |
string | Which sample points to draw alongside a box. Reading the raw values lets plotly render true Tukey whiskers (1.5*IQR) with the points beyond the fences as outliers. One of: outliers (only the outliers), all (every point, jittered), suspected (mark suspected outliers), none (no points, but still real Tukey whiskers). For viz box the default is outliers. For viz smart this flag OVERRIDES the default size-based heuristic, which overlays all points on a column with few non-null values (<=1,000) — unless the dashboard has more than 8 panels, where all-points cells turn to noise, so the overlay drops to outliers-only — and only the outliers for a medium one (<=10,000 values). Above that, a column that HAS outliers shows them as points on a precomputed quartile box (a single pass collects only the out-of-fence values, capped); a column with no outliers stays a fast cache-only quartile summary with no data re-scan. An explicit mode is applied to every box panel (one batched pass to read the values), except none, which keeps the cache-only box for BOX panels. A smart violin panel still renders under none, just with no sample points — its KDE needs the values anyway; combine with the violin option's off mode for the cache-only escape hatch. The same modes also pick the sample points drawn beside a violin, for viz violin and for the violin panels of viz smart — though a smart violin panel skips the size-based all upgrade (its KDE silhouette already shows the distribution) and overlays only the outliers unless an explicit mode is given. |
Map Options ↩
| Option | Type | Description | Default |
|---|---|---|---|
‑‑lat |
string | Latitude column for a map (decimal degrees, -90 to 90). | |
‑‑lon |
string | Longitude column for a map (decimal degrees, -180 to 180). | |
‑‑text |
string | Column whose value labels each point on hover. | |
‑‑density |
flag | Render a density heatmap (DensityMap) instead of points. Weighted by the --color or --size column when given, else by a uniform weight. Cannot be combined with --series. | |
‑‑style |
string | MapLibre basemap style (all render without an access token): open-street-map (the default), carto-positron, carto-darkmatter, carto-voyager, white-bg, basic, streets, outdoors, light, dark, satellite, satellite-streets. The three carto styles also have label-free "-nolabels" variants (e.g. carto-positron-nolabels) that keep basemap place names from competing with a dense data overlay. | open-street-map |
Geo Options ↩
| Option | Type | Description | Default |
|---|---|---|---|
‑‑projection |
string | Map projection for viz geo. One of: natural-earth (the default), mercator, orthographic, equirectangular, albers-usa, robinson, winkel-tripel, mollweide, hammer, azimuthal-equal-area. viz geo also reuses the lat, lon, text, color, size and series options from map. |
natural-earth |
Choropleth Options ↩
| Option | Type | Description | Default |
|---|---|---|---|
‑‑locations |
string | Column holding the region key for each row (an ISO-3 country code, a 2-letter US state code, a country name, or a GeoJSON feature id, per --location-mode). With --geocode, this instead names a place-name column to forward-geocode into region codes. | |
‑‑location‑mode |
string | How --locations values are matched to regions. One of: iso3 (the default, ISO-3166-1 alpha-3 country codes), usa-states (2-letter US state codes), country-names (full country names), geojson-id (match a --geojson feature id). | iso3 |
‑‑color‑scale |
string | Colorscale for the region fill. One of: viridis (the default), cividis, greys, greens, blues, reds, ylgnbu, ylorrd, bluered, rdbu, portland, electric, jet, hot, blackbody, earth, picnic, rainbow. | viridis |
‑‑map |
flag | Render on a token-free MapLibre tile basemap (a ChoroplethMap) instead of the default projection basemap. Requires --geojson; feature-id-key defaults to id. Reuses --style for the basemap. | |
‑‑geojson |
string | Custom region polygons as a local file path or an http(s) URL to a GeoJSON FeatureCollection. May also be a shortcut name defined in the QSV_GEOJSON_SHORTCUTS env var (a JSON map of name to {path, id}); the shortcut's id sets --feature-id-key when you don't pass one. The source is validated up front. Required for --map, and for the geojson-id location mode. Also enables point-in-polygon binning: with --lat/--lon (and without --geocode), each row's point is binned into the region whose polygon contains it (exact, no geocoding) and colored by --value/--agg or counts. In viz smart, it also overlays the region boundaries on the map, labelling each with its --feature-name-key value (falling back to its id) — as on-map text on the projection/static map, or as a centroid hover marker on the interactive tile map (which culls on-map text). Labels are omitted above 60 regions. |
|
‑‑feature‑id‑key |
string | Property path in each GeoJSON feature whose value matches an entry in the locations column, or that labels each binned region (e.g. id, properties.fips). | id |
‑‑feature‑name‑key |
string | GeoJSON property path whose value is shown as the human-readable region label in choropleth hover (e.g. properties.name). When omitted, common name keys are auto-detected; falls back to the feature id when absent. | |
‑‑geocode |
flag | Derive the region codes by reusing qsv's geocode engine (needs a build with the geocode feature). Either reverse-geocode the lat/lon points, or forward-geocode the locations name column. Only valid with location modes iso3 or usa-states. viz choropleth also reuses --value, --agg, --style and the lat/lon options. |
|
‑‑no‑snap |
flag | For point-in-polygon binning (lat/lon points binned into a custom GeoJSON without geocoding): do not snap at all — drop every point that falls outside every region. By default an outside point instead snaps to its nearest region when within the snap-distance limit (see --snap-max-dist). Applies to both the viz choropleth command and the viz smart GeoJSON choropleth panel. A stderr note reports coverage either way; each snapping region's hover tallies the points it absorbed from outside, and snapped or dropped points are reported in a note beneath the map (or in the smart panel's title). |
|
‑‑snap‑max‑dist |
float | For point-in-polygon binning: the farthest (in km) an outside point may snap to a region's boundary; points with no region within this distance are dropped. Distance is an equirectangular km approximation. When omitted, the cap is auto-derived from the GeoJSON's median region size (10% of the median bbox diagonal) and the lat/lon coordinate precision (coarse, few-decimal coordinates raise the cap to cover their quantization error), clamped to 0.1-100 km; a fixed 10 km is used only when neither signal is available. Applies to both the viz choropleth command and the viz smart GeoJSON choropleth panel; the coverage notes state the cap applied and how it was derived. Pass a large value for effectively unbounded snapping; cannot be combined with --no-snap. |
Smart Options ↩
| Option | Type | Description | Default |
|---|---|---|---|
‑‑max‑charts |
integer | Maximum number of panels in the dashboard. 0 (the default) means auto: draw every eligible column (up to 64), for both HTML and static image export (png/svg/pdf/...). Up to 8 cartesian panels render as one typed subplot grid; beyond 8, HTML switches to an inline-div grid of independent plots, and static image export uses domain-positioned axes to fit them in one image. Set a positive to cap the panel count instead. Eligible columns beyond the cap are reported but not drawn. | 0 |
‑‑grid‑cols |
integer | Number of columns in the dashboard grid for the per-column distribution panels. Overview panels (map/geo, correlation, time-series) always span the full width. | 2 |
‑‑heatmap‑density |
integer | For the viz smart map panel: at or above mappable points, draw the core as a density heatmap (DensityMap) instead of markers. The heatmap keeps per-point hover (coordinates, plus the point's label). Defaults to 0 (disabled): dense point maps instead open as individual points with an in-map "Clusters/Points" toggle (collapse the dense areas into interactive count bubbles on demand) rather than aggregating into a static heat surface. Set a positive to opt back into the heatmap above that point count. |
0 |
‑‑cluster |
string | For the viz smart map panel: whether to offer an in-map "Clusters/Points" toggle that collapses dense points into native MapLibre count bubbles (which expand back into individual, hoverable points on zoom-in). Hovering a bubble shows its point count; clicking it zooms to where that cluster breaks apart. The map always OPENS as individual points; the toggle switches clustering on. One of: auto, on, off. "auto" (the default) offers the toggle for a plain-marker core (no density heatmap, no bubble-size measure) once it reaches 1,000 points. "on" offers it whenever the core draws as markers, regardless of point count or a bubble-size measure. "off" omits the toggle, so points are always drawn plainly. Only affects smart. |
auto |
‑‑photos |
flag | For the viz smart map panel: when a column holds image URLs (detected from the stats cache - an http(s) value ending in a common image extension), embed each point's image URL so that dwelling on a map point for 2 seconds opens that row's photo in a small preview card beside the pointer (arrow keys page through a row with several photos; Escape dismisses the card). Points that have photos say so in their hover label. When the image host allows cross-origin reads, fetched images are cached in the browser's IndexedDB, so re-dwelling a point or reloading the page serves them locally; otherwise the preview falls back to a normal image load served by the ordinary browser cache. OFF by default, and deliberately so: images load from whatever third-party host the DATA names, so enabling this makes everyone who opens the dashboard request those URLs directly (revealing their IP to that host). Nothing is fetched until a viewer dwells. Embedding every mapped point's URLs also grows the HTML. Applies to HTML output only - static image exports (PNG/SVG/PDF) are unaffected - and only on the tile-basemap map panel. Only affects smart. |
|
‑‑limit |
integer | Top-N categories per frequency bar chart. | 10 |
‑‑no‑nulls |
flag | Omit the "(NULL)" bar (empty cells) from frequency bar charts. By default viz smart shows a "(NULL)" bar, like qsv frequency. |
|
‑‑no‑other |
flag | Omit the "Other (N)" aggregate bar from frequency bar charts. It collects the categories beyond --limit (N = how many distinct categories were rolled up) and is shown by default. When just ONE category is left over, it is charted under its own name instead of as an opaque "Other (1)" bar. | |
‑‑smarter |
flag | Before building the dashboard, run qsv moarstats --advanced to enrich the stats cache with distribution-shape statistics (bimodality, entropy, skewness, outlier share, Gini). This unlocks histograms for bimodal columns, frequency bars for concentrated high-cardinality columns, skew/outlier hints on box panels, and Lorenz curves for the most unequal additive measures (high Gini). Costs one extra pass over the data and writes .stats.csv, its sidecars, and an .idx index (like running qsv moarstats manually). On geocode-enabled builds it also enriches map point hovers with the US FIPS code and annotates the spatial-extent summary with the country's continent; the county is always shown in map hovers, with or without --smarter. Only affects smart. Applied only with default parsing; inputs using --no-headers or a custom --delimiter fall back to the standard dashboard. |
|
‑‑hierarchy‑style |
string | For smart, the chart used for the categorical part-to-whole hierarchy panel (built when 2+ low-cardinality dimensions exist). One of: auto (default), treemap, sunburst, icicle. auto follows best practice — a treemap for a shallow 2-level hierarchy (accurate size comparison) and a sunburst for a deep 3-level one (parent child structure); icicle is an opt-in level-aligned alternative. Only affects smart. |
|
‑‑dictionary |
string | Use a describegpt Data Dictionary to guide panel selection from each field's semantic role/concept (falling back to its content type) instead of relying on column statistics alone: dimensions and numeric codes (ward, census_tract, zone) become bars, measures get box/correlation/trend panels, date/datetime columns feed the time-series panel (not noisy frequency bars), identifiers / PII / free-text are skipped, and lat/lon feed the map. Field labels are shown as panel subtitles beneath the field-name titles. Columns the dictionary cannot classify still use the statistical heuristic. is one of: "infer" to run describegpt on the input now (with description, infer-content-type, two-pass and jsonschema output; requires an LLM configured) and use its output; or a path to an existing describegpt dictionary file (jsonschema or json). With "infer", the generated dictionary is saved beside the input as .schema.json so you can fine-tune it; if that file already exists, it is reused as-is (skipping the LLM) - edit it to fine-tune, or delete it to force a fresh re-infer. Generation/read failures soft-fall back to the stats-only dashboard. The dictionary also drives the KPI overview row via two optional per-field hints in a property's "x-qsv" object (edit them in the saved schema to fine-tune). A "gauge_range" of [min, max] on a continuous numeric measure renders its KPI tile as a GAUGE on that canonical scale (e.g. [0,1] for a ratio, [0,100] for a percent); qsv keeps it only when the observed data lies within the range, so a mis-scaled range can't draw a misleading dial, and "infer" emits it for canonical-scale measures. A "target" number on a measure renders a "vs target" DELTA against that goal (value minus target) - a GOAL you supply, never a fabricated prior-period baseline, so "infer" never emits it; hand-author it. The dictionary is also the ONLY source of the pipeline funnel panel, declared in the dataset-level "x-qsv" object as a "relationships" entry with "kind": "pipeline". Two encodings, both hand-editable: stages as COLUMNS - "members" lists the stage columns in process order, WIDEST/UPSTREAM FIRST (note this is the opposite direction from a "kind":"ordered" group, which ascends), e.g. {"kind":"pipeline", "members":["planned_amt","committed_amt","spent_amt"]} stages as ROW VALUES - "stage_column" names the category column, "stages" lists its values in process order, and an optional "value_column" names the measure to sum per stage (omit it to count rows), e.g. {"kind":"pipeline","members":["stage","revenue"], "stage_column":"stage", "stages":["Impression","Click","Lead","Conversion"], "value_column":"revenue"} Declared order is authoritative and is never re-sorted by size, so a stage that outruns its predecessor stays visible instead of being quietly reordered away. A declaration naming a missing column, or a stage that is an average/rate rather than a summable amount, is skipped with a note rather than erroring. Only affects smart. |
|
‑‑dictionary‑context |
string | Path to a file with extra context about the dataset (a glossary, README, data dictionary, PDF, etc.) forwarded to describegpt as --context-file when --dictionary infer generates the dictionary. Better context yields better role/concept/label/grain tags, hence a better dashboard. Ignored unless --dictionary infer is used (it does not apply when reading an existing dictionary file). Only affects smart. |
|
‑‑dict‑info |
flag | When a usable Data Dictionary is available (per --dictionary), add a "Data Dictionary" link beneath the dashboard title and an info icon on each panel title: hovering shows that column's dictionary description; clicking opens a human-friendly rendering of the dictionary in a side drawer NEXT TO the plots (embedded in the dashboard file - no extra file is written), scrolled to and highlighting that column's entry. The drawer is open by default on load and can be dismissed with its close button or Esc. The dictionary page carries a role-tinted table of contents and per-column "View chart" links back to the panels, plus a row of download buttons: the dictionary itself as JSON Schema, the frequency counts the dashboard actually charted, and every generated sidecar this run read (the stats cache and its metadata, the frequency cache when it was reused, and the bivariate stats CSV when freshly written). A sidecar qsv wrote but viz never read - the human-readable .stats.csv - is NOT offered, since nothing can show it describes the same computation the dashboard used. Every file is BUNDLED into the HTML, so anyone you send the dashboard to can download them with no access to your machine; absolute local paths are stripped from the embedded metadata so sharing a dashboard doesn't disclose your directory layout. Sidecars over 4 MB are skipped with a note. The drawer's popout button opens the same document in its own browser tab instead (needs a browser that allows user-initiated pop-ups). HTML output only; ignored with a note when no dictionary is available or when exporting an image. Only affects smart. |
|
‑‑dataset‑pid |
string | A persistent identifier (PID) for the dataset - typically a full URL such as a DOI (https://doi.org/10.1234/abc) or other citable link. When set, a "PID" row is added to the metadata table at the top of the dashboard. http(s) and mailto values become a clickable link (opened in a new tab); any other scheme is shown as plain text rather than linked. HTML output only. Only affects smart. |
|
‑‑bivariate |
flag | Add two pairwise-association overview panels driven by qsv moarstats --bivariate: a normalized mutual information (NMI) heatmap over every column pair (works for numeric AND categorical columns, unlike the Pearson-only correlation heatmap), plus a ranked "top relationships" bar of the strongest pairs when there are more than 8 chartable columns. The ranked bar (not the heatmap, which still shows every pair) requires a pair's co-occurring row count to be at least 10% of the best-supported pair's, so a technically-perfect NMI from two sparsely-populated columns that only ever co-occur in a narrow row slice can't crowd out a more broadly meaningful association; each bar's hover shows its co-occurring row count. A numeric pair whose Spearman rank correlation diverges sharply from its Pearson correlation is flagged "nonlinear" in the hover. Identifier / PII / free-text columns (per --dictionary) and map lat/lon columns are excluded. This automatically turns on --smarter, and when --dictionary isn't already set, also turns on --dictionary infer (so the PII/identifier exclusion has semantic signal to work with). Capped at 50 columns (1,225 pairs); wider datasets skip these panels with a warning (run qsv moarstats --bivariate directly for the full pairwise output). Only affects smart. |
|
‑‑log‑scale |
string | Use a logarithmic y-axis for panels with a high dynamic range: frequency bar panels whose tallest bar dwarfs the rest (e.g. a large "(NULL)" or "Other (N)" bucket), so the small categories stay visible; and box panels of an all-positive column whose observed max/min ratio is huge (a box otherwise squashed against its extremes). One of: auto, on, off. "auto" (the default) switches a panel to a log y-axis only when its dynamic range is high; "on" forces a log y-axis on every frequency panel and every all-positive box panel; "off" keeps the linear axes. Only affects smart. |
auto |
‑‑violin |
string | Draw distribution panels as violins (a box plot wrapped in a KDE density silhouette — a strict superset of a plain box) instead of boxes. One of: auto, on, off. "auto" (the default) draws a violin for every continuous column EXCEPT those on a log value axis (the KDE is estimated in linear space, which a log axis would geometrically distort) and those with fewer than 20 distinct values or fewer than 50 non-null observations (too few for a meaningful KDE — the curve would be smoothing artifact) — all keep an honest box; "on" also violins those; "off" never draws violins. Violin KDEs are clamped to each column's observed range (Plotly spanmode "hard") so a bounded or discrete measure can't show density past a natural limit. A column with at most 10,000 non-null values gets an exact violin (with outlier points, like a raw box); up to 30,000 values (one-fifth of the smart point budget, so it scales with QSV_VIZ_MAX_POINTS) still draws an exact violin but drops the point overlay; a larger column draws its silhouette and inner box from a deterministic sample of at most that many evenly strided values, carries no point overlay (a sample misses the true extremes), and is titled "(sampled)". An explicit all, outliers or suspected mode given via the box-points option instead collects every value for every panel, violins included; that option's none mode just hides a violin's points. Only affects smart. |
auto |
‑‑title |
string | Chart title. | |
‑‑x‑title |
string | X-axis title. (defaults to the x column name) | |
‑‑y‑title |
string | Y-axis title. (defaults to the y column name) | |
‑‑y‑range |
string | Fix the y-axis to an explicit min:max range (two colon- separated numbers, e.g. -10:55) instead of autoscaling; points outside are clipped from view. Handy when one extreme outlier squashes the rest. Applies to cartesian charts (bar/line/scatter/histogram/box/violin/heatmap/ contour). Pass a negative min with =: --y-range=-10:55. |
|
‑‑rangeslider |
flag | Add a draggable range-slider (a navigator strip) under the x-axis for panning and zooming. Best for an ordered x-axis (time series, line, candlestick/ohlc). Applies to cartesian charts (bar/line/scatter/histogram/box/violin/candlestick/ ohlc); off by default. | |
‑‑slider |
string | Animate the chart over a column: each distinct value of the given column becomes an animation frame, with a Play/Pause button and a slider to scrub through the frames (Gapminder- style). Supported for bar/line/scatter and geo, and may be split into animated traces with the --series option. (Not supported for viz map — the MapLibre basemap can't animate; use viz geo for an animated point map.) For smart, this controls whether one animated relationship-over-time panel is added: the numeric pair whose per-time-bucket centroid path bends the most (a trailing-window scatter colored by time bucket), or an animated geo map of global-extent dated points, or a Gapminder entity-bubble chart (at most one is shown; when several qualify the bubble wins, then the geo map, then the pair). auto (default) adds one only on a strong signal (a date column and enough time buckets); on lowers the bar (as few as two buckets) but still requires a genuinely drifting or animatable relationship; off never does. Axis ranges are pinned across frames so nothing jumps. |
|
‑‑slider‑speed |
integer | Milliseconds each animation frame is shown while playing. | 800 |
‑‑slider‑cumulative |
flag | Accumulate rows across frames: frame N includes every row whose --slider value is at or below the Nth value, so the animation builds up cumulatively instead of replacing each step. Applies to bar/line/scatter and geo. | |
‑‑annotation |
string | Caption note drawn at the bottom of the plot (e.g. to note a clipped outlier). Cartesian charts only. | |
‑‑theme |
string | Plotly theme that drives the chart's overall look (background, fonts, axis styling). One of: default, plotly_white, plotly_dark, seaborn, seaborn_whitegrid, seaborn_dark, matplotlib, plotnine (case-insensitive; hyphens accepted). When omitted, qsv's built-in look is used. Applies to all chart types, including smart. |
|
‑‑width |
integer | Image width in pixels for static export. Default 1000; for smart, auto-scaled to the grid's column count. |
|
‑‑height |
integer | Image height in pixels for static export. Default 600; for smart, auto-scaled to the number of panel rows. |
|
‑‑scale |
float | Image scale factor (static export). | 1.0 |
‑‑open |
flag | Open the generated chart in the default browser/viewer. |
Common Options ↩
| Option | Type | Description | Default |
|---|---|---|---|
‑h,‑‑help |
flag | Display this message | |
‑o,‑‑output |
string | Write output to instead of stdout. The chart format is inferred from the extension: .html (default), .png, .svg, .pdf, .jpeg, .webp. | |
‑d,‑‑delimiter |
string | The field delimiter for reading CSV data. Must be a single character. (default: ,) | |
‑n,‑‑no‑headers |
flag | When set, the first row will not be interpreted as headers. Columns can then only be selected by index. |
Source: src/cmd/viz.rs
| Table of Contents | README