This PR adds support for exporting Vega(-Lite) chart specifications to SVG and PNG static images. This support is added to the vl-convert-rs Rust library, the vl-convert-python Python library, and the vl-convert CLI application.
How it works
deno_core to deno_runtime
The first change this PR makes is adding a dependency on the deno_runtime crate. This is a wrapper around deno_core that adds a variety of extensions for increased browser/node.js support. This is needed to provide support for functions like fetch, which are required by Vega in order to evaluate specifications for image generation.
Custom test width measurement for SVG export
The Vega JavaScript library supports exporting chart specifications to SVG images, and this conversion works in Deno. However, there is a subtle complication. In order to properly position text within the exported SVG, Vega needs to compute the width of text fragments (at a particular font size, in a particular font, etc.). When running in Node.js, these calculations are done using node canvas, which does not work in Deno. When node canvas is not available, Vega falls back to a rough heuristic for text measurement that results in poor text placement results.
For example, here is the stacked horizontal bar chart example from the Vega-Lite gallery.
And here is what the exported image looks like without node canvas.
Notice how much extra space is added between the y-axis label and the y-axis tick labels due to inaccurate text measurements.
This PR works around this by overriding the text width calculation function using a custom Rust function. This custom Rust function uses the usvg crate (part of the resvg project) to compute the width of text fragments. With this customization, we regain accurate text placement in the SVG results produced by Vega. Here is the above example as generated by this PR:
PNG export
The Vega JavaScript library supports exporting chart specifications directly to PNG images. When running in Node.js, this functionality relies on node canvas, which is not available in Deno.
This PR generates PNG images by first exporting charts to SVG as described above, then converting the SVG image to a PNG image using the resvg crate.
CLI changes
Now that additional conversions are supported, the CLI app has been updated to use subcommands, one per conversion format: vl2vg, vl2svg, vl2png, vg2svg, vg2png.
Display the documentation for the top-level vl-convert command
$ vl-convert --help
vl-convert: A utility for converting Vega-Lite specifications
Usage: vl-convert <COMMAND>
Commands:
vl2vg Convert a Vega-Lite specification to a Vega specification
vl2svg Convert a Vega-Lite specification to an SVG image
vl2png Convert a Vega-Lite specification to an PNG image
vg2svg Convert a Vega specification to an SVG image
vg2png Convert a Vega specification to an PNG image
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help information
-V, --version Print version information
Various conversion formats are handled by the subcommands listed above. Documentation for each subcommands is displayed using the --help flag.
vl2vg
Convert a Vega-Lite JSON specification to a Vega JSON specification
$ vl-convert vl2vg --help
Convert a Vega-Lite specification to a Vega specification
Usage: vl-convert vl2vg [OPTIONS] --input <INPUT> --output <OUTPUT>
Options:
-i, --input <INPUT> Path to input Vega-Lite file
-o, --output <OUTPUT> Path to output Vega file to be created
-v, --vl-version <VL_VERSION> Vega-Lite Version. One of 4.17, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5 [default: 5.5]
-p, --pretty Pretty-print JSON in output file
-h, --help Print help information
For example, convert a Vega-Lite specification file named in.vl.json into a Vega specification file named out.vg.json. Perform the conversion using version 5.5 of the Vega-Lite JavaScript library and pretty-print the resulting JSON.
$ vl-convert vl2svg --help
Convert a Vega-Lite specification to an SVG image
Usage: vl-convert vl2svg [OPTIONS] --input <INPUT> --output <OUTPUT>
Options:
-i, --input <INPUT> Path to input Vega-Lite file
-o, --output <OUTPUT> Path to output SVG file to be created
-v, --vl-version <VL_VERSION> Vega-Lite Version. One of 4.17, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5 [default: 5.5]
-h, --help Print help information
For example, convert a Vega-Lite specification file named in.vl.json into an SVG file named out.svg. Perform the conversion using version 5.5 of the Vega-Lite JavaScript library.
$ vl-convert vl2png --help
Convert a Vega-Lite specification to an PNG image
Usage: vl-convert vl2png [OPTIONS] --input <INPUT> --output <OUTPUT>
Options:
-i, --input <INPUT> Path to input Vega-Lite file
-o, --output <OUTPUT> Path to output PNG file to be created
-v, --vl-version <VL_VERSION> Vega-Lite Version. One of 4.17, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5 [default: 5.5]
-s, --scale <SCALE> Image scale factor [default: 1.0]
-h, --help Print help information
For example, convert a Vega-Lite specification file named in.vl.json into a PNG file named out.png with a scale factor of 2. Perform the conversion using version 5.5 of the Vega-Lite JavaScript library.
$ vl-convert vg2svg --help
Convert a Vega specification to an SVG image
Usage: vl-convert vg2svg --input <INPUT> --output <OUTPUT>
Options:
-i, --input <INPUT> Path to input Vega file
-o, --output <OUTPUT> Path to output SVG file to be created
-h, --help Print help information
For example, convert a Vega specification file named in.vg.json into an SVG file named out.svg.
$ vl-convert vg2svg -i ./in.vg.json -o ./out.svg
vg2png
$ vl-convert vg2png --help
Convert a Vega specification to an PNG image
Usage: vl-convert vg2png [OPTIONS] --input <INPUT> --output <OUTPUT>
Options:
-i, --input <INPUT> Path to input Vega file
-o, --output <OUTPUT> Path to output PNG file to be created
-s, --scale <SCALE> Image scale factor [default: 1.0]
-h, --help Print help information
For example, convert a Vega specification file named in.vg.json into a PNG file named out.png with a scale factor of 2.
Overview
This PR adds support for exporting Vega(-Lite) chart specifications to SVG and PNG static images. This support is added to the
vl-convert-rs
Rust library, thevl-convert-python
Python library, and thevl-convert
CLI application.How it works
deno_core
todeno_runtime
The first change this PR makes is adding a dependency on the
deno_runtime
crate. This is a wrapper arounddeno_core
that adds a variety of extensions for increased browser/node.js support. This is needed to provide support for functions likefetch
, which are required by Vega in order to evaluate specifications for image generation.Custom test width measurement for SVG export
The Vega JavaScript library supports exporting chart specifications to SVG images, and this conversion works in Deno. However, there is a subtle complication. In order to properly position text within the exported SVG, Vega needs to compute the width of text fragments (at a particular font size, in a particular font, etc.). When running in Node.js, these calculations are done using node canvas, which does not work in Deno. When node canvas is not available, Vega falls back to a rough heuristic for text measurement that results in poor text placement results.
For example, here is the stacked horizontal bar chart example from the Vega-Lite gallery.
And here is what the exported image looks like without node canvas.
Notice how much extra space is added between the y-axis label and the y-axis tick labels due to inaccurate text measurements.
This PR works around this by overriding the text width calculation function using a custom Rust function. This custom Rust function uses the
usvg
crate (part of theresvg
project) to compute the width of text fragments. With this customization, we regain accurate text placement in the SVG results produced by Vega. Here is the above example as generated by this PR:PNG export
The Vega JavaScript library supports exporting chart specifications directly to PNG images. When running in Node.js, this functionality relies on node canvas, which is not available in Deno.
This PR generates PNG images by first exporting charts to SVG as described above, then converting the SVG image to a PNG image using the
resvg
crate.CLI changes
Now that additional conversions are supported, the CLI app has been updated to use subcommands, one per conversion format:
vl2vg
,vl2svg
,vl2png
,vg2svg
,vg2png
.Display the documentation for the top-level
vl-convert
commandVarious conversion formats are handled by the subcommands listed above. Documentation for each subcommands is displayed using the
--help
flag.vl2vg
Convert a Vega-Lite JSON specification to a Vega JSON specification
For example, convert a Vega-Lite specification file named
in.vl.json
into a Vega specification file namedout.vg.json
. Perform the conversion using version 5.5 of the Vega-Lite JavaScript library and pretty-print the resulting JSON.vl2svg
Convert a Vega-Lite specification to an SVG image
For example, convert a Vega-Lite specification file named
in.vl.json
into an SVG file namedout.svg
. Perform the conversion using version 5.5 of the Vega-Lite JavaScript library.vl2png
Convert a Vega-Lite specification to an PNG image
For example, convert a Vega-Lite specification file named
in.vl.json
into a PNG file namedout.png
with a scale factor of 2. Perform the conversion using version 5.5 of the Vega-Lite JavaScript library.vg2svg
Convert a Vega specification to an SVG image
For example, convert a Vega specification file named
in.vg.json
into an SVG file namedout.svg
.vg2png
For example, convert a Vega specification file named
in.vg.json
into a PNG file namedout.png
with a scale factor of 2.