475 lines
14 KiB
Plaintext
475 lines
14 KiB
Plaintext
---
|
|
engine: julia
|
|
---
|
|
|
|
```{julia}
|
|
#| error: false
|
|
#| echo: false
|
|
#| output: false
|
|
using InteractiveUtils
|
|
```
|
|
|
|
|
|
# Plots and Data Visualization in Julia: _Plots.jl_
|
|
|
|
Julia has numerous graphics packages. Two frequently used ones are [Makie.jl](https://docs.makie.org/stable/) and
|
|
[Plots.jl](https://docs.juliaplots.org/latest/). Before presenting `Plots.jl` in detail, we list some others.
|
|
|
|
## Brief Overview: Some Graphics Packages
|
|
|
|
| Package/Documentation | Tutorial | Examples | Remarks |
|
|
|:----|:--|:--|:--------|
|
|
|[Plots.jl](https://docs.juliaplots.org/latest/) | [Tutorial](https://docs.juliaplots.org/latest/tutorial/) | [Gallery](https://docs.juliaplots.org/latest/gallery/gr/) | designed as a unified interface to various _backends_ (graphics libraries) |
|
|
| [Makie.jl](https://docs.makie.org/stable/) | [Basic tutorial](https://docs.makie.org/v0.21/tutorials/basic-tutorial) | [Beautiful Makie](https://beautiful.makie.org/) | "data visualization ecosystem for Julia", backends: Cairo (vector graphics), OpenGL, WebGL |
|
|
|[PlotlyJS.jl](http://juliaplots.org/PlotlyJS.jl/stable/) | [Getting started](https://plotly.com/julia/getting-started/)| [Examples](https://plotly.com/julia/plotly-fundamentals/)| Interface to the [Plotly](https://plotly.com/graphing-libraries/) JavaScript graphics library |
|
|
| [Gadfly.jl](https://gadflyjl.org/stable/)| [Tutorial](https://gadflyjl.org/stable/tutorial/) | [Gallery](https://github.com/GiovineItalia/Gadfly.jl?tab=readme-ov-file#gallery)| "a plotting and data visualization system written in Julia, influenced by R's [ggplot2](https://ggplot2.tidyverse.org/)" |
|
|
| [Bokeh.jl](https://cjdoris.github.io/Bokeh.jl/stable/) | | [Gallery](https://cjdoris.github.io/Bokeh.jl/stable/gallery/)| Julia frontend for [Bokeh](https://bokeh.org/) |
|
|
|[VegaLite.jl](https://www.queryverse.org/VegaLite.jl/stable/) | [Tutorial](https://www.queryverse.org/VegaLite.jl/stable/gettingstarted/tutorial/)| [Examples](https://www.queryverse.org/VegaLite.jl/stable/examples/examples_barcharts/)| Julia frontend for [Vega-Lite](https://vega.github.io/vega-lite/)|
|
|
| [Luxor.jl](https://juliagraphics.github.io/LuxorManual/stable/) |[Tutorial](https://juliagraphics.github.io/LuxorManual/stable/tutorial/helloworld/)|[Examples](https://juliagraphics.github.io/LuxorManual/stable/example/moreexamples/)| General vector graphics/illustrations |
|
|
| [Javis.jl](https://juliaanimators.github.io/Javis.jl/stable/) |[Tutorials](https://juliaanimators.github.io/Javis.jl/stable/tutorials/)| [Examples](https://juliaanimators.github.io/Javis.jl/stable/examples/)| *Animated* vector graphics
|
|
| [TidierPlots.jl](https://github.com/TidierOrg/TidierPlots.jl)| [Reference](https://tidierorg.github.io/TidierPlots.jl/latest/) || "is a 100% Julia implementation of the R package ggplot2 powered by Makie.jl"|
|
|
|[PythonPlot.jl](https://github.com/JuliaPy/PythonPlot.jl)| |[Examples (in Python)](https://matplotlib.org/stable/gallery/index.html)| Interface to Matplotlib (Python), 1:1 transfer of the Python API, therefore see [Matplotlib documentation](https://matplotlib.org/stable/api/pyplot_summary.html)
|
|
|
|
: {.striped .hover}
|
|
|
|
<!--
|
|
| [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl) | | [Examples](https://gist.github.com/gizmaa/7214002)| Interface to Matplotlib (Python), 1:1 transfer of the Python API, therefore see [Matplotlib documentation](https://matplotlib.org/stable/) |
|
|
-->
|
|
|
|
## Plots.jl
|
|
|
|
### Simple Plots
|
|
|
|
The `plot()` function expects, in the simplest case:
|
|
|
|
- as the first argument a vector of $x$-values of length $n$ and
|
|
- as the second argument a vector of the same length with the corresponding $y$-values.
|
|
- The second argument can also be an $n\times m$ matrix. Each column is treated as a separate graph (called a `series` in the documentation), plotting $m$ curves:
|
|
|
|
|
|
```{julia}
|
|
using Plots
|
|
|
|
x = range(0, 8π; length = 100)
|
|
sx = @. sin(x) # the @. macro broadcasts (vectorizes) every operation
|
|
cx = @. cos(2x^(1/2))
|
|
|
|
plot(x, [sx cx])
|
|
```
|
|
|
|
- Functions like `plot()`, `scatter()`, `contour()`, `heatmap()`, `histogram()`, `bar()`, etc. from _Plots.jl_ all start a new plot.
|
|
- The versions `plot!()`, `scatter!()`, `contour!()`, `heatmap!()`, `histogram!()`, `bar!()`, etc. extend an existing plot:
|
|
|
|
```{julia}
|
|
plot(x, sx) # plot only sin(x)
|
|
plot!(x, cx) # add second graph
|
|
plot!(x, sqrt.(x)) # add a third one
|
|
```
|
|
|
|
Plots are objects that can be assigned. Then they can be used later, copied, and in particular extended with the `!` functions:
|
|
|
|
```{julia}
|
|
plot1 = plot(x, [sx cx])
|
|
plot1a = deepcopy(plot1) # plot objects are quite deep structures
|
|
scatter!(plot1, x, sx) # add scatter plot, i.e. unconnected data points
|
|
```
|
|
|
|
The copied version `plot1a` remains unchanged by the `scatter!` call and can be used independently:
|
|
|
|
```{julia}
|
|
plot!(plot1a, x, 2 .* sx)
|
|
```
|
|
|
|
|
|
|
|
Plot objects can be saved as graphics files (PDF, SVG, PNG, etc.):
|
|
|
|
|
|
```{julia}
|
|
savefig(plot1, "plot.png")
|
|
```
|
|
|
|
|
|
```{julia}
|
|
;ls -l plot.png
|
|
```
|
|
|
|
Plot objects can also be inserted as subplots into other plots, see section @sec-subplot.
|
|
|
|
|
|
|
|
### Function Plots
|
|
|
|
`plot()` can also be passed a function and a vector of $x$-values:
|
|
|
|
```{julia}
|
|
# https://mzrg.com/math/graphs.shtml
|
|
|
|
f(x) = abs(sin(x^x)/2^((x^x-π/2)/π))
|
|
|
|
plot(f, 0:0.01:3)
|
|
```
|
|
|
|
|
|
The parametric form $x = x(t),\ y = y(t)$ is plotted by passing two functions and a vector of $t$-values to `plot()`.
|
|
|
|
```{julia}
|
|
# https://en.wikipedia.org/wiki/Butterfly_curve_(transcendental)
|
|
|
|
xt(t) = sin(t) * (exp(cos(t))-2cos(4t)-sin(t/12)^5)
|
|
yt(t) = cos(t) * (exp(cos(t))-2cos(4t)-sin(t/12)^5)
|
|
|
|
plot(xt, yt, 0:0.01:12π)
|
|
```
|
|
|
|
|
|
### Plot Themes
|
|
|
|
> "PlotThemes is a package to spice up plots made with Plots.jl."\
|
|
See the illustrated [list of themes](https://docs.juliaplots.org/stable/generated/plotthemes/)
|
|
|
|
```{julia}
|
|
using PlotThemes
|
|
|
|
# list of themes
|
|
keys(PlotThemes._themes)
|
|
```
|
|
|
|
```{julia}
|
|
Plots.showtheme(:juno)
|
|
```
|
|
|
|
```{julia}
|
|
using PlotThemes
|
|
|
|
theme(:juno) # set a theme for all further plots
|
|
|
|
plot(x, [sx cx 1 ./ (1 .+ x)])
|
|
```
|
|
|
|
|
|
### Plot Attributes
|
|
|
|
The `Plots.jl` functions have numerous options.
|
|
Attributes are divided into 4 groups:
|
|
|
|
::::{.cell}
|
|
```{julia}
|
|
#| output: asis
|
|
plotattr(:Plot) # attributes for the overall plot
|
|
```
|
|
::::
|
|
|
|
::::{.cell}
|
|
```{julia}
|
|
#| output: asis
|
|
plotattr(:Subplot) # attributes for a subplot
|
|
```
|
|
::::
|
|
|
|
::::{.cell}
|
|
```{julia}
|
|
#| output: asis
|
|
plotattr(:Axis) # attributes for an axis
|
|
```
|
|
::::
|
|
|
|
::::{.cell}
|
|
```{julia}
|
|
#| output: asis
|
|
plotattr(:Series) # attributes for a series, e.g., a line in the plot
|
|
```
|
|
::::
|
|
|
|
You can also query what individual attributes mean and which values are allowed:
|
|
```{julia}
|
|
plotattr("linestyle")
|
|
```
|
|
|
|
|
|
An example:
|
|
```{julia}
|
|
theme(:default) # return to default theme
|
|
|
|
x = 0:0.05:1
|
|
y = sin.(2π*x)
|
|
|
|
plot(x, y, seriestype = :sticks, linewidth = 4, seriescolor = "#00b300",
|
|
marker = :circle, markersize = 8, markercolor = :green,
|
|
)
|
|
```
|
|
|
|
Many specifications can be abbreviated significantly; see, e.g., the `Aliases:` in the output of `plotattr("linestyle")`.
|
|
|
|
The following `plot()` command is equivalent to the previous one:
|
|
|
|
```{julia}
|
|
#| eval: false
|
|
plot(x, y, t = :sticks, w = 4, c = "#00b300", m = (:circle, 8, :green ))
|
|
```
|
|
|
|
|
|
### Additional Extras
|
|
|
|
```{julia}
|
|
using Plots # no harm in repeating
|
|
using Plots.PlotMeasures # for measurements in mm, cm,...
|
|
using LaTeXStrings # for LaTeX constructs in plot labels
|
|
using PlotThemes # predefined themes
|
|
```
|
|
|
|
The `LaTeXStrings.jl` package provides the `L"..."` string constructor. These strings can contain LaTeX constructs, especially formulas. Without explicit dollar signs, they are automatically interpreted in LaTeX math mode.
|
|
|
|
```{julia}
|
|
xs = range(0, 2π, length = 100)
|
|
|
|
data = [sin.(xs) cos.(xs) 2sin.(xs) (x->sin(x^2)).(xs)] # 4 functions
|
|
|
|
theme(:ggplot2)
|
|
|
|
plot10 = plot(xs, data,
|
|
fontfamily="Computer Modern",
|
|
|
|
# LaTeX string L"..."
|
|
title = L"Trigonometric functions $\sin(\alpha), \cos(\alpha), 2\sin(\alpha), \sin(\alpha^2)$",
|
|
xlabel = L"angle $\alpha$",
|
|
ylabel = "value",
|
|
|
|
# 1x4-matrices with colors, markers,... for the 4 'series'
|
|
color=[:black :green RGB(0.3, 0.8, 0.2) :blue ],
|
|
markers = [:rect :circle :utriangle :diamond],
|
|
markersize = [2 1 0 4],
|
|
linewidth = [1 3 1 2],
|
|
linestyle = [:solid :dash :dot :solid ],
|
|
|
|
# axes
|
|
xlim = (0, 6.6),
|
|
ylim = (-2, 2.3),
|
|
yticks = -2:.4:2.3, # with step size
|
|
|
|
# legend
|
|
legend = :bottomleft,
|
|
label = [ L"\sin(\alpha)" L"\cos(\alpha)" L"2\sin(\alpha)" L"\sin(\alpha^2)"],
|
|
|
|
top_margin = 5mm, # here Plots.PlotMeasures is needed
|
|
)
|
|
|
|
# additional text: annotate!(x-pos, y-pos, text("...", font, fontsize))
|
|
|
|
annotate!(plot10, 4.1, 1.8, text("Some remark","Computer Modern", 10) )
|
|
```
|
|
|
|
### Other Plot Functions
|
|
|
|
So far, we have mainly plotted lines. Many other types exist, such as _scatter plots, contours, heatmaps, histograms, sticks_, etc.
|
|
|
|
This can be controlled with the `seriestype` attribute:
|
|
|
|
```{julia}
|
|
theme(:default)
|
|
|
|
x = range(0, 2π; length = 50)
|
|
plot(x, sin.(x), seriestype=:scatter)
|
|
```
|
|
|
|
or by using the specific function named after the `seriestype`:
|
|
```{julia}
|
|
x = range(0, 2π; length = 50)
|
|
scatter(x, sin.(x))
|
|
```
|
|
|
|
|
|
|
|
### Subplots and Layout {#sec-subplot}
|
|
|
|
Multiple plots can be combined into one figure. The arrangement is determined by the `layout` parameter: `layout=(m,n)` arranges plots in an $m\times n$ grid:
|
|
|
|
```{julia}
|
|
x = range(0, 2π; length = 100)
|
|
plots = [] # vector of plot objects
|
|
for f in [sin, cos, tan, sinc]
|
|
p = plot(x, f.(x))
|
|
push!(plots, p)
|
|
end
|
|
plot(plots..., layout=(2,2), legend=false, title=["sin" "cos" "tan" "sinc"])
|
|
```
|
|
|
|
```{julia}
|
|
plot(plots..., layout=(4,1), legend=false, title=["sin" "cos" "tan" "sinc"])
|
|
```
|
|
|
|
|
|
Layouts can also be nested and explicit width/height proportions can be specified using the `@layout` macro:
|
|
|
|
|
|
```{julia}
|
|
mylayout = @layout [
|
|
a{0.3w} [ b
|
|
c{0.2h} ]
|
|
d{0.2h}
|
|
]
|
|
|
|
plot(plots..., layout=mylayout, legend=false, title=["sin" "cos" "tan" "sinc"])
|
|
```
|
|
|
|
|
|
|
|
### Backends
|
|
|
|
`Plots.jl` provides a unified interface to various _backends_ (graphics engines). You can switch backends and use the same plot commands and attributes.
|
|
|
|
However, not all _backends_ support all plot types and attributes. An overview is available [here](https://docs.juliaplots.org/stable/generated/supported/).
|
|
|
|
So far, we have used the default backend: [GR](https://gr-framework.org/about.html), a graphics engine developed at the Jülich Research Center, primarily in C.
|
|
|
|
|
|
```{julia}
|
|
using Plots
|
|
backend() # display the selected backend, GR is the default
|
|
```
|
|
|
|
|
|
Another example:
|
|
```{julia}
|
|
x = 1:30
|
|
y = rand(30)
|
|
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Water level")
|
|
```
|
|
|
|
The same plot with the `PlotlyJS` backend:
|
|
|
|
|
|
```{julia}
|
|
plotlyjs() # change plots backend
|
|
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Water level")
|
|
```
|
|
|
|
This backend enables interactivity via JavaScript. Hovering over the image allows zooming and panning; 3D plots can also be rotated.
|
|
|
|
|
|
```{julia}
|
|
gr() # return to GR as backend
|
|
```
|
|
|
|
|
|
|
|
### 3D Plots
|
|
|
|
The `surface()` and `contour()` functions plot a function $f(x,y)$. Required arguments are:
|
|
|
|
- a set (vector) $X$ of $x$-values,
|
|
- a set (vector) $Y$ of $y$-values and
|
|
- a function of two variables that is then evaluated on $X \times Y$ and plotted.
|
|
|
|
```{julia}
|
|
f(x,y) = (1 - x/2 + x^5 + y^3) * exp(-x^2 - y^2)
|
|
|
|
surface( -3:0.02:3, -3:0.02:3, f)
|
|
```
|
|
|
|
```{julia}
|
|
contour( -3:0.02:3, -3:0.02:3, f, fill=true, colormap=:summer, levels=20, contour_labels=false)
|
|
```
|
|
|
|
Curves (or point sets) in three dimensions are plotted by calling `plot()` with three vectors
|
|
containing the $x$, $y$, and $z$ coordinates of the data points.
|
|
|
|
```{julia}
|
|
plotlyjs()
|
|
|
|
t = range(0, stop=8π, length=100) # parameter t
|
|
x = @. t * cos(t) # x(t), y(t), z(t)
|
|
y = @. 0.1 * t * sin(t)
|
|
z = @. 100 * t/8π
|
|
plot(x, y, z, zcolor=reverse(z), markersize=3, markershape= :circle,
|
|
linewidth=5, legend=false, colorbar=false)
|
|
|
|
```
|
|
|
|
> The `plotlyjs` backend makes the plot interactive: it can be rotated and zoomed with the mouse.
|
|
|
|
### Plots.jl and _recipes_
|
|
|
|
Other packages can extend `Plots.jl` by defining so-called _recipes_ for special plots and data structures (see [https://docs.juliaplots.org/latest/ecosystem/](https://docs.juliaplots.org/latest/ecosystem/)), e.g.:
|
|
|
|
- `StatsPlots.jl`: direct plotting of _DataFrames_, special statistical plots, etc.
|
|
- `GraphRecipes.jl`: [plotting of graph structures](https://docs.juliaplots.org/latest/GraphRecipes/examples/)
|
|
|
|
|
|
### A Bar Chart
|
|
|
|
For the last example, we load a package providing over 700 free (_"public domain"_) datasets, including:
|
|
|
|
- the _Titanic_ passenger list,
|
|
- fuel consumption data for American cars from the 70s, or
|
|
- historical exchange rates:
|
|
|
|
```{julia}
|
|
using RDatasets
|
|
```
|
|
|
|
|
|
```{julia}
|
|
#| error: false
|
|
#| echo: false
|
|
#| output: false
|
|
#RDatasets.datasets()
|
|
```
|
|
|
|
The dataset ["Motor Trend Car Road Tests"](https://rdrr.io/r/datasets/mtcars.html)
|
|
|
|
```{julia}
|
|
cars = dataset("datasets", "mtcars")
|
|
```
|
|
|
|
We only need two columns for the plot: `cars.Model` and `cars.MPG`, the fuel consumption in _miles per gallon_ (higher is more economical).
|
|
|
|
```{julia}
|
|
theme(:bright)
|
|
|
|
bar(cars.Model, cars.MPG,
|
|
label = "Miles/Gallon",
|
|
title = "Models and Miles/Gallon",
|
|
xticks =:all,
|
|
xrotation = 45,
|
|
size = [600, 400],
|
|
legend =:topleft,
|
|
bottom_margin = 10mm
|
|
)
|
|
|
|
```
|
|
|
|
|
|
### What is Missing: Animation
|
|
|
|
See the [documentation](https://docs.juliaplots.org/latest/animations/); here is an example
|
|
(from <https://www.juliafordatascience.com/animations-with-plots-jl/>):
|
|
|
|
```{julia}
|
|
#| error: false
|
|
#| warning: false
|
|
using Plots, Random
|
|
theme(:default)
|
|
|
|
anim = @animate for i in 1:50
|
|
Random.seed!(123)
|
|
scatter(cumsum(randn(i)), ms=i, lab="", alpha = 1 - i/50,
|
|
xlim=(0,50), ylim=(-5, 7))
|
|
end
|
|
|
|
gif(anim, fps=50)
|
|
|
|
```
|
|
|
|
|
|
:::: {.content-visible when-format="typst"}
|
|
```{julia}
|
|
#| echo: false
|
|
Random.seed!(123)
|
|
i = 33
|
|
scatter(cumsum(randn(i)), ms=i, lab="", alpha = 1 - i/50,
|
|
xlim=(0,50), ylim=(-5, 7))
|
|
|
|
```
|
|
::::
|