# Chart edits (ops)

An op is one edit to a chart, written as a small JSON object. The editor makes the same edits when you click through its panels, so what you can do there you can do with ops.

## How to send ops

Send a list of ops to [edit a chart](https://chartjuice.com/docs/api/#apply_ops), or include them as `ops` when you [create one](https://chartjuice.com/docs/api/#create_chart). They are applied in order, and all together or not at all. If one op is wrong, the answer is `invalid_ops`, it says which op and why, and the chart is left as it was.

An op changes only what it names. `{"op":"setTitle","title":{"text":"Sales"}}` sets the title's text and leaves its size, color and position alone. A field that is not part of the op is an error.

## Columns, steps and roles

Ops refer to a column by its id, not its name. Ids look like `c1`, `c2`, `c3`, in the order the columns were read. Renaming a column does not change its id. [Get the chart](https://chartjuice.com/docs/api/#get_chart) to see its columns and their ids.

A step is a sort, a filter or another change to what is charted that leaves the data itself alone. Steps have ids too: `t1`, `t2` and so on, in the order they were added.

A role is the part a column plays in the chart. On a bar chart, `category` is the column of labels and `values` are the columns of numbers. Each chart type has its own roles: [list the chart types](https://chartjuice.com/docs/api/#list_chart_types) to see them.

## The examples

The examples on this page are written for one chart: a bar chart with three columns, `c1` (Month), `c2` (Sales) and `c3` (Costs), and two steps, `t1` (a sort) and `t2` (a filter). To try them, make that chart first:

```json
{
  "type": "bar",
  "data": "Month,Sales,Costs\nJan,4200,3100\nFeb,5100,3300\nMar,4800,3900\nApr,6300,4100",
  "ops": [
    {
      "op": "addTransform",
      "transform": {
        "type": "sort",
        "column": "c2",
        "direction": "desc"
      }
    },
    {
      "op": "addTransform",
      "transform": {
        "type": "filter",
        "column": "c2",
        "op": "gt",
        "value": 1000
      }
    }
  ]
}
```

Under each op, "Fields" lists what it takes, and "From the catalog" is the compact form that AI assistants read, which you can also get from [the op catalog endpoint](https://chartjuice.com/docs/api/#get_op_catalog).

The catalog also names `setAdvanced`, which sets raw chart options. The API does not take it.

## Type and layout

### setType

Change the chart type. The data, the roles and the style carry over.

```json
{
  "op": "setType",
  "type": "line"
}
```

Fields

| Field | Type |
| --- | --- |
| `type` required | "bar" \| "line" \| "pie" \| "scatter" \| "histogram" \| "boxplot" \| "dotplot" \| "sankey" \| "radar" \| "heatmap" |

From the catalog

```
{"op":"setType","type":"bar|line|pie|scatter|histogram|boxplot|dotplot|sankey|radar|heatmap"}: data, mapping and style carry over.
```

### setVariants

Set the options that belong to one chart type. Only the options you name change.

```json
{
  "op": "setVariants",
  "variants": {
    "bar": {
      "orientation": "horizontal",
      "stack": "stacked"
    }
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `variants` required | object |
| `variants.bar` optional | object |
| `variants.bar.orientation` optional | "vertical" \| "horizontal" |
| `variants.bar.stack` optional | "none" \| "stacked" \| "percent" |
| `variants.line` optional | object |
| `variants.line.area` optional | boolean |
| `variants.line.step` optional | boolean |
| `variants.line.stack` optional | "none" \| "stacked" \| "percent" |
| `variants.line.smooth` optional | number, 0 to 1 |
| `variants.pie` optional | object |
| `variants.pie.donut` optional | boolean |
| `variants.pie.innerRadiusPct` optional | number, 10 to 90 |
| `variants.scatter` optional | object |
| `variants.scatter.bubble` optional | boolean |
| `variants.scatter.trendline` optional | boolean |
| `variants.scatter.showR2` optional | boolean |
| `variants.histogram` optional | object |
| `variants.histogram.binMode` optional | "auto" \| "count" \| "width" |
| `variants.histogram.bins` optional | integer, 1 to 200 |
| `variants.histogram.binWidth` optional | number, over 0 |
| `variants.boxplot` optional | object |
| `variants.boxplot.quartileMethod` optional | "exclusive" \| "inclusive" |
| `variants.boxplot.showOutliers` optional | boolean |
| `variants.dotplot` optional | object |
| `variants.dotplot.marker` optional | "dot" \| "x" |
| `variants.sankey` optional | object |
| `variants.sankey.orient` optional | "horizontal" \| "vertical" |
| `variants.radar` optional | object |
| `variants.radar.max` optional | number, over 0 or null |
| `variants.heatmap` optional | object |
| `variants.heatmap.scale` optional | "sequential" \| "diverging" |

From the catalog

```
{"op":"setVariants","variants":{"<type>":{...}}}: options per type:
bar {orientation:"vertical"|"horizontal", stack:"none"|"stacked"|"percent"}
line {area:bool, step:bool, stack:"none"|"stacked"|"percent", smooth:0..1}
pie {donut:bool, innerRadiusPct:10..90}
scatter {bubble:bool, trendline:bool, showR2:bool}
histogram {binMode:"auto"|"count"|"width", bins:1..200, binWidth:>0}
boxplot {quartileMethod:"exclusive"|"inclusive", showOutliers:bool}   (exclusive = "Textbook", inclusive = "Excel")
dotplot {marker:"dot"|"x"}
sankey {orient:"horizontal"|"vertical"}
radar {max:number|null}
heatmap {scale:"sequential"|"diverging"}
```

## Which columns are charted

### setMapping

Say which column plays which role. Roles you leave out stay as they are, and null clears one.

```json
{
  "op": "setMapping",
  "mapping": {
    "category": "c1",
    "values": [
      "c2",
      "c3"
    ]
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `mapping` required | object |
| `mapping.category` optional | string or null |
| `mapping.values` optional | array of strings |
| `mapping.value` optional | string or null |
| `mapping.x` optional | string or null |
| `mapping.y` optional | string or null |
| `mapping.size` optional | string or null |
| `mapping.group` optional | string or null |
| `mapping.source` optional | string or null |
| `mapping.target` optional | string or null |

From the catalog

```
{"op":"setMapping","mapping":{"category":"c1","values":["c2","c3"]}}: roles per type:
bar/line/radar: category + values[]   pie: category + value   scatter: x, y, size?, group?
histogram/boxplot/dotplot: value, group?   sankey: source, target, value   heatmap: x, y, value
```

### autoMap

Let Chartjuice pick the roles again from the data.

```json
{
  "op": "autoMap"
}
```

From the catalog

```
{"op":"autoMap"}: let Chartjuice pick sensible roles again.
```

## Steps

### addTransform

Add a step: a sort, filter, top N, total, pivot or calculated column. Steps change what is charted without changing the data.

```json
{
  "op": "addTransform",
  "transform": {
    "type": "topN",
    "column": "c2",
    "n": 3,
    "otherLabel": "Other"
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `transform` required | one of: filter, sort, aggregate, pivot, unpivot, topN, derive |
| `transform (filter).column` required | string |
| `transform (filter).op` required | "eq" \| "neq" \| "gt" \| "gte" \| "lt" \| "lte" \| "contains" \| "notEmpty" |
| `transform (filter).value` optional | any |
| `transform (sort).column` required | string |
| `transform (sort).direction` required | "asc" \| "desc" |
| `transform (aggregate).groupBy` required | array of strings |
| `transform (aggregate).measures` required | array of objects |
| `transform (aggregate).measures[].column` required | string |
| `transform (aggregate).measures[].fn` required | "sum" \| "avg" \| "count" \| "min" \| "max" \| "median" |
| `transform (pivot).index` required | string |
| `transform (pivot).columns` required | string |
| `transform (pivot).values` required | string |
| `transform (pivot).fn` required | "sum" \| "avg" \| "count" \| "min" \| "max" \| "median" |
| `transform (unpivot).idColumns` required | array of strings |
| `transform (unpivot).nameColumn` required | string |
| `transform (unpivot).valueColumn` required | string |
| `transform (topN).column` required | string |
| `transform (topN).n` required | integer, at least 1 |
| `transform (topN).otherLabel` optional | string |
| `transform (derive).name` required | string |
| `transform (derive).expression` required | string |
| `at` optional | integer, at least 0 |

From the catalog

```
{"op":"addTransform","transform":{...},"at"?:index}
{"type":"sort","column":"c2","direction":"asc"|"desc"}   (desc = largest first: the left bar, or the top bar when bars are horizontal)
{"type":"filter","column":"c1","op":"eq|neq|gt|gte|lt|lte|contains|notEmpty","value"?:string|number}
{"type":"topN","column":"c2","n":5,"otherLabel"?:"Other"}   (keeps the largest n and sums the rest into one more row, otherLabel: n 5 gives 6 bars or slices)
{"type":"aggregate","groupBy":["c1"],"measures":[{"column":"c2","fn":"sum|avg|count|min|max|median"}]}
{"type":"pivot","index":"c1","columns":"c2","values":"c3","fn":"sum"}
{"type":"unpivot","idColumns":["c1"],"nameColumn":"Series","valueColumn":"Value"}
{"type":"derive","name":"Profit","expression":"[Revenue] - [Costs]"}   (+ - * / and parentheses; [Column Name] references)
```

### updateTransform

Replace a step, by its id.

```json
{
  "op": "updateTransform",
  "id": "t1",
  "transform": {
    "type": "sort",
    "column": "c3",
    "direction": "asc"
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `id` required | string |
| `transform` required | one of: filter, sort, aggregate, pivot, unpivot, topN, derive |
| `transform (filter).column` required | string |
| `transform (filter).op` required | "eq" \| "neq" \| "gt" \| "gte" \| "lt" \| "lte" \| "contains" \| "notEmpty" |
| `transform (filter).value` optional | any |
| `transform (sort).column` required | string |
| `transform (sort).direction` required | "asc" \| "desc" |
| `transform (aggregate).groupBy` required | array of strings |
| `transform (aggregate).measures` required | array of objects |
| `transform (aggregate).measures[].column` required | string |
| `transform (aggregate).measures[].fn` required | "sum" \| "avg" \| "count" \| "min" \| "max" \| "median" |
| `transform (pivot).index` required | string |
| `transform (pivot).columns` required | string |
| `transform (pivot).values` required | string |
| `transform (pivot).fn` required | "sum" \| "avg" \| "count" \| "min" \| "max" \| "median" |
| `transform (unpivot).idColumns` required | array of strings |
| `transform (unpivot).nameColumn` required | string |
| `transform (unpivot).valueColumn` required | string |
| `transform (topN).column` required | string |
| `transform (topN).n` required | integer, at least 1 |
| `transform (topN).otherLabel` optional | string |
| `transform (derive).name` required | string |
| `transform (derive).expression` required | string |

From the catalog

```
{"op":"updateTransform","id":"t1","transform":{...}}, {"op":"removeTransform","id":"t1"}, {"op":"moveTransform","id":"t1","to":0}
```

### removeTransform

Remove a step, by its id.

```json
{
  "op": "removeTransform",
  "id": "t2"
}
```

Fields

| Field | Type |
| --- | --- |
| `id` required | string |

From the catalog

```
{"op":"updateTransform","id":"t1","transform":{...}}, {"op":"removeTransform","id":"t1"}, {"op":"moveTransform","id":"t1","to":0}
```

### moveTransform

Move a step to a new place in the order. Positions count from 0.

```json
{
  "op": "moveTransform",
  "id": "t2",
  "to": 0
}
```

Fields

| Field | Type |
| --- | --- |
| `id` required | string |
| `to` required | integer, at least 0 |

From the catalog

```
{"op":"updateTransform","id":"t1","transform":{...}}, {"op":"removeTransform","id":"t1"}, {"op":"moveTransform","id":"t1","to":0}
```

## Text

### setTitle

Set the title: its text, whether it shows, where it sits and how it looks.

```json
{
  "op": "setTitle",
  "title": {
    "text": "Sales and costs",
    "align": "center",
    "style": {
      "size": "XL",
      "bold": true
    }
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `title` required | object |
| `title.show` optional | boolean |
| `title.text` optional | string |
| `title.align` optional | "left" \| "center" \| "right" |
| `title.vertical` optional | "top" \| "bottom" |
| `title.style` optional | object |
| `title.style.size` optional | "XS" \| "S" \| "M" \| "L" \| "XL" \| "XXL" or number, 6 to 200 |
| `title.style.color` optional | string |
| `title.style.bold` optional | boolean |
| `title.style.italic` optional | boolean |

From the catalog

```
{"op":"setTitle","title":{"show"?:bool,"text"?:str,"align"?:"left|center|right","vertical"?:"top|bottom","style"?:TextStyle}}
```

### setSubtitle

Set the line under the title.

```json
{
  "op": "setSubtitle",
  "subtitle": {
    "show": true,
    "text": "January to April"
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `subtitle` required | object |
| `subtitle.show` optional | boolean |
| `subtitle.text` optional | string |
| `subtitle.style` optional | object |
| `subtitle.style.size` optional | "XS" \| "S" \| "M" \| "L" \| "XL" \| "XXL" or number, 6 to 200 |
| `subtitle.style.color` optional | string |
| `subtitle.style.bold` optional | boolean |
| `subtitle.style.italic` optional | boolean |

From the catalog

```
{"op":"setSubtitle","subtitle":{"show"?:bool,"text"?:str,"style"?:TextStyle}}
```

## Axes

### setAxis

Change one axis: its title, labels and their number format, gridlines, line, ticks and range.

```json
{
  "op": "setAxis",
  "axis": "y",
  "patch": {
    "title": {
      "show": true,
      "text": "US dollars"
    },
    "labels": {
      "format": {
        "prefix": "$",
        "compact": true
      }
    }
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `axis` required | "x" \| "y" |
| `patch` required | object |
| `patch.title` optional | object |
| `patch.title.show` optional | boolean |
| `patch.title.text` optional | string |
| `patch.title.style` optional | object |
| `patch.title.style.size` optional | "XS" \| "S" \| "M" \| "L" \| "XL" \| "XXL" or number, 6 to 200 |
| `patch.title.style.color` optional | string |
| `patch.title.style.bold` optional | boolean |
| `patch.title.style.italic` optional | boolean |
| `patch.labels` optional | object |
| `patch.labels.show` optional | boolean |
| `patch.labels.style` optional | object |
| `patch.labels.style.size` optional | "XS" \| "S" \| "M" \| "L" \| "XL" \| "XXL" or number, 6 to 200 |
| `patch.labels.style.color` optional | string |
| `patch.labels.style.bold` optional | boolean |
| `patch.labels.style.italic` optional | boolean |
| `patch.labels.format` optional | object |
| `patch.labels.format.decimals` optional | integer, 0 to 10 or null |
| `patch.labels.format.prefix` optional | string |
| `patch.labels.format.suffix` optional | string |
| `patch.labels.format.thousands` optional | boolean |
| `patch.labels.format.compact` optional | boolean |
| `patch.gridlines` optional | object |
| `patch.gridlines.show` optional | boolean |
| `patch.gridlines.color` optional | string |
| `patch.line` optional | object |
| `patch.line.show` optional | boolean |
| `patch.ticks` optional | object |
| `patch.ticks.show` optional | boolean |
| `patch.min` optional | any |
| `patch.max` optional | any |
| `patch.boundaryGap` optional | boolean |

From the catalog

```
{"op":"setAxis","axis":"x"|"y","patch":{"title"?:{"show","text","style"},"labels"?:{"show","style","format"},"gridlines"?:{"show","color"},"line"?:{"show"},"ticks"?:{"show"},"min"?:number|null,"max"?:number|null,"boundaryGap"?:bool}}
```

## Legend and labels

### setLegend

Show or hide the legend, and place it.

```json
{
  "op": "setLegend",
  "legend": {
    "show": true,
    "position": {
      "x": "right",
      "y": "top"
    },
    "orient": "vertical"
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `legend` required | object |
| `legend.show` optional | boolean or "auto" |
| `legend.position` optional | object |
| `legend.position.x` optional | "left" \| "center" \| "right" |
| `legend.position.y` optional | "top" \| "middle" \| "bottom" |
| `legend.orient` optional | "horizontal" \| "vertical" |
| `legend.padding` optional | number, 0 to 200 |
| `legend.style` optional | object |
| `legend.style.size` optional | "XS" \| "S" \| "M" \| "L" \| "XL" \| "XXL" or number, 6 to 200 |
| `legend.style.color` optional | string |
| `legend.style.bold` optional | boolean |
| `legend.style.italic` optional | boolean |

From the catalog

```
{"op":"setLegend","legend":{"show"?:true|false|"auto","position"?:{"x":"left|center|right","y":"top|middle|bottom"},"orient"?:"horizontal|vertical","padding"?:px,"style"?:TextStyle}}
```

### setLabels

Show the values on the marks, and format them.

```json
{
  "op": "setLabels",
  "labels": {
    "show": true,
    "position": "top",
    "format": {
      "prefix": "$",
      "thousands": true
    }
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `labels` required | object |
| `labels.show` optional | boolean |
| `labels.position` optional | "inside" \| "outside" \| "top" \| "center" |
| `labels.style` optional | object |
| `labels.style.size` optional | "XS" \| "S" \| "M" \| "L" \| "XL" \| "XXL" or number, 6 to 200 |
| `labels.style.color` optional | string |
| `labels.style.bold` optional | boolean |
| `labels.style.italic` optional | boolean |
| `labels.format` optional | object |
| `labels.format.decimals` optional | integer, 0 to 10 or null |
| `labels.format.prefix` optional | string |
| `labels.format.suffix` optional | string |
| `labels.format.thousands` optional | boolean |
| `labels.format.compact` optional | boolean |
| `labels.showPercent` optional | boolean |

From the catalog

```
{"op":"setLabels","labels":{"show"?:bool,"position"?:"inside|outside|top|center","showPercent"?:bool,"style"?:TextStyle,"format"?:NumberFormat}}   (showPercent: pie only)
```

## Colors and look

### setCanvas

Set the chart's size in pixels, its background and its padding. An empty background is transparent.

```json
{
  "op": "setCanvas",
  "canvas": {
    "width": 1200,
    "height": 675,
    "background": "#FFFFFF"
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `canvas` required | object |
| `canvas.width` optional | number, 100 to 4,000 |
| `canvas.height` optional | number, 100 to 4,000 |
| `canvas.background` optional | string |
| `canvas.padding` optional | object |
| `canvas.padding.top` optional | number, 0 to 400 |
| `canvas.padding.right` optional | number, 0 to 400 |
| `canvas.padding.bottom` optional | number, 0 to 400 |
| `canvas.padding.left` optional | number, 0 to 400 |

From the catalog

```
{"op":"setCanvas","canvas":{"width"?:px,"height"?:px,"background"?:"#hex" or "" for transparent,"padding"?:{"top","right","bottom","left"}}}
```

### setFont

Set the font and the default text color for the whole chart.

```json
{
  "op": "setFont",
  "font": {
    "family": "Bitter",
    "color": "#102A43"
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `font` required | object |
| `font.family` optional | "Inter" \| "Bitter" \| "IBM Plex Mono" |
| `font.color` optional | string |

From the catalog

```
{"op":"setFont","font":{"family"?:"Inter|Bitter|IBM Plex Mono","color"?:"#hex"}}
```

### setPalette

Set the colors series take, in order.

```json
{
  "op": "setPalette",
  "palette": [
    "#0F766E",
    "#F59E0B",
    "#E11D48"
  ]
}
```

Fields

| Field | Type |
| --- | --- |
| `palette` required | array of strings |

From the catalog

```
{"op":"setPalette","palette":["#0C008C","#5D55FA",…]}: series colors in order. Named presets (Ocean, Pastel, …): lookup_docs "palettes".
```

### setSeriesStyle

Give one series its own color or legend name. Null goes back to the palette's color or the column's name.

```json
{
  "op": "setSeriesStyle",
  "column": "c3",
  "color": "#E11D48",
  "name": "Running costs"
}
```

Fields

| Field | Type |
| --- | --- |
| `column` required | string |
| `color` optional | string or null |
| `name` optional | any |

From the catalog

```
{"op":"setSeriesStyle","column":"c2","color"?:"#hex"|null,"name"?:str|null}: one series' color or legend name.
```

### setMarkStyle

Style the marks themselves: bars, lines, points, slices and so on.

```json
{
  "op": "setMarkStyle",
  "marks": {
    "bar": {
      "radius": 6,
      "opacity": 0.9
    }
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `marks` required | object |
| `marks.bar` optional | object |
| `marks.bar.radius` optional | number, 0 to 40 |
| `marks.bar.opacity` optional | number, 0 to 1 |
| `marks.line` optional | object |
| `marks.line.width` optional | number, 0 to 12 |
| `marks.line.symbol` optional | "none" \| "emptyCircle" \| "circle" \| "square" \| "triangle" \| "diamond" |
| `marks.line.symbolSize` optional | number, 0 to 30 |
| `marks.line.symbolColor` optional | string or null |
| `marks.area` optional | object |
| `marks.area.opacity` optional | number, 0 to 1 |
| `marks.area.gradient` optional | boolean |
| `marks.pie` optional | object |
| `marks.pie.radiusPct` optional | number, 10 to 100 |
| `marks.pie.offsetX` optional | number, -50 to 50 |
| `marks.pie.labelLines` optional | boolean |
| `marks.scatter` optional | object |
| `marks.scatter.symbol` optional | "none" \| "emptyCircle" \| "circle" \| "square" \| "triangle" \| "diamond" |
| `marks.scatter.size` optional | number, 2 to 60 |
| `marks.scatter.opacity` optional | number, 0 to 1 |
| `marks.histogram` optional | object |
| `marks.histogram.gap` optional | number, 0 to 60 |
| `marks.boxplot` optional | object |
| `marks.boxplot.width` optional | number, 10 to 200 |
| `marks.dotplot` optional | object |
| `marks.dotplot.size` optional | number, 4 to 40 |
| `marks.sankey` optional | object |
| `marks.sankey.nodeWidth` optional | number, 4 to 60 |
| `marks.sankey.nodeGap` optional | number, 2 to 60 |
| `marks.sankey.linkOpacity` optional | number, 0 to 1 |
| `marks.radar` optional | object |
| `marks.radar.shape` optional | "polygon" \| "circle" |
| `marks.radar.fillOpacity` optional | number, 0 to 1 |
| `marks.heatmap` optional | object |
| `marks.heatmap.colors` optional | array of strings |
| `marks.heatmap.showValues` optional | boolean |

From the catalog

```
{"op":"setMarkStyle","marks":{"<mark>":{...}}}:
bar {radius:0..40, opacity:0..1}   line {width:0..12, symbol:"none|emptyCircle|circle|square|triangle|diamond", symbolSize:0..30, symbolColor:"#hex"|null}
area {opacity:0..1, gradient:bool}   pie {radiusPct:10..100, offsetX:-50..50, labelLines:bool}
scatter {symbol, size:2..60, opacity:0..1}   histogram {gap:0..60}   boxplot {width:10..200}   dotplot {size:4..40}
sankey {nodeWidth:4..60, nodeGap:2..60, linkOpacity:0..1}   radar {shape:"polygon|circle", fillOpacity:0..1}
heatmap {colors:["#low","#high"] or ["#low","#mid","#high"], showValues:bool}
```

### applyTheme

Apply a ready-made set of colors to the whole chart.

```json
{
  "op": "applyTheme",
  "theme": "midnight"
}
```

Fields

| Field | Type |
| --- | --- |
| `theme` required | "juice" \| "midnight" \| "minimal" |

From the catalog

```json
{"op":"applyTheme","theme":"juice|midnight|minimal"}
```

## Data cells

### setData

Replace the whole table from inside a list of ops. To send CSV or JSON rows, use the replace data endpoint, which reads types for you.

```json
{
  "op": "setData",
  "data": {
    "columns": [
      {
        "id": "c1",
        "name": "City",
        "kind": "text"
      },
      {
        "id": "c2",
        "name": "People",
        "kind": "number"
      }
    ],
    "rows": [
      [
        "Oslo",
        700000
      ],
      [
        "Bergen",
        290000
      ]
    ]
  }
}
```

Fields

| Field | Type |
| --- | --- |
| `data` required | object |
| `data.columns` required | array of objects |
| `data.columns[].id` required | string |
| `data.columns[].name` required | string |
| `data.columns[].kind` required | "text" \| "number" \| "date" |
| `data.rows` required | array of (array of anys) |
| `remap` optional | boolean |

From the catalog

```
{"op":"setData","data":{"columns":[{"id":"c1","name":"Month","kind":"text"},…],"rows":[[…],…]}}: replaces the whole table; only when the user asks for new or example data.
```

### updateCell

Change one cell. Rows count from 0.

```json
{
  "op": "updateCell",
  "row": 0,
  "column": "c2",
  "value": 4500
}
```

Fields

| Field | Type |
| --- | --- |
| `row` required | integer, at least 0 |
| `column` required | string |
| `value` required | any |

From the catalog

```
{"op":"updateCell","row":0,"column":"c2","value":42}   (rows are 0-based)
```

### insertRows

Add rows at a position. Each row has one value per column.

```json
{
  "op": "insertRows",
  "at": 4,
  "rows": [
    [
      "May",
      7100,
      4300
    ]
  ]
}
```

Fields

| Field | Type |
| --- | --- |
| `at` required | integer, at least 0 |
| `rows` required | array of (array of anys) |

From the catalog

```
{"op":"insertRows","at":3,"rows":[["Jul",5100]]}, {"op":"deleteRows","at":3,"count":1}
```

### deleteRows

Remove rows, starting at a position.

```json
{
  "op": "deleteRows",
  "at": 0,
  "count": 1
}
```

Fields

| Field | Type |
| --- | --- |
| `at` required | integer, at least 0 |
| `count` required | integer, at least 1 |

From the catalog

```
{"op":"insertRows","at":3,"rows":[["Jul",5100]]}, {"op":"deleteRows","at":3,"count":1}
```

### insertColumn

Add a column at a position, with its values if you have them.

```json
{
  "op": "insertColumn",
  "at": 3,
  "name": "Target",
  "kind": "number",
  "values": [
    4000,
    5000,
    5000,
    6000
  ]
}
```

Fields

| Field | Type |
| --- | --- |
| `at` required | integer, at least 0 |
| `name` required | string |
| `kind` required | "text" \| "number" \| "date" |
| `values` optional | array of anys |

From the catalog

```
{"op":"insertColumn","at":2,"name":"Target","kind":"number|text|date","values"?:[…]}, {"op":"deleteColumn","column":"c3"}
```

### deleteColumn

Remove a column. It is taken out of the roles too.

```json
{
  "op": "deleteColumn",
  "column": "c3"
}
```

Fields

| Field | Type |
| --- | --- |
| `column` required | string |

From the catalog

```
{"op":"insertColumn","at":2,"name":"Target","kind":"number|text|date","values"?:[…]}, {"op":"deleteColumn","column":"c3"}
```

### renameColumn

Rename a column. Its id stays the same.

```json
{
  "op": "renameColumn",
  "column": "c2",
  "name": "Revenue"
}
```

Fields

| Field | Type |
| --- | --- |
| `column` required | string |
| `name` required | string |

From the catalog

```
{"op":"renameColumn","column":"c2","name":"Revenue"}, {"op":"setColumnKind","column":"c1","kind":"date"}, {"op":"reorderColumns","order":["c2","c1"]}
```

### setColumnKind

Say whether a column holds text, numbers or dates.

```json
{
  "op": "setColumnKind",
  "column": "c1",
  "kind": "text"
}
```

Fields

| Field | Type |
| --- | --- |
| `column` required | string |
| `kind` required | "text" \| "number" \| "date" |

From the catalog

```
{"op":"renameColumn","column":"c2","name":"Revenue"}, {"op":"setColumnKind","column":"c1","kind":"date"}, {"op":"reorderColumns","order":["c2","c1"]}
```

### reorderColumns

Put the columns in a new order. Name every column once.

```json
{
  "op": "reorderColumns",
  "order": [
    "c1",
    "c3",
    "c2"
  ]
}
```

Fields

| Field | Type |
| --- | --- |
| `order` required | array of strings |

From the catalog

```
{"op":"renameColumn","column":"c2","name":"Revenue"}, {"op":"setColumnKind","column":"c1","kind":"date"}, {"op":"reorderColumns","order":["c2","c1"]}
```

---

This is https://chartjuice.com/docs/ops/ as Markdown. Every docs page is listed at https://chartjuice.com/llms.txt.
