---
engine: julia
---

```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
```


# Plots and Data Visualization in Julia: _Plots.jl_

There are numerous graphics packages for Julia. Two frequently used ones are [Makie.jl](https://docs.makie.org/stable/) and
[Plots.jl](https://docs.juliaplots.org/latest/). Before presenting these in more detail, some other packages are listed.

## 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://goropikari.github.io/PlotsGallery.jl/) |  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](http://juliagraphics.github.io/Luxor.jl/stable/) |[Tutorial](https://juliagraphics.github.io/Luxor.jl/stable/tutorial/helloworld/)|[Examples](https://juliagraphics.github.io/Luxor.jl/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. Then each column vector is regarded as a separate graph (called `series` in the documentation) and $m$ curves are plotted:


```{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])
```

- The functions of the _Plots.jl_ package such as `plot(), scatter(), contour(), heatmap(), histogram(), bar(),...` etc. all start a new plot.
- The versions `plot!(), scatter!(), contour!(), heatmap!(), histogram!(), bar!(),...` 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` has not been modified by the `scatter!` statement and can be used independently:

```{julia}
plot!(plot1a, x, 2 .* sx)   
```



Plot objects can be saved as graphics files (PDF, SVG, PNG,...):


```{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)$ can be drawn 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 the plots made with Plots.jl."\
  Here is the illustrated [list of themes](https://docs.juliaplots.org/stable/generated/plotthemes/)

or:
```{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 functions of the `Plots.jl` package have a large number of options. 
`Plots.jl` divides the attributes 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
```
::::

One can also ask what the 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 also be abbreviated significantly, see e.g. the `Aliases:` in the above output of the command `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                # repetition does not hurt
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 a string constructor `L"..."`. These strings can contain LaTeX constructs, especially formulas. If the string does not contain explicit dollar signs, it is 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"Winkelfunktionen $\sin(\alpha), \cos(\alpha), 2\sin(\alpha), \sin(\alpha^2)$",
           xlabel = L"Winkel $\alpha$",
           ylabel = "Funktionswert", 
    
           # 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("nicht schön, aber viel","Computer Modern", 10) )
```

### Other Plot Functions

So far, we have plotted mainly lines. There are many other types such as _scatter plot, contour, heatmap, histogram, stick,..._ 

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)` means that the plots are arranged in an $m\times n$ scheme:

```{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` is designed as a unified interface to various _backends_ (graphics engines). One can switch to another backend 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, the default backend has been used. It is called [GR](https://gr-framework.org/about.html) and is a graphics engine developed at the Jülich Research Center and written 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 = "Wasserstand")
```

and here the same plot with the `PlotlyJS` backend. 


```{julia}
plotlyjs()       # change plots backend
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Wasserstand")
```

This backend enables a certain interactivity using JavaScript. When moving the mouse into the image, one can zoom and pan with the mouse, and 3D plots can also be rotated. 


```{julia}
gr() # return to GR as backend
```



### 3D Plots

The functions `surface()` and `contour()` allow plotting of a function $f(x,y)$. The 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 simply point sets) in three dimensions can be plotted by calling `plot()` with 3 vectors 
containing the $x$, $y$ and $z$-coordinates of the data points, respectively. 

```{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)

```

> We use the `plotlyjs` backend here, so the plot is interactive and can be rotated and zoomed with the mouse.

### Plots.jl and _recipes_

Other packages can extend the capabilities of `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. or 
- `GraphRecipes.jl` [Plotting of graph structures](https://docs.juliaplots.org/latest/GraphRecipes/examples/)


### A Bar Chart

For the last example, we load a package that provides over 700 free (_"public domain"_) datasets, including, for example:

 - the passenger list of the _Titanic_, 
 - fuel consumption data of American cars from the 70s  or
 - historical exchange rates

provides:

```{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 the two columns `cars.Model` and `cars.MPG` for the plot, the fuel consumption in _miles per gallon_ (more means 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 

Please refer to the [documentation](https://docs.juliaplots.org/latest/animations/) and only an example 
(from <https://www.juliafordatascience.com/animations-with-plots-jl/>) is given:

```{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="pdf"}
```{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))

```
::::
