# Run as: iex --dot-iex path/to/notebook.exs
# Title: Plotting with VegaLite
Mix.install([
{:vega_lite, "~> 0.1.6"},
{:kino_vega_lite, "~> 0.1.11"}
])
# ── Introduction ──
# We need two libraries for plotting in Livebook:
# * The [`vega_lite`](https://hexdocs.pm/vega_lite/)
# package allows us to define our graph specifications
# * The [`kino_vega_lite`](https://hexdocs.pm/kino_vega_lite/) package
# instructs Livebook how to render our specifications
# Let's install them by running the setup cell above.
# When building graphics we make extensive use of the functions from `VegaLite`,
# so it's useful to alias the module as something shorter.
alias VegaLite, as: Vl
# ── The Chart smart cell ── (⎇ from Introduction)
# Before we get into exploring all the various chart types, let's have
# a look at an awesome feature that comes with `kino_vega_lite` - the
# **Chart** smart cell!
# Coding up a chart usually involves a couple steps. If you don't know
# the API of a particular library, it may be a bit challenging. On the
# other hand, if you know the API in-and-out, it's a rather repetitive
# task. That's where the **Chart** smart cell comes in, it is a
# high-level UI that helps us write our chart code. It is great
# a tool for learning and for automating our workflows. Let's
# give it a try!
# First, we need some data to work with, here's a small excerpt from
# the popular [Iris dataset](https://www.kaggle.com/datasets/uciml/iris):
# iris = [
# %{"petal_length" => 5.1, "petal_width" => 1.9, "species" => "Iris-virginica"},
# %{"petal_length" => 4.0, "petal_width" => 1.3, "species" => "Iris-versicolor"},
# %{"petal_length" => 1.6, "petal_width" => 0.2, "species" => "Iris-setosa"},
# %{"petal_length" => 1.6, "petal_width" => 0.2, "species" => "Iris-setosa"},
# %{"petal_length" => 4.6, "petal_width" => 1.4, "species" => "Iris-versicolor"},
# %{"petal_length" => 4.8, "petal_width" => 1.8, "species" => "Iris-virginica"},
# %{"petal_length" => 5.6, "petal_width" => 2.2, "species" => "Iris-virginica"},
# %{"petal_length" => 5.1, "petal_width" => 1.6, "species" => "Iris-versicolor"},
# %{"petal_length" => 1.5, "petal_width" => 0.3, "species" => "Iris-setosa"},
# %{"petal_length" => 4.5, "petal_width" => 1.6, "species" => "Iris-versicolor"}
# ]
# :ok
# Now, to insert a new Chart cell, place your cursor between cells,
# click on the <kbd>+ Smart</kbd> button and select Chart.
# You can see an example of that below. Click on the "Evaluate"
# button to see the chart, then see how it changes as you customize
# the parameters.
# Vl.new(width: 400, height: 200, title: "Iris")
# |> Vl.data_from_values(iris, only: ["petal_length", "petal_width", "species"])
# |> Vl.mark(:point)
# |> Vl.encode_field(:x, "petal_length", type: :quantitative)
# |> Vl.encode_field(:y, "petal_width", type: :quantitative)
# |> Vl.encode_field(:color, "species")
# Under cell actions there is a "Source" button, click on it to
# see the source code of your chart. You can even convert it to
# a regular Code cell for further adjustments!
# The Chart smart cell is one of many Smart cells available
# in Livebook ⚡ Not only that, you can create your own Smart
# cells too, which we discuss in the
# [Exploring Smart cells](/learn/notebooks/smart-cells) notebook!
# ── Basic concepts ── (⎇ from Introduction)
# Composing a basic Vega-Lite graphic usually consists of the following steps:
# # Initialize the specification, optionally with some top-level properties
# Vl.new(width: 400, height: 400)
# # Specify data source for the graphic using one of the data_from_* functions
# |> Vl.data_from_values(iteration: 1..100, score: 1..100)
# # Pick a visual mark
# |> Vl.mark(:line)
# # Map data fields to visual properties of the mark, in this case point positions
# |> Vl.encode_field(:x, "iteration", type: :quantitative)
# |> Vl.encode_field(:y, "score", type: :quantitative)
# Below you can find a number of example graphics for common use cases.
# For a number of plain Vega-Lite examples you can look
# [here](https://vega.github.io/vega-lite/examples).
# ── Bar charts ── (⎇ from Introduction)
# ### Simple bar chart
# A bar chart encodes quantitative values as the length of regular bars.
# # Source: https://vega.github.io/vega-lite/examples/bar.html
# data = [
# %{"a" => "A", "b" => 28},
# %{"a" => "B", "b" => 55},
# %{"a" => "C", "b" => 43},
# %{"a" => "D", "b" => 91},
# %{"a" => "E", "b" => 81},
# %{"a" => "F", "b" => 53},
# %{"a" => "G", "b" => 19},
# %{"a" => "H", "b" => 87},
# %{"a" => "I", "b" => 52}
# ]
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_values(data)
# |> Vl.mark(:bar)
# |> Vl.encode_field(:x, "a", type: :nominal, axis: [label_angle: 0])
# |> Vl.encode_field(:y, "b", type: :quantitative)
# ### Stacked bar chart
# A stacked bar chart contains multi-color bars to represent
# several quantitative values at once.
# # Source: https://vega.github.io/vega-lite/examples/stacked_bar_weather.html
# Vl.new(width: 300, height: 200)
# |> Vl.data_from_url("https://vega.github.io/editor/data/seattle-weather.csv")
# |> Vl.mark(:bar)
# |> Vl.encode_field(:x, "date", time_unit: :month, type: :ordinal, title: "Month of the year")
# |> Vl.encode(:y, aggregate: :count, type: :quantitative, title: "Number of days")
# |> Vl.encode_field(:color, "weather",
# type: :nominal,
# title: "Weather type",
# scale: [
# domain: ["sun", "fog", "drizzle", "rain", "snow"],
# range: ["#e7ba52", "#c7c7c7", "#aec7e8", "#1f77b4", "#9467bd"]
# ]
# )
# ### Grouped bar chart
# Graphing one bar plot per group.
# # Source: https://vega.github.io/vega-lite/examples/bar_grouped.html
# Vl.new(width: [step: 12])
# |> Vl.data_from_url("https://vega.github.io/editor/data/population.json")
# |> Vl.transform(filter: "datum.year == 2000")
# |> Vl.transform(calculate: "datum.sex == 2 ? 'Female' : 'Male'", as: "gender")
# |> Vl.mark(:bar)
# |> Vl.encode_field(:column, "age", type: :ordinal, spacing: 10)
# |> Vl.encode_field(:y, "people", aggregate: :sum, title: "population", axis: [grid: false])
# |> Vl.encode_field(:x, "gender", title: nil)
# |> Vl.encode_field(:color, "gender")
# |> Vl.config(view: [stroke: nil])
# ── Histograms, density plots and dot plots ── (⎇ from Introduction)
# ### Histogram
# A histogram represents the value frequency in predefined intervals.
# # Source: https://vega.github.io/vega-lite/examples/histogram.html
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/movies.json")
# |> Vl.mark(:bar)
# |> Vl.encode_field(:x, "IMDB Rating", bin: true)
# |> Vl.encode(:y, aggregate: :count)
# ### Density plot
# A density plot represents the distribution estimate of a numeric value.
# # Source: https://vega.github.io/vega-lite/examples/area_density.html
# Vl.new(width: 400, height: 100)
# |> Vl.data_from_url("https://vega.github.io/editor/data/movies.json")
# |> Vl.transform(density: "IMDB Rating")
# |> Vl.mark(:area)
# |> Vl.encode_field(:x, "value", type: :quantitative, title: "IMDB rating")
# |> Vl.encode_field(:y, "density", type: :quantitative)
# ### Stacked density estimates
# Several density plots stacked together.
# # Source: https://vega.github.io/vega-lite/examples/area_density_stacked.html
# Vl.new(width: 400, height: 80)
# |> Vl.data_from_url("https://vega.github.io/editor/data/penguins.json")
# |> Vl.transform(density: "Body Mass (g)", groupby: ["Species"], extent: [2500, 6500])
# |> Vl.mark(:area)
# |> Vl.encode_field(:x, "value", type: :quantitative, title: "Body mass (g)")
# |> Vl.encode_field(:y, "density", type: :quantitative, stack: true)
# |> Vl.encode_field(:color, "Species", type: :nominal)
# ### 2D Histogram scatterplot
# A 2D version of a regular histogram, with intervals in both axis
# and frequency represented by point size.
# # Source: https://vega.github.io/vega-lite/examples/circle_binned.html
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/movies.json")
# |> Vl.mark(:circle)
# |> Vl.encode_field(:x, "IMDB Rating", bin: [maxbins: 10])
# |> Vl.encode_field(:y, "Rotten Tomatoes Rating", bin: [maxbins: 10])
# |> Vl.encode(:size, aggregate: :count)
# ### 2D Histogram heatmap
# Another version of 2D histogram, with color scale representing value frequency.
# # Source: https://vega.github.io/vega-lite/examples/rect_binned_heatmap.html
# Vl.new(width: 300, height: 200)
# |> Vl.data_from_url("https://vega.github.io/editor/data/movies.json")
# |> Vl.transform(
# filter: [
# and: [
# [field: "IMDB Rating", valid: true],
# [field: "Rotten Tomatoes Rating", valid: true]
# ]
# ]
# )
# |> Vl.mark(:rect)
# |> Vl.encode_field(:x, "IMDB Rating", bin: [maxbins: 60])
# |> Vl.encode_field(:y, "Rotten Tomatoes Rating", bin: [maxbins: 40])
# |> Vl.encode(:color, aggregate: :count)
# |> Vl.config(view: [stroke: nil])
# ### 2D Ordinal heatmap
# A heatmap similar to the above, but with already discrete categories.
# # Source: https://vega.github.io/vega-lite/examples/rect_heatmap_weather.html
# Vl.new(title: "Daily max temperatures (C) in Seattle, WA")
# |> Vl.data_from_url("https://vega.github.io/editor/data/seattle-weather.csv")
# |> Vl.mark(:rect)
# |> Vl.encode_field(:x, "date",
# time_unit: :date,
# type: :ordinal,
# title: "Day",
# axis: [label_angle: 0, format: "%e"]
# )
# |> Vl.encode_field(:y, "date",
# time_unit: :month,
# type: :ordinal,
# title: "Month"
# )
# |> Vl.encode_field(:color, "temp_max",
# aggregate: :max,
# type: :quantitative,
# legend: [title: nil]
# )
# |> Vl.config(view: [stroke: nil])
# ── Scatter and strip plots ── (⎇ from Introduction)
# ### Scatterplot
# A scatterplot represents 2D data directly as geometric points.
# # Source: https://vega.github.io/vega-lite/examples/point_2d.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/cars.json")
# |> Vl.mark(:point)
# |> Vl.encode_field(:x, "Horsepower", type: :quantitative)
# |> Vl.encode_field(:y, "Miles_per_Gallon", type: :quantitative)
# ### Strip plot
# Shows the relationship between two values using tick marks.
# # Source: https://vega.github.io/vega-lite/examples/tick_strip.html
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/cars.json")
# |> Vl.mark(:tick)
# |> Vl.encode_field(:x, "Horsepower", type: :quantitative)
# |> Vl.encode_field(:y, "Cylinders", type: :ordinal)
# ### Colored scatterplot
# Scatterplot with clear point groups.
# # Source: https://vega.github.io/vega-lite/examples/point_color_with_shape.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/penguins.json")
# |> Vl.mark(:point)
# |> Vl.encode_field(:x, "Flipper Length (mm)", type: :quantitative, scale: [zero: false])
# |> Vl.encode_field(:y, "Body Mass (g)", type: :quantitative, scale: [zero: false])
# |> Vl.encode_field(:color, "Species", type: :nominal)
# |> Vl.encode_field(:shape, "Species", type: :nominal)
# ── Line charts ── (⎇ from Introduction)
# ### Line chart
# A simple chart resulting from linking individual points.
# # Source: https://vega.github.io/vega-lite/examples/line.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/stocks.csv")
# |> Vl.transform(filter: "datum.symbol == 'GOOG'")
# |> Vl.mark(:line)
# |> Vl.encode_field(:x, "date", type: :temporal)
# |> Vl.encode_field(:y, "price", type: :quantitative)
# ### Multi series line chart
# Multiple line charts combined together.
# # Source: https://vega.github.io/vega-lite/examples/line_color.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/stocks.csv")
# |> Vl.mark(:line)
# |> Vl.encode_field(:x, "date", type: :temporal)
# |> Vl.encode_field(:y, "price", type: :quantitative)
# |> Vl.encode_field(:color, "symbol", type: :nominal)
# ### Line chart with point markers
# Marking individual points on top of the line.
# # Source: https://vega.github.io/vega-lite/examples/line_color.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/stocks.csv")
# |> Vl.mark(:line, point: true)
# |> Vl.encode_field(:x, "date", time_unit: :year, type: :temporal)
# |> Vl.encode_field(:y, "price", aggregate: :mean, type: :quantitative)
# |> Vl.encode_field(:color, "symbol", type: :nominal)
# ### Sequence generators
# Line charts using generated data.
# # Source: https://vega.github.io/vega-lite/examples/sequence_line_fold.html
# Vl.new(width: 300, height: 150)
# |> Vl.data(sequence: [start: 0, stop: 12.7, step: 0.1, as: "x"])
# |> Vl.transform(calculate: "sin(datum.x)", as: "sin(x)")
# |> Vl.transform(calculate: "cos(datum.x)", as: "cos(x)")
# |> Vl.transform(fold: ["sin(x)", "cos(x)"])
# |> Vl.mark(:line)
# |> Vl.encode_field(:x, "x", type: :quantitative)
# |> Vl.encode_field(:y, "value", type: :quantitative)
# |> Vl.encode_field(:color, "key", type: :nominal, title: nil)
# ── Area charts and streamgraphs ── (⎇ from Introduction)
# ### Area chart
# An area chart represents quantitative data and is based on line chart.
# # Source: https://vega.github.io/vega-lite/examples/area.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/unemployment-across-industries.json")
# |> Vl.mark(:area)
# |> Vl.encode_field(:x, "date", time_unit: :yearmonth, axis: [format: "%Y"])
# |> Vl.encode_field(:y, "count", aggregate: :sum, title: "count")
# ### Stacked area chart
# A combination of multiple area charts allowing for easy visual comparison.
# # Source: https://vega.github.io/vega-lite/examples/stacked_area.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/unemployment-across-industries.json")
# |> Vl.mark(:area)
# |> Vl.encode_field(:x, "date", time_unit: :yearmonth, axis: [format: "%Y"])
# |> Vl.encode_field(:y, "count", aggregate: :sum, title: "count")
# |> Vl.encode_field(:color, "series", scale: [scheme: "category20b"])
# ### Streamgraph
# A streamgraph is a type of area chart which is displaced around a central axis.
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/unemployment-across-industries.json")
# |> Vl.mark(:area)
# |> Vl.encode_field(:x, "date", time_unit: :yearmonth, axis: [format: "%Y"])
# |> Vl.encode_field(:y, "count", aggregate: :sum, axis: nil, stack: :center)
# |> Vl.encode_field(:color, "series", scale: [scheme: "category20b"])
# ── Circular plots ── (⎇ from Introduction)
# ### Pie chart
# A pie chart encodes proportional differences among a set of numeric values
# as the angular extent and area of a circular slice.
# data = [
# %{"category" => 1, "value" => 4},
# %{"category" => 2, "value" => 6},
# %{"category" => 3, "value" => 10},
# %{"category" => 4, "value" => 3},
# %{"category" => 5, "value" => 7},
# %{"category" => 6, "value" => 8}
# ]
# Vl.new()
# |> Vl.data_from_values(data)
# |> Vl.mark(:arc)
# |> Vl.encode_field(:theta, "value", type: :quantitative)
# |> Vl.encode_field(:color, "category", type: :nominal)
# |> Vl.config(view: [stroke: nil])
# ### Radial plot
# This radial plot uses both angular and radial extent to convey
# multiple dimensions of data. However, this approach is not perceptually
# effective, as viewers will most likely be drawn to the total area of
# the shape, conflating the two dimensions.
# # Source: https://vega.github.io/vega-lite/examples/arc_radial.html
# Vl.new()
# |> Vl.data_from_values(data: [12, 23, 47, 6, 52, 19])
# |> Vl.encode_field(:theta, "data", type: :quantitative, stack: true)
# |> Vl.encode_field(:radius, "data", scale: [type: :sqrt, zero: true, range_min: 20])
# |> Vl.encode_field(:color, "data", type: :nominal, legend: nil)
# |> Vl.layers([
# Vl.new()
# |> Vl.mark(:arc, inner_radius: 20, stroke: "#fff"),
# Vl.new()
# |> Vl.mark(:text, radius_offset: 10)
# |> Vl.encode_field(:text, "data", type: :quantitative)
# ])
# |> Vl.config(view: [stroke: nil])
# ── Calculations ── (⎇ from Introduction)
# ### Layering rolling averages over raw values
# Raw value points and a calculated rolling average on top.
# # Source: https://vega.github.io/vega-lite/examples/layer_line_rolling_mean_point_raw.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/seattle-weather.csv")
# |> Vl.transform(
# window: [
# [field: "temp_max", op: :mean, as: "rolling_mean"]
# ],
# frame: [-15, 15]
# )
# |> Vl.encode_field(:x, "date", type: :temporal, title: "Date", opacity: 0.3)
# |> Vl.layers([
# Vl.new()
# |> Vl.mark(:point, opacity: 0.3)
# |> Vl.encode_field(:y, "temp_max", type: :quantitative),
# Vl.new()
# |> Vl.mark(:line, color: :red, size: 3)
# |> Vl.encode_field(:y, "rolling_mean",
# type: :quantitative,
# title: "Rolling mean of max temperature"
# )
# ])
# ### Linear regression
# Linear regression is an approach of finding a line that best
# represents the relationship in the data.
# # Source: https://vega.github.io/vega-lite/examples/layer_point_line_regression.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/movies.json")
# |> Vl.layers([
# Vl.new()
# |> Vl.mark(:point, filled: true)
# |> Vl.encode_field(:x, "Rotten Tomatoes Rating", type: :quantitative)
# |> Vl.encode_field(:y, "IMDB Rating", type: :quantitative),
# Vl.new()
# |> Vl.mark(:line, color: :firebrick)
# |> Vl.transform(regression: "IMDB Rating", on: "Rotten Tomatoes Rating")
# |> Vl.encode_field(:x, "Rotten Tomatoes Rating", type: :quantitative)
# |> Vl.encode_field(:y, "IMDB Rating", type: :quantitative)
# ])
# ── Composite marks ── (⎇ from Introduction)
# ### Error bars showing standard deviation
# Adding observations standard deviation alongside the mean point.
# # Source: https://vega.github.io/vega-lite/examples/layer_point_errorbar_ci.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/barley.json")
# |> Vl.encode_field(:y, "variety", type: :ordinal)
# |> Vl.layers([
# Vl.new()
# |> Vl.mark(:point, filled: true)
# |> Vl.encode_field(:x, "yield",
# aggregate: :mean,
# type: :quantitative,
# scale: [zero: false],
# title: "Barley yield"
# )
# |> Vl.encode(:color, value: :black),
# Vl.new()
# |> Vl.mark(:errorbar, extent: :stdev)
# |> Vl.encode_field(:x, "yield", type: :quantitative, title: "Barley yield")
# ])
# ### Line chart with confidence interval band
# Line with confidence band, which represents the uncertainty of an estimate function.
# # Source: https://vega.github.io/vega-lite/examples/layer_line_errorband_ci.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/cars.json")
# |> Vl.encode_field(:x, "Year", time_unit: :year)
# |> Vl.layers([
# Vl.new()
# |> Vl.mark(:errorband, extent: :ci)
# |> Vl.encode_field(:y, "Miles_per_Gallon",
# type: :quantitative,
# title: "Mean of miles per gallon (95% CIs)"
# ),
# Vl.new()
# |> Vl.mark(:line)
# |> Vl.encode_field(:y, "Miles_per_Gallon", aggregate: :mean)
# ])
# ── Box plots ── (⎇ from Introduction)
# ### Box plot with min/max whiskers
# A vertical box plot showing median, min, and max values.
# # Source: https://vega.github.io/vega-lite/examples/boxplot_minmax_2D_vertical.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/penguins.json")
# |> Vl.mark(:boxplot, extent: "min-max")
# |> Vl.encode_field(:x, "Species", type: :nominal)
# |> Vl.encode_field(:color, "Species", type: :nominal, legend: nil)
# |> Vl.encode_field(:y, "Body Mass (g)", type: :quantitative, scale: [zero: false])
# ── Faceting ── (⎇ from Introduction)
# ### Trellis bar chart
# Trellis display is a series of graphs with the same scale and axes
# split according to some criteria, so that they are easy to compare.
# # Source: https://vega.github.io/vega-lite/examples/trellis_bar.html
# Vl.new(width: [step: 17])
# |> Vl.data_from_url("https://vega.github.io/editor/data/population.json")
# |> Vl.transform(filter: "datum.year == 2000")
# |> Vl.transform(calculate: "datum.sex == 2 ? 'Female' : 'Male'", as: "gender")
# |> Vl.mark(:bar)
# |> Vl.encode_field(:row, "gender")
# |> Vl.encode_field(:x, "age")
# |> Vl.encode_field(:y, "people", aggregate: :sum, title: "population")
# |> Vl.encode_field(:color, "gender")
# ### Trellis area chart
# Similar to the above, except for area charts.
# # Source: https://vega.github.io/vega-lite/examples/trellis_area.html
# Vl.new(width: 400, height: 60)
# |> Vl.data_from_url("https://vega.github.io/editor/data/stocks.csv")
# |> Vl.transform(filter: "datum.symbol !== 'GOOG'")
# |> Vl.mark(:area)
# |> Vl.encode_field(:x, "date", type: :temporal, axis: [grid: false])
# |> Vl.encode_field(:y, "price", type: :quantitative, axis: [grid: false])
# |> Vl.encode_field(:color, "symbol", type: :nominal, legend: nil)
# |> Vl.encode_field(:row, "symbol", type: :nominal, title: "Symbol")
# ### Trellis multi-level scatterplot
# Again, the trellis display, but this time for scatterplot
# and grouped data.
# # Source: https://vega.github.io/vega-lite/examples/trellis_barley.html
# Vl.new(name: "Trellis Barley", height: [step: 12])
# |> Vl.data_from_url("https://vega.github.io/editor/data/barley.json")
# |> Vl.mark(:point)
# |> Vl.encode_field(:facet, "site",
# type: :ordinal,
# columns: 2,
# sort: [op: :median, field: "yield"]
# )
# |> Vl.encode_field(:x, "yield", aggregate: :median, type: :quantitative, scale: [zero: false])
# |> Vl.encode_field(:y, "variety", type: :ordinal, sort: "-x")
# |> Vl.encode_field(:color, "year", type: :nominal)
# ── Repeated graphics ── (⎇ from Introduction)
# ### Repeated layer
# A multi-layer chart composed by repeating the same specification over several fields.
# # Source: https://vega.github.io/vega-lite/examples/repeat_layer.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/movies.json")
# |> Vl.repeat(
# [layer: ["US Gross", "Worldwide Gross"]],
# Vl.new()
# |> Vl.mark(:line)
# |> Vl.encode_field(:x, "IMDB Rating", bin: true, type: :quantitative)
# |> Vl.encode_repeat(:y, :layer,
# aggregate: :mean,
# type: :quantitative,
# title: "Mean of US and Worldwide Gross"
# )
# |> Vl.encode(:color, datum: [repeat: :layer], type: :nominal)
# )
# ### Repeated figure
# A multi-view chart composed by repeating the same specification over several fields.
# # Source: https://vega.github.io/vega-lite/docs/repeat.html#repeated-line-charts
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/weather.csv")
# |> Vl.repeat(
# ["temp_max", "precipitation", "wind"],
# Vl.new()
# |> Vl.mark(:line)
# |> Vl.encode_field(:x, "date", time_unit: :month)
# |> Vl.encode_repeat(:y, :repeat, aggregate: :mean)
# |> Vl.encode_field(:color, "location")
# )
# ### Scatterplot Matrix (SPLOM)
# Scatterplot matrix (SPLOM) is a series of graphics for different
# pairs of variables, it's useful to determine possible correlation
# between some variables.
# # Source: https://vega.github.io/vega-lite/docs/repeat.html#scatterplot-matrix-splom
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/penguins.json")
# |> Vl.repeat(
# [
# row: [
# "Beak Length (mm)",
# "Beak Depth (mm)",
# "Flipper Length (mm)",
# "Body Mass (g)"
# ],
# column: [
# "Body Mass (g)",
# "Flipper Length (mm)",
# "Beak Depth (mm)",
# "Beak Length (mm)"
# ]
# ],
# Vl.new(width: 150, height: 150)
# |> Vl.mark(:point)
# |> Vl.encode_repeat(:x, :column, type: :quantitative, scale: [zero: false])
# |> Vl.encode_repeat(:y, :row, type: :quantitative, scale: [zero: false])
# |> Vl.encode_field(:color, "Species", type: :nominal)
# )
# ── Layering ── (⎇ from Introduction)
# ### Layered charts with separate scales
# Layered charts may concern variables of different units and scales,
# in which case we can display the scales separately.
# # Source: https://vega.github.io/vega-lite/docs/layer.html#combined-scales-and-guides
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/weather.csv")
# |> Vl.transform(filter: "datum.location == 'Seattle'")
# |> Vl.encode_field(:x, "date", time_unit: :month, axis: [format: "%b", title: nil])
# |> Vl.layers([
# Vl.new()
# |> Vl.mark(:area, opacity: 0.3, color: "#85C5A6")
# |> Vl.encode_field(:y, "temp_max",
# aggregate: :average,
# scale: [domain: [0, 30]],
# title: "Avg. Temperature (°C)",
# axis: [title_color: "#85C5A6"]
# )
# |> Vl.encode_field(:y2, "temp_min", aggregate: :average),
# Vl.new()
# |> Vl.mark(:line, interpolate: :monotone, stroke: "#85A9C5")
# |> Vl.encode_field(:y, "precipitation",
# aggregate: :average,
# title: "Precipitation (inches)",
# axis: [title_color: "#85A9C5"]
# )
# ])
# |> Vl.resolve(:scale, y: :independent)
# ── Concatenation ── (⎇ from Introduction)
# ### Arbitrary charts
# You can concatenate arbitrary charts, but it's most useful if they concern the same data.
# # Source: https://vega.github.io/vega-lite/examples/vconcat_weather.html
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/weather.csv")
# |> Vl.transform(filter: "datum.location == 'Seattle'")
# |> Vl.concat(
# [
# Vl.new()
# |> Vl.mark(:bar)
# |> Vl.encode_field(:x, "date", time_unit: :month, type: :ordinal)
# |> Vl.encode_field(:y, "precipitation", aggregate: :mean),
# Vl.new()
# |> Vl.mark(:point)
# |> Vl.encode_field(:x, "temp_min", bin: true)
# |> Vl.encode_field(:y, "temp_max", bin: true)
# |> Vl.encode(:size, aggregate: :count)
# ],
# :vertical
# )
# ── Maps (geographic displays) ── (⎇ from Introduction)
# ### Projection
# A cartographic projection allows for mapping longitude and latitude
# pairs to x, y coordinates.
# # Source: https://vega.github.io/vega-lite/docs/projection.html
# Vl.new(width: 500, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/airports.csv")
# |> Vl.projection(type: :albers_usa)
# |> Vl.mark(:circle)
# |> Vl.encode_field(:longitude, "longitude", type: :quantitative)
# |> Vl.encode_field(:latitude, "latitude", type: :quantitative)
# |> Vl.encode(:size, value: 10)
# |> Vl.config(view: [stroke: nil])
# ### Choropleth map
# A Choropleth map is a map composed of colored polygons,
# used to represent spatial variations of a quantity.
# # Source: https://vega.github.io/vega-lite/examples/geo_choropleth.html
# Vl.new(width: 500, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/us-10m.json",
# format: [type: :topojson, feature: "counties"]
# )
# |> Vl.transform(
# lookup: "id",
# from: [
# data: [url: "https://vega.github.io/editor/data/unemployment.tsv"],
# key: "id",
# fields: ["rate"]
# ]
# )
# |> Vl.projection(type: :albers_usa)
# |> Vl.mark(:geoshape)
# |> Vl.encode_field(:color, "rate", type: :quantitative)
# |> Vl.config(view: [stroke: nil])
# ── Interactive graphics ── (⎇ from Introduction)
# ### Overview and detail
# Two charts - one for selecting the range of interest, and the other
# for displaying that specific range.
# # Source: https://vega.github.io/vega-lite/examples/interactive_overview_detail.html
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/sp500.csv")
# |> Vl.concat(
# [
# Vl.new(width: 480)
# |> Vl.mark(:area)
# |> Vl.encode_field(:x, "date",
# type: :temporal,
# scale: [domain: [param: "brush"]],
# axis: [title: nil]
# )
# |> Vl.encode_field(:y, "price", type: :quantitative),
# Vl.new(width: 480, height: 60)
# |> Vl.param("brush", select: [type: :interval, encodings: [:x]])
# |> Vl.mark(:area)
# |> Vl.encode_field(:x, "date", type: :temporal)
# |> Vl.encode_field(:y, "price", type: :quantitative, axis: [tick_count: 3, grid: false])
# ],
# :vertical
# )
# ### Scatterplot with external links and tooltips
# A scatterplot with each point having a tooltip and linking to some page.
# # Source: https://vega.github.io/vega-lite/examples/point_href.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/cars.json")
# |> Vl.transform(
# calculate: "'https://www.google.com/search?q=' + datum.Name",
# as: "url"
# )
# |> Vl.mark(:point)
# |> Vl.encode_field(:x, "Horsepower", type: :quantitative)
# |> Vl.encode_field(:y, "Miles_per_Gallon", type: :quantitative)
# |> Vl.encode_field(:color, "Origin", type: :nominal)
# |> Vl.encode_field(:tooltip, "Name", type: :nominal)
# |> Vl.encode_field(:href, "url", type: :nominal)
# ### Regular brush
# Highlighting points by selecting and dragging a rectangular area.
# # Source: https://vega.github.io/vega-lite/examples/interactive_brush.html
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/cars.json")
# |> Vl.param("brush", select: :interval)
# |> Vl.mark(:point)
# |> Vl.encode_field(:x, "Horsepower", type: :quantitative)
# |> Vl.encode_field(:y, "Miles_per_Gallon", type: :quantitative)
# |> Vl.encode(:color,
# condition: [param: "brush", field: "Cylinders", type: :ordinal],
# value: :gray
# )
# ### Interactive mean
# A brush selection parameterizing the range of data points to calculate mean over.
# # Source: https://vega.github.io/vega-lite/examples/selection_layer_bar_month.html
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/weather.csv")
# |> Vl.transform(filter: "datum.location == 'Seattle'")
# |> Vl.layers([
# Vl.new()
# |> Vl.param("brush", select: [type: :interval, encodings: ["x"]])
# |> Vl.mark(:bar)
# |> Vl.encode_field(:x, "date", time_unit: :month, type: :ordinal)
# |> Vl.encode_field(:y, "precipitation", aggregate: :mean)
# |> Vl.encode(:opacity, value: 0.7, condition: [param: "brush", value: 1]),
# Vl.new()
# |> Vl.transform(filter: [param: "brush"])
# |> Vl.mark(:rule)
# |> Vl.encode_field(:y, "precipitation", aggregate: :mean)
# |> Vl.encode(:color, value: :firebrick)
# |> Vl.encode(:size, value: 3)
# ])
# ### Single point
# Highlighting a single point by clicking on it.
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/cars.json")
# |> Vl.param("pts", select: :point)
# |> Vl.mark(:point)
# |> Vl.encode_field(:x, "Horsepower", type: :quantitative)
# |> Vl.encode_field(:y, "Miles_per_Gallon", type: :quantitative)
# |> Vl.encode(:color,
# condition: [
# param: "pts",
# field: "Cylinders",
# type: :ordinal,
# scale: [scheme: "yelloworangebrown"]
# ],
# value: :gray
# )
# |> Vl.encode(:size, condition: [param: "pts", empty: false, value: 200], value: 50)
# ### Multiple points
# Highlighting a group of matching points by clicking on one of them.
# Vl.new(width: 400, height: 300)
# |> Vl.data_from_url("https://vega.github.io/editor/data/cars.json")
# |> Vl.param("pts", select: [type: :point, fields: ["Cylinders"]])
# |> Vl.mark(:point)
# |> Vl.encode_field(:x, "Horsepower", type: :quantitative)
# |> Vl.encode_field(:y, "Miles_per_Gallon", type: :quantitative)
# |> Vl.encode(:color,
# condition: [
# param: "pts",
# field: "Cylinders",
# type: :ordinal,
# scale: [scheme: "yelloworangebrown"]
# ],
# value: :gray
# )
# |> Vl.encode(:size, condition: [param: "pts", empty: false, value: 200], value: 50)
# ### Map connections
# An interactive visualization of connections between locations on a map.
# # Source: https://vega.github.io/vega-lite/examples/airport_connections.html
# Vl.new(width: 800, height: 500)
# |> Vl.projection(type: :albers_usa)
# |> Vl.layers([
# # Map with regions
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/us-10m.json",
# format: [type: :topojson, feature: "states"]
# )
# |> Vl.mark(:geoshape, fill: "#ddd", stroke: "#fff", stroke_width: 1),
# # Connection lines
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/flights-airport.csv")
# |> Vl.mark(:rule, color: "#000", opacity: 0.35)
# |> Vl.transform(filter: [param: "org", empty: false])
# |> Vl.transform(
# lookup: "origin",
# from: [
# data: [url: "https://vega.github.io/editor/data/airports.csv"],
# key: "iata",
# fields: ["latitude", "longitude"]
# ]
# )
# |> Vl.transform(
# lookup: "destination",
# from: [
# data: [url: "https://vega.github.io/editor/data/airports.csv"],
# key: "iata",
# fields: ["latitude", "longitude"]
# ],
# as: ["latitude2", "longitude2"]
# )
# |> Vl.encode_field(:latitude, "latitude")
# |> Vl.encode_field(:longitude, "longitude")
# |> Vl.encode_field(:latitude2, "latitude2")
# |> Vl.encode_field(:longitude2, "longitude2"),
# # Points
# Vl.new()
# |> Vl.data_from_url("https://vega.github.io/editor/data/flights-airport.csv")
# |> Vl.transform(aggregate: [[op: :count, as: "routes"]], groupby: ["origin"])
# |> Vl.transform(
# lookup: "origin",
# from: [
# data: [url: "https://vega.github.io/editor/data/airports.csv"],
# key: "iata",
# fields: ["state", "latitude", "longitude"]
# ]
# )
# |> Vl.transform(filter: "datum.state !== 'PR' && datum.state !== 'VI'")
# |> Vl.param("org", select: [type: :point, on: :mouseover, nearest: true, fields: ["origin"]])
# |> Vl.mark(:circle)
# |> Vl.encode_field(:latitude, "latitude")
# |> Vl.encode_field(:longitude, "longitude")
# |> Vl.encode_field(:size, "routes", type: :quantitative, scale: [max_range: 1000], legend: nil)
# |> Vl.encode_field(:order, "routes", sort: :descending)
# ])
# |> Vl.config(view: [stroke: nil])