
# Makie.jl

## Backends
Four backends:

1. `CairoMakie` - SVG
2. `GLMakie` - 2D/3D/fast interactivity
3. `WGLMakie` - Same as GLMakie, but in browser
4. `RPRMakie` - experimental raytracing

I will use `GLMakie` or `CairoMakie`. To switch use `CairoMakie.activate!()`

## Standard plotting 

```julia
f = Figure()
x = rand(100)
y = rand(100)

scatter(f[1,1],x,y)
lines(f[1,2],x,y)
hist(f[2,1],x)
density!(f[2,1],x) # inplace -> add to current plot
stem(f[2,2],x)
```

## Layouts for scientific figures

Makie has the best layouting tool I have ever used. [full tutorial here](https://docs.makie.org/stable/tutorials/layout-tutorial/)

```julia
f = Figure()

# we plan to generate two subfigures (with subplots each) - better to generate two "separate" layouts
ga = f[1, 1] = GridLayout()
gb = f[2, 1] = GridLayout()

axtop   = Axis(ga[1,1])
axmain  = Axis(ga[2, 1], xlabel = "before", ylabel = "after")
axright = Axis(ga[2, 2])


labels = ["treatment", "placebo", "control"]
d = randn(3, 100, 2) .+ [1, 3, 5]

for (label, col) in zip(labels, eachslice(d, dims = 1))
    scatter!(axmain, col, label = label)
    density!(axtop, col[:, 1])
    density!(axright, col[:, 2], direction = :y)
end

linkyaxes!(axmain, axright)
linkxaxes!(axmain, axtop)
hidedecorations!(axtop, grid = false)
hidedecorations!(axright, grid = false)

#--- add a legend
leg = Legend(ga[1, 2], axmain)

# absolute size for now :shrug:
leg.width =100
leg.height =100

leg.tellwidth = true
leg.tellheight = true

#----
# second plot
ax,h = heatmap(gb[1,1],rand(100,10),colorrange = [0,1])
ax2,h2 = heatmap(gb[1,2],rand(100,10),colorrange = [0,1])
cb = Colorbar(gb[1,3],h)
cb.alignmode = Mixed(right=0)

#----
# Labels
Label(ga[1, 1, TopLeft()], "A1", font = :bold, padding = (0, 0, 5, 0))
Label(ga[2, 1, TopLeft()], "A2", font = :bold, padding = (0, 0, 5, 0))
Label(ga[2, 2, TopLeft()], "A3", font = :bold, padding = (0, 0, 5, 0))

Label(gb[1, 1, TopLeft()], "B", font = :bold, padding = (0, 0, 5, 0))

#---
# top plot needs more space
rowsize!(f.layout,2,Relative(0.3))

#---
f
```
# Interactivity

With Makie.jl, two ways of interactivity:

**Observables** - very general way, a little bit more verbose

**Pluto.jl Sliders** - very simple, need to redraw plot everytime^[it is technically possible to combine Pluto with Observables, but it is a bit buggy]  


## Pluto.jl

### Installation / Start
```julia
]add Pluto
Pluto.run()
```
::: {.callout-tip}
If you need remote access, run it via `Pluto.run(host="0.0.0.0")`
:::

### Sliders

A slider is defined like this:
```julia
@bind yourVarName PlutoUI.Slider(from:to) # from:step:to is optional, step by def 1
```

if you move the slider, `yourVarName` + all cells that depend on that variable are automatically recalculated. Quick & dirty way to generate an interactive plot

## Bonus: Makie Interactivity

There is another way to get to interactivity. Using `Observables.jl`

To provide a simple example of the logic:
```julia
using GLMakie

x = rand(10_000)
obs_ix = Observable(1) # index to plot until
scatter(@lift(x[1:obs_ix])) # non-interactive example # <1>

f = Figure()
obs_sl = GLMakie.Slider(f[2,1],range=1:length(x))
y = @lift(x[1:$(obs_sl.value)])
ax,s = scatter(f[1,1],y)
xlims!(ax,0,length(x))

```
1. `@lift` does the heavy lifting (hrhr) here. It adds a listener to `obs_ix`, whenever that value is changed, the value of the output of `@lift` is changed as well
## Task 2: Interactivity
[Click here for the next task](tasks.qmd#2)



# Grammar of Graphics

The grammar of graphics is a convenient way to build common explorative plots.

For example:


## For ggplot enthusiasts
You could use [TidierPlots.jl - a ggplot clone](https://github.com/TidierOrg/TidierPlots.jl)

Check out the [AoG/GGplot cheatsheet](../../../../cheatsheets/ggplotAOG.qmd):

## AlgebraOfGraphics.jl

::: callout-note
Checkout [this awesome AOG tutorial](https://tutorials.pumas.ai/html/PlottingInJulia/01-AoG-intro.html)
Really beautifully made!
:::

### Loading data
```julia
using GLMakie # backend
using AlgebraOfGraphics
using PalmerPenguins, DataFrames  # example dataset

penguins = dropmissing(DataFrame(PalmerPenguins.load()))
first(penguins, 6)
``` 

::: callout-note
A `tidy dataframe` is a dataframe that follows these three rules:


1. Every column is a variable.
2. Every row is an observation.
3. Every cell is a single value.

Tidy data make your visualization life much easier as you will see!
:::


### AoG basics


`data * mapping * visual`

```julia
  vis_pen = data(penguins) * mapping(:bill_length_mm, :bill_depth_mm) * visual(Scatter) 
  draw(vis_pen)
```

### Adding color

```julia
vis_pencolor = data(penguins) * mapping(:bill_length_mm, :bill_depth_mm, color = :species) * visual(Scatter)
draw(vis_pencolor)

```
But that is a bit redundant, you can shortcut this, by reusing existing mappings / inputs:
```julia
vis_pencolor2 = vis_pen * mapping(color=:species)
draw(vis_pencolor2)

```

### Why `Algebra`OfGraphics?

Follows some algebraic rules of multiplying out sums

`data * mapping * (visual(Scatter)+visual(Lines))`

```julia

data(penguins) * mapping(:bill_length_mm, :bill_depth_mm) * (visual(Scatter)+visual(Lines)) |> draw
```

### Faceting
```julia
data(penguins) * mapping(:bill_length_mm, :bill_depth_mm)  * mapping(color = :species, col = :sex) |> draw

```
```julia
data(penguins) * mapping(:bill_length_mm, :bill_depth_mm)  * mapping(color = :species, col = :sex,row=:body_mass_g => x-> x>3500) |> draw

```

### Linear & Non-linear summaries
```julia
data(penguins) * mapping(:bill_length_mm, :bill_depth_mm, color=:species) * (linear() + visual(Scatter)) |> draw
```
```julia
data(penguins) * mapping(:bill_length_mm, :bill_depth_mm, color=:species) * (smooth() + visual(Scatter)) |> draw
```

### Advanced

```julia
h = data(penguins) * mapping(:bill_length_mm, :bill_depth_mm, color=:species) * (smooth() + visual(Scatter)) |> draw
h.grid
ax = h.grid[1,1].axis
ax + tab -> ax.xticks
h
```

## Task 3

[Click here for the next task](tasks.qmd#3)

