# 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 + Smart 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])