Remix patches

A remix is a modified copy of a figure’s page that uses the original figure’s data, made on the remix page of manage.figpack.org (or with figpack remix). A limitation of a remix is that it belongs to one generated figure. When the figure is made again in Python, for example with new data, the choices made in the remix (which layout items to show, series colors, axis labels, and so on) are lost. Furthermore, the code that builds the figure often lives in a library that the user does not control, so the choices cannot simply be moved into that code.

A remix patch addresses this. It is a small JSON file with the changes that a remix makes to the figure spec, the figpack.render(spec) script in the figure’s index.html. The changes are keyed by the figure’s structure (the names of layout items and series, and the names of settings) rather than by the code that built the figure, so a patch can be applied to any figure with the same structure, regardless of which library built its views.

Exporting a patch

On the remix page, “Export patch” compares the spec that the remixed page renders with the spec in the figure’s original index.html and downloads the difference as <title>-remix.json. The remixed spec is the one the page actually passes to figpack.render, so a spec script that was edited into other JavaScript still exports correctly.

A patch only carries changes to the spec. Other edits to the page, such as added styles, markup or scripts, are not included. The export dialog lists each such change so that nothing is left out silently. Edits to the spec reference block (data-figpack-spec-docs) are ignored, since figpack writes that block anew for each figure.

Applying a patch in Python

Pass the patch file (or the patch as an already-loaded dict) as remix when making the figure:

view.show(title="My figure", remix="my-figure-remix.json")
view.save("my_figure", title="My figure", remix="my-figure-remix.json")

figpack builds the figure spec from the views as usual and then merges the patch into it before writing index.html. The data in data.zarr is unchanged. Note that remix= requires figpack 0.4.1 or later.

The merge follows the same rules as the spec itself:

  • props replace the existing values per key, as whole values;

  • children merge by name;

  • data and view_type replace the existing values, and a data path must exist in data.zarr.

Parts of the patch that do not match the figure are skipped, each with a printed warning such as remix: no child 'item_2' under 'item_0'; skipped. A child matches if it is in the spec or is a subgroup of the node’s group in data.zarr; a child that the patch gives its own data (an existing path, or null for a node defined only by the spec) is added. A data path that does not exist, and values of the wrong type, are also skipped. Props are not checked against the view’s documented props, so a prop that the view does not use is applied but has no effect.

The figure records the patch it was made with in index.html, next to the spec:

<script type="application/json" data-figpack-remix-patch>
{"file": "my-figure-remix.json", "source": {...}, "patch": {...}, "skipped": ["remix: no child 'item_2' under 'item_0'; skipped"]}
</script>

Applying a patch on the remix page

“Apply patch” on the remix page takes a patch file from your disk and merges it into the spec that the remix currently renders, with the same rules as remix= in Python. The two implementations are kept in step by a shared set of test cases (tests/remix_patch_cases), which both pytest and the figpack-manage tests run. The spec script is then rewritten as formatted JSON, so code that the remix had added to the spec script is replaced, and the dialog says so. The preview re-renders, the dialog lists what changed and which parts of the patch were skipped, and “Undo” restores the page as it was.

If a figure was itself made with a patch, “Export patch” on a remix of it includes that patch, followed by the remix’s own changes. The exported patch therefore reproduces the remix on a figure made without a patch.

Note that a patch can be applied to a figure whose structure differs only in part. For example, a changed items list is applied as a whole value even if it names a layout item that the other figure does not have, since the merge checks children and data paths but not the contents of props.

Format

{
  "figpack_remix_patch": 1,
  "source": {
    "figureUrl": "https://figures.figpack.org/figures/default/.../index.html",
    "createdAt": "2026-10-23T12:00:00.000Z"
  },
  "patch": {
    "props": { "items": [{ "name": "raw" }, { "name": "filtered" }] },
    "children": {
      "item_0": {
        "props": { "y_label": "Voltage (mV)" },
        "children": { "series_1": { "props": { "color": "red" } } }
      }
    }
  }
}

figpack_remix_patch is the format version (currently 1), and source records where the patch came from. patch is a spec diff: it has the shape of a spec node, {data?, view_type?, props?, children?}, but contains only what differs between the original spec and the remixed one.

  • props lists only the props whose values changed. A changed value is given in full, so a list such as items or series_names appears as the whole new list. This matches the spec itself, where props replace the zarr attributes as whole values and are not merged.

  • children lists, by name, only the children that differ. A child that is new in the remix (for example a Markdown node defined only by the spec) is given in full.

  • data and view_type appear only where the remix changed them.

Props and children that the remix removed from the spec are not recorded. In a spec generated by figpack, they only repeat the attributes stored in data.zarr, so removing them has no effect on the figure.