---
engine: julia
---

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


# Plots und Datenvisualisierung in Julia: _Plots.jl_

Es gibt zahlreiche Grafikpakete für Julia. Zwei oft genutzte sind [Makie.jl](https://docs.makie.org/stable/) und
[Plots.jl](https://docs.juliaplots.org/latest/). Bevor wir diese genauer  vorstellen, seien noch einige andere Pakete aufgelistet.

## Kurze Übersicht: einige Grafikpakete

| Paket/Doku | Tutorial | Beispiele | Bemerkungen |
|:----|:--|:--|:--------|
|[Plots.jl](https://docs.juliaplots.org/latest/) | [Tutorial](https://docs.juliaplots.org/latest/tutorial/)  | [Galerie](https://goropikari.github.io/PlotsGallery.jl/) |  konzipiert als einheitliches Interface zu verschiedenen _backends_ (Grafikbibliotheken) |
| [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 (Vektorgrafik), 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 zur [Plotly](https://plotly.com/graphing-libraries/) Javascript-Grafikbibliothek |
| [Gadfly.jl](https://gadflyjl.org/stable/)| [Tutorial](https://gadflyjl.org/stable/tutorial/) | [Galerie](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/) | | [Galerie](https://cjdoris.github.io/Bokeh.jl/stable/gallery/)| Julia-Frontend für [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 für [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/)| Allgemeine Vektorgrafik/Illustrationen | 
| [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/)| *Animierte* Vektorgrafik
| [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"|
| [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl) | | [Examples](https://gist.github.com/gizmaa/7214002)| Interface zu Matplotlib (Python),  1:1-Übertragung der Python-API, deswegen s. [Matplotlib-Dokumentation](https://matplotlib.org/stable/) |

: {.striped .hover}



## Plots.jl

### Einfache Plots 

Die `plot()`-Funktion erwartet im einfachsten Fall: 

- als erstes Argument einen Vektor von $x$-Werten der Länge $n$ und 
- als zweites Argument einen gleichlangen Vektor mit den dazugehörigen $y$-Werten.
- Das zweite Argument kann auch eine $n\times m$-Matrix sein. Dann wird jeder Spaltenvektor als eigener Graph (in der Docu `series` genannt) angesehen und es werden $m$ Kurven geplottet:


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

- Die Funktionen des _Plots.jl_-Paketes wie `plot(), scatter(), contour(), heatmap(), histogram(), bar(),...` usw. starten alle einen neuen Plot.
- Die Versionen `plot!(), scatter!(), contour!(), heatmap!(), histogram!(), bar!(),...`  erweitern einen existierenden Plot:

```{julia}
plot(x, sx)          # plot only sin(x)
plot!(x, cx)         # add second graph
plot!(x, sqrt.(x))   # add a thirth one
```

Plots sind Objekte, die zugewiesen werden können. Dann kann man sie später weiterverwenden, kopieren und insbesondere mit den `!`-Funktionen erweitern:

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

Die kopierte Version `plot1a` ist durch die `scatter!`-Anweisung nicht modifiziert worden und kann unabhängig weiterverwendet werden:

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



Plot-Objekte kann man als Grafikdateien (PDF, SVG, PNG,...) abspeichern:


```{julia}
savefig(plot1, "plot.png")
```


```{julia}
;ls -l plot.png
```

Plot-Objekte können auch als Teilplot in andere Plots eingefügt werden, siehe Abschnitt @sec-subplot.


### Plot-Themen

> "PlotThemes is a package to spice up the plots made with Plots.jl."\
  Hier geht es zur illustrierten [Liste der Themen](https://docs.juliaplots.org/stable/generated/plotthemes/)

oder:
```{julia}
using PlotThemes

# Liste der Themen
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-Attribute

Die Funktionen des `Plots.jl`-Paketes haben eine große Anzahl von Optionen. 
`Plots.jl` teilt die Attribute in 4 Gruppen ein:

::::{.cell}
```{julia}
#| output: asis 
plotattr(:Plot)  # Attribute für den Gesamtplot
```
::::

::::{.cell}
```{julia}
#| output: asis
plotattr(:Subplot) # Attribute für einen Teilplot
```
::::

::::{.cell}
```{julia}
#| output: asis
plotattr(:Axis)  # Attribute für eine Achse
```
::::

::::{.cell}
```{julia}
#| output: asis
plotattr(:Series) # Attribute für eine Serie, also zB ein Linienzug im Plot
```
::::

Man kann auch nachfragen, was die einzelnen Attribute bedeuten und welche Werte zulässig sind:
```{julia}
plotattr("linestyle")
```


Ein Beispiel:
```{julia}
theme(:default)  # zurück zum Standardthema 

x = 0:0.05:1
y = sin.(2π*x)

plot(x, y, seriestype = :sticks, linewidth = 4, seriescolor = "#00b300",
        marker = :circle, markersize = 8, markercolor = :green,
)
```

Viele Angaben können auch sehr weit abgekürzt werden, siehe z.B. die Angabe `Aliases:` in der obigen Ausgabe des Kommandos `plotattr("linestyle")`.

Das folgende `plot()`-Kommando is äquivalent zum vorherigen:

```{julia}
#| eval: false
plot(x, y, t = :sticks, w = 4, c = "#00b300", m = (:circle, 8, :green ))
```


### Weitere Extras

```{julia}
using Plots                # Wiederholung schadet nicht
using Plots.PlotMeasures   # für Maßangaben in mm, cm,...
using LaTeXStrings         # für LaTeX-Konstrukte in Plot-Beschriftungen
using PlotThemes           # vorgefertigte Themen
```

Das Paket `LaTeXStrings.jl` stellt einen String-Konstruktor `L"..."` zur Verfügung. Diese Strings können LaTeX-Konstrukte, insbesondere Formeln, enthalten. Wenn der String keine expliziten Dollarzeichen enthält, wird er automatisch im LaTeX-Math-Modus interpretiert.  

```{julia}
xs = range(0, 2π, length = 100)

data = [sin.(xs) cos.(xs) 2sin.(xs) (x->sin(x^2)).(xs)]   # 4 Funktionen

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-Matrizen mit Farben, Marker,...  für die 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 ],
           
           # Achsen
           xlim = (0, 6.6),
           ylim = (-2, 2.3),
           yticks = -2:.4:2.3,       # mit Schrittweite
           
           # Legende 
           legend = :bottomleft,
           label = [ L"\sin(\alpha)" L"\cos(\alpha)" L"2\sin(\alpha)"  L"\sin(\alpha^2)"],
    
           top_margin = 5mm,     # hier wird Plots.PlotMeasures gebraucht
)

# Zusatztext:  annotate!(x-pos, y-pos, text("...", font, fontsize))

annotate!(plot10, 4.1, 1.8, text("nicht schön, aber viel","Computer Modern", 10) )
```

### Andere Plot-Funktionen

Bisher haben wir vor allem Linien geplottet. Es gibt noch viele andere Typen wie  _scatter plot, contour, heatmap, histogram, stick,..._ 

Dies kann man mit dem `seriestype`-Attribut steuern:

```{julia}
theme(:default)

x = range(0, 2π; length = 50)
plot(x, sin.(x), seriestype=:scatter)
```

oder indem man die spezielle Funktion benutzt, die so heißt wie der `seriestype`:
```{julia}
x = range(0, 2π; length = 50)
scatter(x, sin.(x))
```



### Subplots und Layout   {#sec-subplot}

Mehrere Plots können zu einer Abbildung zusammengefasst werden. Die Anordnung bestimmt der `layout`-Parameter. Dabei bedeutet `layout=(m,n)`, dass die Plots in einem $m\times n$-Schema angeordnet werden:

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


Man kann Layouts auch schachteln und mit dem `@layout`-Macro explizite Breiten/Höhenanteile vorgeben:


```{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` ist konzipiert als ein einheitliches Interface zu verschiedenen _backends_ (Grafik-Engines). Man kann zu einem anderen  Backend wechseln und dieselben Plot-Kommandos und -Attribute verwenden.

Allerdings unterstützen nicht alle _backends_ alle Plot-Typen und -Attribute. Einen Überblick gibt es [hier](https://docs.juliaplots.org/stable/generated/supported/).

Bisher wurde das Standard-Backend verwendet. Es heißt [GR](https://gr-framework.org/about.html) und ist eine am Forschungszentrum Jülich entwickelte und hauptsächlich in C geschriebene Grafik-Engine. 


```{julia}
using Plots
backend()      # Anzeige des gewählten backends, GR ist der default
```


Nochmal ein Beispiel 
```{julia}
x = 1:30
y = rand(30)
plot(x, y, linecolor =:green, bg_inside =:lightblue1, line =:solid, label = "Wasserstand")
```

und hier derselbe Plot mit dem `PlotlyJS`-Backend. 


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

Dieses Backend ermöglich mit Hilfe von Javascript eine gewisse Interaktivität. Wenn man die Maus in das Bild bewegt, kann man mit der Maus zoomen, verschieben und 3D-Plots auch drehen. 


```{julia}
gr() # zurück zu GR als backend
```



### 3D Plots

Die Funktionen `surface()` und `contour()` ermöglichen den Plot einer Funktion $f(x,y)$. Als Argumente werden benötigt:

- eine Menge (Vektor) $X$ von $x$-Werten,
- eine Menge (Vektor) $Y$ von $y$-Werten und
- eine Funktion von zwei Variablen, die dann auf $X \times Y$ ausgewertet und geplottet wird.

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

Kurven (oder auch einfach Punktmengen) in drei Dimensionen lassen sich plotten, indem man `plot()` mit 3 Vektoren 
aufruft, die jeweils die $x$, $y$ und $z$-Koordinaten der Datenpunkte enthalten. 

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

```

> Wir verwenden mal das `plotlyjs`-Backend, damit ist der Plot interaktiv und kann mit der Maus gedreht und gezoomt werden.

### Plots.jl und _recipes_

Andere Pakete können die Möglichkeiten von `Plots.jl` erweitern, indem sie sogenannte  _recipes_ für spezielle Plots und Datenstrukturen definieren, siehe [https://docs.juliaplots.org/latest/ecosystem/](https://docs.juliaplots.org/latest/ecosystem/), z.B.:

- `StatsPlots.jl` direktes Plotten von _Dataframes_, spezielle statistische Plots usw. oder 
- `GraphRecipes.jl`  [Plotten von Graphstrukturen](https://docs.juliaplots.org/latest/GraphRecipes/examples/)


### Ein Säulendiagramm

Für das letzte Beispiel laden wir ein Paket, das über 700 freie (_"public domain"_) Datensätze, darunter z.B:

 - die Passagierliste der _Titanic_, 
 - Verbrauchsdaten amerikanischer Autos aus den 70ern  oder
 - historische Währungskurse

bereitstellt:

```{julia}
using RDatasets
```


```{julia}
#| error: false
#| echo: false
#| output: false
#RDatasets.datasets()
```

Der Datensatz ["Motor Trend Car Road Tests"](https://rdrr.io/r/datasets/mtcars.html) 

```{julia}
cars = dataset("datasets", "mtcars")
```

Wir brauchen für den Plot nur die beiden Spalten `cars.Model` und `cars.MPG`, den Benzinverbrauch in _miles per gallon_ (Mehr heißt sparsamer!) 

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

```

