By: David Anthoff
Re-posted from: https://www.queryverse.org//2020/03/11/vegalite-v2.0.0/
We released VegaLite.jl v2.0 a couple of days ago. This new version brings a lot of new features along! I’ll try to walk you through some of them in this blog post.
For those of you not familiar with the package: VegaLite.jl is a powerful plotting package for Julia.
Vega-Lite 4
We updated the Julia package to use the latest version of the underlying JavaScript library, Vega-Lite 4. This brings a ton of new features to the table. You can take a look at a detailed description of all these updates by looking at the release notes for all the Vega-Lite versions we now incorporate:
I encourage you to take a look at these release notes, they have examples for each new feature and give a good overview of what is happening in the underlying library. There is a lot of good stuff (regression, loess, density and quantile transforms, a strokeDash
encoding channel, lots of new interactive stuff and a ton of other features)!
Support for inline data
We now support inline data, i.e. you can now create a plot from vectors of data directly, without the need to pass a tabular data structure like DataFrame
to the plot function. The following example plots a scatter plot of two vectors of random numbers:
using VegaLite
a_vector = rand(10)
@vlplot(:point, x=rand(10), y=a_vector)
You can also pass vectors inside a composite value:
using VegaLite
@vlplot(:line, x={1:10, title="Timestep"}, y=rand(10))
Support for positional x
and y
encodings
The values for the x
and y
encoding channel can now be passed as positional arguments, thus further reducing the amount of code required for common plots.
In particular, the second positional argument is now interpreted as the x
channel, and the third positional argument as the y
channel.
A simple example that uses some tabular data is this:
using VegaLite, VegaDatasets
dataset("cars") |> @vlplot(:point, :Acceleration, :Miles_per_Gallon)
The combination of positional arguments and inline data makes the code for a simple scatter plot of two vectors really concise:
using VegaLite
a = rand(10)
b = rand(10)
@vlplot(:point, a, b)
Save plots as HTML files
You can now save a plot directly as a HTML file:
using VegaLite
@vlplot(:point, rand(10), rand(10)) |> save("figure.html")
These HTML files are self contained, and are especially useful for interactive charts (which will fully work if someone opens the generated HTML file in a web browser).
Much better support for Vega specs
The package now exports a new @vgplot
macro. It works exactly like @vlplot
, except that you can use it to create Vega plots. Vega is the lower-level plotting library that Vega-Lite uses under the hood. It is more verbose than Vega-Lite, but gives you much more control over the types of plots you can create. Take a look at the Vega examples to get a sense.
Better Juno integration
Interactive plots should now work properly in Juno.
Convert plots into Julia code (experimental)
You can now take a plot object and call a function to get some Julia code that would re-create exactly that plot object. Here is a simple example:
using VegaLite, VegaDatasets
p = dataset("cars") |> @vlplot(:point, :Acceleration, :Miles_per_Gallon)
VegaLite.printrepr(stdout, p)
This will output:
@vlplot(mark="point",encoding={x={field="Acceleration"},y={field="Miles_per_Gallon"}})
This standalone example is probably not very useful, but this functionality can be very convenient if you obtain the plot from some other source.
For example, here is an example where you copy a Vega-Lite JSON example and convert it into an equivalent Julia code representation:
using VegaLite
p = vl"""
{
"mark": "point",
"encoding": {
"x": {
"field": "Miles_per_Gallon"
},
"y": {
"field": "Acceleration"
}
}
}
"""
VegaLite.printrepr(stdout, p)
This also outputs the Julia code that would create this spec:
@vlplot(encoding={x={field="Miles_per_Gallon"},y={field="Acceleration"}},mark="point")
Another scenario is that you load a Vega-Lite spec from disc and directly convert it into Julia code:
using VegaLite
VegaLite.printrepr(stdout, load("figure.vegalite"))
Or maybe you used DataVoyager.jl to interactively create a plot and now want to include some code that creates that same figure, but in a non-interactive way:
using DataVoyager, VegaDatasets
# Run Voyager
w = dataset("cars") |> Voyager()
# At this point you would interactively create your plot and proceed once you are done with that
# Extract the plot from the UI
p = w[]
# Convert the interactively created plot into Julia code
VegaLite.printrepr(stdout, p)
New examples
We have a ton of new examples, both for Vega and Vega-Lite plots in the documentation, check them out here!
New expert APIs (experimental)
We now also export a purely non-macro based API. The two functions for that are vlplot
and vgplot
. Normal users are encouraged to continue to use the @vlplot
and @vgplot
macros, these new functions are mostly meant for some special situations where other packages can’t use the macro versions of these calls.
We also export new macros and functions called @vlfrag
, @vgfrag
, vlfrag
and vgfrag
. These allow you to create spec fragments and then pass these to the main level @vlplot
, @vgplot
, vlplot
and vgplot
macros and functions.
For example, in this example I break up the call to @vlplot
into two calls by using the @vlfrag
macro:
using VegaLite, VegaDatasets
x_frag = @vlfrag(:Miles_per_Gallon, title="Custom title")
dataset("cars") |> @vlplot(:point, x=x_frag)
We again discourage use of this feature in normal user code, this is another feature that is probably most useful for package authors that want to make use of VegaLite.jl.
Bug fixes and performance
There are a ton of bug fixes and performance improvements in this version:
- We handle inline data much more efficiently
- We auto-encode encoding types in sub specs
- We properly apply shorthands in sub specs
Thanks
This release had a lot of folks contributing, I in particular want to thank oheil, mcmcgrath13 and tkf for their help!