From 705915892e8aa548f660c705593dc628be6bf2c6 Mon Sep 17 00:00:00 2001 From: jkrumbiegel <22495855+jkrumbiegel@users.noreply.github.com> Date: Wed, 13 Jan 2021 19:16:19 +0100 Subject: [PATCH] remove old content, make important makielayout things more prominent (#596) --- docs/make.jl | 38 ++--- docs/src/basic-tutorial.md | 2 +- docs/src/convenience.md | 27 ---- docs/src/{troubleshooting.md => faq.md} | 108 ++++++++----- docs/src/figure.md | 142 +++++++++++++++++ docs/src/help_functions.md | 58 ------- docs/src/index.md | 4 +- docs/src/makielayout/faq.md | 60 -------- docs/src/makielayout/laxis.md | 32 ++++ docs/src/makielayout/special_plots.md | 39 ----- docs/src/makielayout/tutorial.md | 196 ++++++++++++------------ docs/src/scenes.md | 21 ++- docs/src_generation/src-axis.md | 47 +++++- src/figures.jl | 5 + 14 files changed, 421 insertions(+), 358 deletions(-) delete mode 100644 docs/src/convenience.md rename docs/src/{troubleshooting.md => faq.md} (50%) create mode 100644 docs/src/figure.md delete mode 100644 docs/src/help_functions.md delete mode 100755 docs/src/makielayout/faq.md delete mode 100644 docs/src/makielayout/special_plots.md diff --git a/docs/make.jl b/docs/make.jl index 78d264e2a..ffa3718aa 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -347,37 +347,33 @@ makedocs( pages = Any[ "Home" => "index.md", "Basics" => [ - "basic-tutorial.md", - "plot_method_signatures.md", + "Basic Tutorial" => "basic-tutorial.md", + "Layout Tutorial" => "makielayout/tutorial.md", "animation.md", "interaction.md", "plotting_functions.md", "theming.md", ], "Documentation" => [ - "scenes.md", - "generated/axis.md", - "convenience.md", - "generated/plot-attributes.md", + "plot_method_signatures.md", + "Figure" => "figure.md", + "Axis" => "makielayout/laxis.md", + "GridLayout" => "makielayout/grids.md", + "Legend" => "makielayout/llegend.md", + "Other Layoutables" => "makielayout/layoutables_examples.md", + "How Layouting Works" => "makielayout/layouting.md", "generated/colors.md", - "lighting.md", - "cameras.md", + "generated/plot-attributes.md", "recipes.md", - "output.md", "backends.md", - "troubleshooting.md", + "output.md", + "scenes.md", + "lighting.md", + "cameras.md", + "faq.md", "API Reference AbstractPlotting" => "abstractplotting_api.md", - ], - "MakieLayout" => [ - "Tutorial" => "makielayout/tutorial.md", - "GridLayout" => "makielayout/grids.md", - "Axis" => "makielayout/laxis.md", - "Special Plots" => "makielayout/special_plots.md", - "Legend" => "makielayout/llegend.md", - "Layoutables Examples" => "makielayout/layoutables_examples.md", - "How Layouting Works" => "makielayout/layouting.md", - "Frequently Asked Questions" => "makielayout/faq.md", - "API Reference" => "makielayout/reference.md", + "API Reference MakieLayout" => "makielayout/reference.md", + "generated/axis.md", ], ], strict = true, # experimental kwarg, so that the docs fail if there are any errors encountered diff --git a/docs/src/basic-tutorial.md b/docs/src/basic-tutorial.md index 6238e665e..6d60d6e57 100644 --- a/docs/src/basic-tutorial.md +++ b/docs/src/basic-tutorial.md @@ -1,4 +1,4 @@ -# Tutorial +# Basic Tutorial Here is a quick tutorial to get you started. We assume you have [Julia](https://julialang.org/) and `GLMakie.jl` (or one of the other backends) installed already. diff --git a/docs/src/convenience.md b/docs/src/convenience.md deleted file mode 100644 index 772ca70fc..000000000 --- a/docs/src/convenience.md +++ /dev/null @@ -1,27 +0,0 @@ -# Convenience functions - -Makie also offers some convenience functions to make manipulating the Axis easier. - -```@docs -xlims! -ylims! -zlims! -xlabel! -ylabel! -zlabel! -xticklabels -yticklabels -zticklabels -xtickrange -ytickrange -ztickrange -xticks! -yticks! -zticks! -xtickrotation -ytickrotation -ztickrotation -xtickrotation! -ytickrotation! -ztickrotation! -``` diff --git a/docs/src/troubleshooting.md b/docs/src/faq.md similarity index 50% rename from docs/src/troubleshooting.md rename to docs/src/faq.md index 7a82a6505..a2f61d526 100644 --- a/docs/src/troubleshooting.md +++ b/docs/src/faq.md @@ -1,48 +1,22 @@ -# Troubleshooting +# Frequently Asked Questions -## Installation issues +## Installation Issues -Here, we assume you are running Julia on the vanilla system image - no PackageCompiler goodness. If you are using `PackageCompiler`, check out the page on compilation. +We assume you are running Julia on the default system image without PackageCompiler. ### No `Scene` displayed or GLMakie fails to build -If `Makie` builds, but when a plotting, no `Scene` is displayed, as in: - -```julia -julia> using Makie - -julia> lines([0,1], [0,1]) -Scene (960px, 540px): -events: - window_area: GeometryTypes.HyperRectangle{2,Int64}([0, 0], [0, 0]) - window_dpi: 100.0 - window_open: false - mousebuttons: Set(AbstractPlotting.Mouse.Button[]) - mouseposition: (0.0, 0.0) - mousedrag: notpressed - scroll: (0.0, 0.0) - keyboardbuttons: Set(AbstractPlotting.Keyboard.Button[]) - unicode_input: Char[] - dropped_files: String[] - hasfocus: false - entered_window: false -plots: - *Axis2D{...} - *Lines{...} -subscenes: - *scene(960px, 540px) -``` - -then, your backend may not have built correctly. By default, Makie will try to use GLMakie as a backend, but if it does not build correctly for whatever reason, then scenes will not be displayed. +If `Makie` builds, but when plotting no window or plot is displayed, your backend may not have built correctly. +By default, Makie will try to use GLMakie as a backend, but if it does not build correctly for whatever reason, then scenes will not be displayed. Ensure that your graphics card supports OpenGL; if it does not (old models, or relatively old integrated graphics cards), then you may want to consider CairoMakie. -# Plotting issues +## Plotting issues -## Dimension too large +### Dimensions too large In general, plotting functions tend to plot whatever's given to them as a single texture. This can lead to GL errors, or OpenGL failing silently. To circumvent this, one can 'tile' the plots (i.e., assemble them piece-by-piece) to decrease the individual texture size. -### 2d plots (heatmaps, images, etc.) +#### 2d plots (heatmaps, images, etc.) ```julia heatmap(rand(Float32, 24900, 26620)) @@ -70,7 +44,7 @@ heatmap!(sc, (size(data, 1)÷2 + 1):size(data, 1), (size(data, 2)÷2 + 1):size(d ``` ![tiled heatmap](https://user-images.githubusercontent.com/32143268/61105143-a3b35780-a496-11e9-83d1-bebe549aa593.png) -### 3d plots (volumes) +#### 3d plots (volumes) The approach here is similar to that for the 2d plots, except that here there is a helpful function that gives the maximum texture size. You can check the maximum texture size with: @@ -112,3 +86,67 @@ If `Makie` can't find your font, you can do two things: - `ENV["FREETYPE_ABSTRACTION_FONT_PATH"] = "/path/to/your/fonts"` 3) Specify the path to the font; instead of `font = "Noto"`, you could write `joindir(homedir(), "Noto.ttf")` or something. + + +## Layout Issues + +```@eval +using CairoMakie +CairoMakie.activate!() +``` + +### Elements are squashed into the lower left corner + +Layoutable elements require a bounding box that they align themselves to. If you +place such an element in a layout, the bounding box is controlled by that layout. +If you forget to put an element in a layout, it will have its default bounding box +of `BBox(0, 100, 0, 100)` which ends up being in the lower left corner. You can +also choose to specify a bounding box manually if you need more control. + +```@example +using CairoMakie + +scene, layout = layoutscene(resolution = (1200, 1200)) + +ax1 = Axis(scene, title = "Squashed") +ax2 = layout[1, 1] = Axis(scene, title = "Placed in Layout") +ax3 = Axis(scene, bbox = BBox(400, 800, 400, 800), + title = "Placed at BBox(400, 800, 400, 800)") + +save("faq_squashed_element.svg", scene); nothing # hide +``` + +![squashed elements](faq_squashed_element.svg) + + +### Columns or rows are shrunk to the size of Text or another element + +Columns or rows that have size `Auto(true)` try to determine the width or height of all +single-spanned elements that are placed in them, and if any elements report their +size the row or column will shrink to the maximum reported size. This is so smaller +elements with a known size take as little space as needed. But if there is other +content in the row that should take more space, you can give the offending element +the attribute `tellheight = false` or `tellwidth = false`. This way, its own size +can be determined automatically, but +it doesn't report it to the row or column of the layout. Alternatively, you can set the size +of that row or column to `Auto(false)` (or any other value than `Auto(true)`). + +```@example +using CairoMakie + +scene, layout = layoutscene(resolution = (1200, 1200)) + +layout[1, 1] = Axis(scene, title = "Shrunk") +layout[2, 1] = Axis(scene, title = "Expanded") +layout[1, 2] = Label(scene, "tellheight = true", tellheight = true) +layout[2, 2] = Label(scene, "tellheight = false", tellheight = false) + +save("faq_shrunk_row.svg", scene); nothing # hide +``` + +![shrunk row](faq_shrunk_row.svg) + +```@eval +using GLMakie +GLMakie.activate!() +``` \ No newline at end of file diff --git a/docs/src/figure.md b/docs/src/figure.md new file mode 100644 index 000000000..82a81f604 --- /dev/null +++ b/docs/src/figure.md @@ -0,0 +1,142 @@ +# Figure + +The `Figure` object contains a top-level `Scene` and a `GridLayout`, as well as a list of layoutables that have been placed into it, like `Axis`, `Colorbar`, `Slider`, `Legend`, etc. + +!!! note + Wherever you see the old `scene, layout = layoutscene()` workflow from MakieLayout, you can imagine that + the `Figure` takes over the role of both `scene` and `layout`, plus additional conveniences like keeping + track of layoutables. + +## Creating A Figure + +You can create a figure explicitly with the `Figure()` function, and set attributes of the underlying scene. +The most important one of which is the `resolution`. + +```julia +f = Figure() +f = Figure(resolution = (600, 400)) +``` + +A figure is also created implicitly when you use simple, non-mutating plotting commands like `plot()`, `scatter()`, `lines()`, etc. +Because these commands also create an axis for the plot to live in and the plot itself, they return a compound object `FigureAxisPlot`, which just stores these three parts. +To access the figure you can either destructure that object into its three parts or access the figure field directly. + +```julia +figureaxisplot = scatter(rand(100, 2)) +figure = figureaxisplot.figure + +# destructuring syntax +figure, axis, plot = scatter(rand(100, 2)) + +# you can also ignore components +figure, _ = scatter(rand(100, 2)) +``` + +You can pass arguments to the created figure in a dict-like object to the special `figure` keyword: + +```julia +scatter(rand(100, 2), figure = (resolution = (600, 400),)) +``` + +## Placing Layoutables Into A Figure + +All layoutables take their parent figure as the first argument, then you can place them in the figure layout +via indexing syntax. + +```julia +f = Figure() +ax = f[1, 1] = Axis(f) +sl = f[2, 1] = Slider(f) +``` + +## FigurePositions and FigureSubpositions + +The indexing syntax of `Figure` is implemented to work seamlessly with layouting. +If you index into the figure, a `FigurePosition` object that stores this indexing operation is created. +This object can be used to plot a new axis into a certain layout position in the figure, for example like this: + +```@example +using GLMakie + +f = Figure() +pos = f[1, 1] +scatter(pos, rand(100, 2)) + +pos2 = f[1, 2] +lines(pos2, cumsum(randn(100))) + +# you don't have to store the position in a variable first, of course +heatmap(f[1, 3], randn(10, 10)) + +f +``` + +You can also index further into a `FigurePosition`, which creates a `FigureSubposition`. +With `FigureSubposition`s you can describe positions in arbitrarily nested grid layouts. +Often, a desired plot layout can only be achieved with nesting, and repeatedly indexing makes this easy. + +```@example +using GLMakie + +f = Figure() +f[1, 1] = Axis(f, title = "I'm not nested") +f[1, 2][1, 1] = Axis(f, title = "I'm nested") +# plotting into nested positions also works +heatmap(f[1, 2][2, 1], randn(20, 20)) +f +``` + +All nested grid layouts that don't exist yet, but are needed for a nested plotting call, are created in the background automatically. + +!!! note + The `GridLayout`s that are implicitly created when using `FigureSubpositions` are not directly available in the return + value for further manipulation. You can instead retrieve them after the fact with the `content` function, for example, + as explained in the following section. + +## Retrieving Objects From A Figure + +Sometimes users are surprised that indexing into a figure does not retrieve the object placed at that position. +This is because the `FigurePosition` is needed for plotting, and returning content objects directly would take +away that possibility. +Furthermore, a `GridLayout` can hold multiple objects at the same position, or have partially overlapping content, +so it's not well-defined what should be returned given a certain index. + +To retrieve objects from a Figure you can instead use indexing plus the `contents` or `content` functions. +The `contents` function returns a Vector of all objects found at the given `FigurePosition`. +You can use the `exact = true` keyword argument so that the position has to match exactly, otherwise objects +contained in that position are also returned. + +```julia +f = Figure() +box = f[1:3, 1:2] = Box(f) +ax = f[1, 1] = Axis(f) + +contents(f[1, 1]) == [ax] +contents(f[1:3, 1:2]) == [box, ax] +contents(f[1:3, 1:2], exact = true) == [box] +``` + +If you use `contents` on a `FigureSubposition`, the `exact` keyword only refers to the lowest-level +grid layout, all upper levels have to match exactly. + +```julia +f = Figure() +ax = f[1, 1][2, 3] = Axis(f) + +contents(f[1, 1][2, 3]) == [ax] +contents(f[1:2, 1:2][2, 3]) == [] # the upper level has to match exactly +``` + +Often, you will expect only one object at a certain position and you want to work directly with it, without +retrieving it from the Vector returned by `contents`. +In that case, use the `content` function instead. +It works equivalently to `only(contents(pos, exact = true))`, so it errors if it can't return exactly one object +from an exact given position. + +```julia +f = Figure() +ax = f[1, 1] = Axis(f) + +contents(f[1, 1]) == [ax] +content(f[1, 1]) == ax +``` \ No newline at end of file diff --git a/docs/src/help_functions.md b/docs/src/help_functions.md deleted file mode 100644 index 61e8cbcf0..000000000 --- a/docs/src/help_functions.md +++ /dev/null @@ -1,58 +0,0 @@ -# Help functions - -## `help` - -```@docs -help -``` - -Example usage: -```@example -using AbstractPlotting # hide -help(scatter; extended = true) -``` - - -## `help_arguments` - -```@docs -help_arguments -``` - -Example usage: -```@example -using AbstractPlotting # hide -help_arguments(stdout, scatter) -``` - -## `help_attributes` - -```@docs -help_attributes -``` - -Example usage: -```@example -using AbstractPlotting # hide -help_attributes(stdout, Scatter; extended = true) -``` - - -# Plot styling options -Use these functions to find out the styling options. - -## `available_marker_symbols` - -```@example -using AbstractPlotting # hide -AbstractPlotting.available_marker_symbols() -``` - -## `available_gradients` - -```@example -using AbstractPlotting # hide -AbstractPlotting.available_gradients() -``` - -For other plot attributes and their usage, see the section [Plot attributes](@ref). diff --git a/docs/src/index.md b/docs/src/index.md index 841610e6f..b69ff550b 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -25,8 +25,8 @@ CairoMakie.activate!() ## First Steps -- Learn the basics of plotting with Makie in the [Tutorial](@ref) -- Check out how to make more complex plots and layouts in the [MakieLayout Tutorial](@ref) +- Learn the basics of plotting with Makie in the [Basic Tutorial](@ref) +- Check out how to make more complex plots and layouts in the [Layout Tutorial](@ref) - See example plots in the [Gallery](http://juliaplots.org/MakieReferenceImages/gallery/index.html). diff --git a/docs/src/makielayout/faq.md b/docs/src/makielayout/faq.md deleted file mode 100755 index 33453b3c9..000000000 --- a/docs/src/makielayout/faq.md +++ /dev/null @@ -1,60 +0,0 @@ -```@eval -using CairoMakie -CairoMakie.activate!() -``` - -## Elements are squashed into the lower left corner - -Layoutable elements require a bounding box that they align themselves to. If you -place such an element in a layout, the bounding box is controlled by that layout. -If you forget to put an element in a layout, it will have its default bounding box -of `BBox(0, 100, 0, 100)` which ends up being in the lower left corner. You can -also choose to specify a bounding box manually if you need more control. - -```@example -using CairoMakie - -scene, layout = layoutscene(resolution = (1200, 1200)) - -ax1 = Axis(scene, title = "Squashed") -ax2 = layout[1, 1] = Axis(scene, title = "Placed in Layout") -ax3 = Axis(scene, bbox = BBox(400, 800, 400, 800), - title = "Placed at BBox(400, 800, 400, 800)") - -save("faq_squashed_element.svg", scene); nothing # hide -``` - -![squashed elements](faq_squashed_element.svg) - - -## Columns or rows are shrunk to the size of Text or another element - -Columns or rows that have size `Auto(true)` try to determine the width or height of all -single-spanned elements that are placed in them, and if any elements report their -size the row or column will shrink to the maximum reported size. This is so smaller -elements with a known size take as little space as needed. But if there is other -content in the row that should take more space, you can give the offending element -the attribute `tellheight = false` or `tellwidth = false`. This way, its own size -can be determined automatically, but -it doesn't report it to the row or column of the layout. Alternatively, you can set the size -of that row or column to `Auto(false)` (or any other value than `Auto(true)`). - -```@example -using CairoMakie - -scene, layout = layoutscene(resolution = (1200, 1200)) - -layout[1, 1] = Axis(scene, title = "Shrunk") -layout[2, 1] = Axis(scene, title = "Expanded") -layout[1, 2] = Label(scene, "tellheight = true", tellheight = true) -layout[2, 2] = Label(scene, "tellheight = false", tellheight = false) - -save("faq_shrunk_row.svg", scene); nothing # hide -``` - -![shrunk row](faq_shrunk_row.svg) - -```@eval -using GLMakie -GLMakie.activate!() -``` \ No newline at end of file diff --git a/docs/src/makielayout/laxis.md b/docs/src/makielayout/laxis.md index 7f30b8521..a7c6f2c51 100755 --- a/docs/src/makielayout/laxis.md +++ b/docs/src/makielayout/laxis.md @@ -459,6 +459,38 @@ Some interactions might have more complex state involving plot objects that need For those purposes, you can overload the methods `registration_setup!(parent, interaction)` and `deregistration_cleanup!(parent, interaction)` which are called during registration and deregistration, respectively. +## Special Plots + +A few special plot functions currently only work specifically with the `Axis` type. + +### Vertical / Horizontal Lines + +Often, it's useful to mark horizontal or vertical locations in a plot with lines that span +a certain percentage of the axis, not the data. There are two functions `hlines!` and `vlines!` +which work with `Axis` instances. + +The positional argument gives one or many locations in data coordinates, while +the keyword arguments `xmin` and `xmax` (for hlines) or `ymin` and `ymax` (for vlines) +specify the extent along the axis. These values can also be a single number or an iterable. + +```@example +using CairoMakie + +scene, layout = layoutscene(resolution = (1400, 900)) +ax1 = layout[1, 1] = Axis(scene, title = "vlines") + +lines!(ax1, 0..4pi, sin) +vlines!(ax1, [pi, 2pi, 3pi], color = :red) + +ax2 = layout[1, 2] = Axis(scene, title = "hlines") +hlines!(ax2, [1, 2, 3, 4], xmax = [0.25, 0.5, 0.75, 1], color = :blue) + +scene +save("example_vlines.svg", scene); nothing # hide +``` + +![example vlines](example_vlines.svg) + ```@eval using GLMakie GLMakie.activate!() diff --git a/docs/src/makielayout/special_plots.md b/docs/src/makielayout/special_plots.md deleted file mode 100644 index bb414feaa..000000000 --- a/docs/src/makielayout/special_plots.md +++ /dev/null @@ -1,39 +0,0 @@ -```@eval -using CairoMakie -CairoMakie.activate!() -``` - -# MakieLayout Special Plots - -## Vertical / Horizontal Lines - -Often, it's useful to mark horizontal or vertical locations in a plot with lines that span -a certain percentage of the axis, not the data. There are two functions `hlines!` and `vlines!` -which work with `Axis` instances. - -The positional argument gives one or many locations in data coordinates, while -the keyword arguments `xmin` and `xmax` (for hlines) or `ymin` and `ymax` (for vlines) -specify the extent along the axis. These values can also be a single number or an iterable. - -```@example -using CairoMakie - -scene, layout = layoutscene(resolution = (1400, 900)) -ax1 = layout[1, 1] = Axis(scene, title = "vlines") - -lines!(ax1, 0..4pi, sin) -vlines!(ax1, [pi, 2pi, 3pi], color = :red) - -ax2 = layout[1, 2] = Axis(scene, title = "hlines") -hlines!(ax2, [1, 2, 3, 4], xmax = [0.25, 0.5, 0.75, 1], color = :blue) - -scene -save("example_vlines.svg", scene); nothing # hide -``` - -![example vlines](example_vlines.svg) - -```@eval -using GLMakie -GLMakie.activate!() -``` \ No newline at end of file diff --git a/docs/src/makielayout/tutorial.md b/docs/src/makielayout/tutorial.md index 95168a1c5..2ed449048 100755 --- a/docs/src/makielayout/tutorial.md +++ b/docs/src/makielayout/tutorial.md @@ -3,56 +3,50 @@ using CairoMakie CairoMakie.activate!() ``` -# MakieLayout Tutorial +# Layout Tutorial -In this tutorial, we will see some of the capabilities of MakieLayout while +In this tutorial, we will see some of the capabilities of layouts in Makie while building a complex figure step by step. This is the final result we will create: ![step_22](step_22.svg) All right, let's get started! -## Scene and Layout +## Creating A Figure -First, we import CairoMakie, which brings in AbstractPlotting and MakieLayout as well. -Then we create the main scene and layout. -The function `layoutscene` is a convenience function that creates a `Scene` -which has a `GridLayout` attached to it that always fills the whole scene area. -You can pass the outer padding of the top layout as the first argument. +First, we import CairoMakie. +Then we create an empty `Figure` which will hold all our content elements and organize them in a layout. ```@example tutorial using CairoMakie using Random # hide Random.seed!(2) # hide -outer_padding = 30 -scene, layout = layoutscene(outer_padding, resolution = (1200, 700), - backgroundcolor = RGBf0(0.98, 0.98, 0.98)) +fig = Figure(resolution = (1200, 700), backgroundcolor = RGBf0(0.98, 0.98, 0.98)) -scene -save("step_001.svg", scene) # hide +fig +save("step_001.svg", fig) # hide nothing # hide ``` ![step_001](step_001.svg) ## First Axis -The scene is completely empty, I have made the background light gray so it's easier -to see. Now we add an Axis. This is an axis or subplot type that MakieLayout defines -which knows how to behave in a layout (which the Makie version doesn't). +The figure is completely empty, I have made the background light gray so it's easier +to see. Now we add an `Axis`. -We create the axis and place it into the layout in one go. You place objects in -a layout by using indexing syntax. You can save the axis in a variable by chaining +We create the axis and place it into the figure's layout in one go. You place objects in +a figure by using indexing syntax. You can save the axis in a variable by chaining the `=` expressions. We call the axis title "Pre Treatment" because we're going to plot some made up measurements, like they could result from an experimental trial. ```@example tutorial -ax1 = layout[1, 1] = Axis(scene, title = "Pre Treatment") +ax1 = fig[1, 1] = Axis(fig, title = "Pre Treatment") -scene -save("step_002.svg", scene) # hide +fig +save("step_002.svg", fig) # hide nothing # hide ``` ![step_002](step_002.svg) @@ -60,8 +54,7 @@ nothing # hide ## Plotting into an Axis We can plot into the axis with the ! versions of Makie's plotting functions. -Contrary to Makie, these calls return the plot objects, not the Scene or Axis, -so it's easier to save them. +Such mutating function calls return the plot object that is created, which we save for later. ```@example tutorial data1 = randn(50, 2) * [1 2.5; 2.5 1] .+ [10 10] @@ -70,8 +63,8 @@ line1 = lines!(ax1, 5..15, x -> x, color = :red, linewidth = 2) scat1 = scatter!(ax1, data1, color = (:red, 0.3), markersize = 15px, marker = '■') -scene -save("step_003.svg", scene) # hide +fig +save("step_003.svg", fig) # hide nothing # hide ``` ![step_003](step_003.svg) @@ -83,17 +76,25 @@ the right of the one we have. Currently our layout has one row and one cell, and only one Axis inside of it: ```@example tutorial -layout +fig.layout ``` -We can extend the grid by indexing into new grid cells. Let's place a new axis -next to the one we have, in row 1 and column 2. +We can extend the grid with a new axis by plotting into a new grid position. Let's place a new axis +with another line plot next to the one we have, in row 1 and column 2. + +We can use the non-mutating plotting syntax and pass a position in our figure as the first argument. +When we index into a figure, we get a `FigurePosition` object which describes the position we want +to put our new axis in. + +The plotting call returns an `AxisPlot` object which we can directly destructure into axis and plot. ```@example tutorial -ax2 = layout[1, 2] = Axis(scene, title = "Post Treatment") +ax2, line2 = lines(fig[1, 2], 7..17, x -> -x + 26, + color = :blue, linewidth = 2, + axis = (title = "Post Treatment",)) -scene -save("step_004.svg", scene) # hide +fig +save("step_004.svg", fig) # hide nothing # hide ``` ![step_004](step_004.svg) @@ -103,22 +104,22 @@ axis on the right. We can take another look at the `layout` to see how it has changed: ```@example tutorial -layout +fig.layout ``` Let's plot into the new axis, the same way we did the scatter plots before. +We can also leave out the axis as the first argument if we just want to plot into +the current axis. ```@example tutorial data2 = randn(50, 2) * [1 -2.5; -2.5 1] .+ [13 13] -line2 = lines!(ax2, 7..17, x -> -x + 26, color = :blue, linewidth = 2) -scat2 = scatter!(ax2, data2, +scat2 = scatter!(data2, color = (:blue, 0.3), markersize = 15px, marker = '▲') - -scene -save("step_005.svg", scene) # hide +fig +save("step_005.svg", fig) # hide nothing # hide ``` ![step_005](step_005.svg) @@ -128,13 +129,14 @@ nothing # hide We want to make the left and right axes correspond to each other, so we can compare the plots more easily. To do that, we link both x and y axes. That will keep them -synchronized. +synchronized. The function `linkaxes!` links both x and y, `linkxaxes!` links only x and +`linkyaxes!` links only y. ```@example tutorial linkaxes!(ax1, ax2) -scene -save("step_006.svg", scene) # hide +fig +save("step_006.svg", fig) # hide nothing # hide ``` ![step_006](step_006.svg) @@ -142,13 +144,13 @@ nothing # hide This looks good, but now both y-axes are the same, so we can hide the right one to make the plot less cluttered. We keep the grid lines, though. You can see that -now that the y-axis is gone, the two LAxes grow to fill the gap. +now that the y-axis is gone, the two Axes grow to fill the gap. ```@example tutorial hideydecorations!(ax2, grid = false) -scene -save("step_007.svg", scene) # hide +fig +save("step_007.svg", fig) # hide nothing # hide ``` ![step_007](step_007.svg) @@ -162,50 +164,50 @@ ax1.xlabel = "Weight [kg]" ax2.xlabel = "Weight [kg]" ax1.ylabel = "Maximum Velocity [m/sec]" -scene -save("step_007_2.svg", scene) # hide +fig +save("step_007_2.svg", fig) # hide nothing # hide ``` ![step_007 2](step_007_2.svg) ## Adding a Legend -Let's add a legend to our plot that describes elements from both axes. We use +Let's add a legend to our figure that describes elements from both axes. We use Legend for that. Legend is a relatively complex object and there are many ways to create it, but here we'll keep it simple. We place the legend on the right again, in row 1 and column 3. Instead of specifying column three, we can also say `end+1`. ```@example tutorial -leg = layout[1, end+1] = Legend(scene, +leg = fig[1, end+1] = Legend(fig, [line1, scat1, line2, scat2], ["f(x) = x", "Data", "f(x) = -x + 26", "Data"]) -scene -save("step_008.svg", scene) # hide +fig +save("step_008.svg", fig) # hide nothing # hide ``` ![step_008](step_008.svg) -You can see one nice feature of MakieLayout here, which is that the legend takes +You can see one nice feature of Makie here, which is that the legend takes much less horizontal space than the two axes. In fact, it takes exactly the space -that it needs. This is possible because objects in MakieLayout can tell their width +that it needs. This is possible because layoutable objects in Makie can tell their width or height to their parent `GridLayout`, which can then shrink the row or column appropriately. One thing that could be better about this plot, is that the legend looks like it belongs only to the right axis, even though it describes elements from both axes. So let's move it in the middle below the two. This is easily possible in -MakieLayout, without having to recreate the plot from scratch. We simply assign +Makie, without having to recreate the plot from scratch. We simply assign the legend to its new slot. We want it in the second row, and spanning the first two columns. ```@example tutorial -layout[2, 1:2] = leg +fig[2, 1:2] = leg -scene -save("step_009.svg", scene) # hide +fig +save("step_009.svg", fig) # hide nothing # hide ``` ![step_009](step_009.svg) @@ -223,10 +225,10 @@ two axes, now that there is no legend shrinking the column width to its own size We can remove empty cells in a layout by calling `trim!` on it: ```@example tutorial -trim!(layout) +trim!(fig.layout) -scene -save("step_010.svg", scene) # hide +fig +save("step_010.svg", fig) # hide nothing # hide ``` ![step_010](step_010.svg) @@ -243,8 +245,8 @@ this behavior. So we set the `tellheight` attribute to `true`. ```@example tutorial leg.tellheight = true -scene -save("step_011.svg", scene) # hide +fig +save("step_011.svg", fig) # hide nothing # hide ``` ![step_011](step_011.svg) @@ -256,14 +258,14 @@ use of space is to change the legend's orientation to `:horizontal`. ```@example tutorial leg.orientation = :horizontal -scene -save("step_012.svg", scene) # hide +fig +save("step_012.svg", fig) # hide nothing # hide ``` ![step_012](step_012.svg) -## Sublayouts +## Nested Layouts Let's add two new axes with heatmaps! We want them stacked on top of each other on the right side of the figure. We'll do the naive thing first, which is to @@ -272,12 +274,12 @@ versions of layout assignment syntax for convenience. Here, we create and assign two axes at once. The number of cells and objects has to match to do this. ```@example tutorial -hm_axes = layout[1:2, 3] = [Axis(scene, title = t) for t in ["Cell Assembly Pre", "Cell Assembly Post"]] +hm_axes = fig[1:2, 3] = [Axis(fig, title = t) for t in ["Cell Assembly Pre", "Cell Assembly Post"]] heatmaps = [heatmap!(ax, i .+ rand(20, 20)) for (i, ax) in enumerate(hm_axes)] -scene -save("step_013.svg", scene) # hide +fig +save("step_013.svg", fig) # hide nothing # hide ``` ![step_013](step_013.svg) @@ -304,14 +306,14 @@ The detaching from the main layout happens automatically. ```@example tutorial hm_sublayout = GridLayout() -layout[1:2, 3] = hm_sublayout +fig[1:2, 3] = hm_sublayout # there is another shortcut for filling a GridLayout vertically with # a vector of content hm_sublayout[:v] = hm_axes -scene -save("step_014.svg", scene) # hide +fig +save("step_014.svg", fig) # hide nothing # hide ``` ![step_014](step_014.svg) @@ -323,8 +325,8 @@ The function `hidedecorations!` hides both x and y decorations at once. hidedecorations!.(hm_axes) -scene -save("step_015.svg", scene) # hide +fig +save("step_015.svg", fig) # hide nothing # hide ``` ![step_015](step_015.svg) @@ -351,10 +353,10 @@ for hm in heatmaps hm.colorrange = (1, 3) end -cbar = hm_sublayout[:, 2] = Colorbar(scene, heatmaps[1], label = "Activity [spikes/sec]") +cbar = hm_sublayout[:, 2] = Colorbar(fig, heatmaps[1], label = "Activity [spikes/sec]") -scene -save("step_016.svg", scene) # hide +fig +save("step_016.svg", fig) # hide nothing # hide ``` ![step_016](step_016.svg) @@ -367,15 +369,15 @@ sublayout. Let's give it a fixed width of 30 units. ```@example tutorial cbar.width = 30 -scene -save("step_017.svg", scene) # hide +fig +save("step_017.svg", fig) # hide nothing # hide ``` ![step_017](step_017.svg) Much better! Note that you can usually set all attributes during creation of an object -(`Colorbar(scene, width = 30)`) or after the fact, like in this example. +(`Colorbar(fig, width = 30)`) or after the fact, like in this example. Objects can also have a width or height relative to the space given to them by their parent `GridLayout`. If we feel that the colorbar is a bit too tall, we can shrink it @@ -387,8 +389,8 @@ If you only specify a number like `30`, it is interpreted as `Fixed(30)`. ```@example tutorial cbar.height = Relative(2/3) -scene -save("step_18.svg", scene) # hide +fig +save("step_18.svg", fig) # hide nothing # hide ``` ![step_18](step_18.svg) @@ -401,8 +403,8 @@ We can set the `ticks` attribute to any iterable of numbers that we want. ```@example tutorial cbar.ticks = 1:0.5:3 -scene -save("step_18b.svg", scene) # hide +fig +save("step_18b.svg", fig) # hide nothing # hide ``` ![step_18b](step_18b.svg) @@ -412,11 +414,11 @@ nothing # hide Now the plot could use a title! While other plotting packages sometimes have functions like `supertitle`, they often don't work quite right or force you to -make manual adjustments. In MakieLayout, the `Label` object is much more flexible +make manual adjustments. In Makie, the `Label` object is much more flexible as it allows you to place text anywhere you want. We therefore create our super title not with a dedicated function but as a simple part of the whole layout. -How can we place content in a row above row 1? This is easy in MakieLayout, as +How can we place content in a row above row 1? This is easy in Makie, as indexing outside of the current GridLayout cells works not only with higher numbers but also with lower numbers. Therefore, we can index into the zero-th row, which will create a new row and push all other content down. @@ -426,11 +428,11 @@ to reflect the new GridLayout size. ```@example tutorial -supertitle = layout[0, :] = Label(scene, "Plotting with MakieLayout", +supertitle = fig[0, :] = Label(fig, "Complex Figures with Makie", textsize = 30, font = "Noto Sans Bold", color = (:black, 0.25)) -scene -save("step_19.svg", scene) # hide +fig +save("step_19.svg", fig) # hide nothing # hide ``` ![step_19](step_19.svg) @@ -442,10 +444,10 @@ In figures meant for publication, you often need to label subplots with letters or numbers. These can sometimes cause trouble because they overlap with other content, which has to be fixed after the fact in vector graphics software. -This is not necessary in MakieLayout. Let's place letters in the upper left corners +This is not necessary in Makie. Let's place letters in the upper left corners of the left group and the right group. To do that, we will make use of a property of layouts that we have used without mentioning it. When we place our letters, we -want them to act similarly to the axis titles or labels. In MakieLayout, layoutable +want them to act similarly to the axis titles or labels. In Makie, layoutable objects have an inner part, which is considered the "important" area that should align with other "important" inner areas. You can see that the three upper axes align with their top spines, and not their titles. @@ -465,13 +467,13 @@ choice. (Remember that our previously first row is now the second row, due to th super title.) ```@example tutorial -label_a = layout[2, 1, TopLeft()] = Label(scene, "A", textsize = 35, +label_a = fig[2, 1, TopLeft()] = Label(fig, "A", textsize = 35, font = "Noto Sans Bold", halign = :right) -label_b = layout[2, 3, TopLeft()] = Label(scene, "B", textsize = 35, +label_b = fig[2, 3, TopLeft()] = Label(fig, "B", textsize = 35, font = "Noto Sans Bold", halign = :right) -scene -save("step_20.svg", scene) # hide +fig +save("step_20.svg", fig) # hide nothing # hide ``` ![step_20](step_20.svg) @@ -488,8 +490,8 @@ is (left, right, bottom, top). label_a.padding = (0, 6, 16, 0) label_b.padding = (0, 6, 16, 0) -scene -save("step_21.svg", scene) # hide +fig +save("step_21.svg", fig) # hide nothing # hide ``` ![step_21](step_21.svg) @@ -513,14 +515,14 @@ because the left two axes will grow to fill the remaining space. colsize!(hm_sublayout, 1, Aspect(1, 1)) -scene -save("step_22.svg", scene) # hide +fig +save("step_22.svg", fig) # hide nothing # hide ``` ![step_22](step_22.svg) And there we have it! Hopefully this tutorial has given you an overview how to -approach the creation of a complex figure in MakieLayout. Check the rest of the +approach the creation of a complex figure in Makie. Check the rest of the documentation for more details and other dynamic parts like sliders and buttons! ```@eval diff --git a/docs/src/scenes.md b/docs/src/scenes.md index bf4907656..8b55f34ac 100644 --- a/docs/src/scenes.md +++ b/docs/src/scenes.md @@ -2,13 +2,16 @@ ## What is a `Scene`? -A `Scene` is basically a container for `Plot`s and other `Scene`s. `Scenes` have `Plot`s (including an `Axis` if `show_axis = true`) and `Subscenes` associated with them. Every Scene has a transformation, made up of _scale_, _translation_, and _rotation_. +`Scene`s are fundamental building blocks of Makie figures. +A Scene is like a container for `Plot`s and other `Scene`s. +`Scenes` have `Plot`s (including an `Axis` if `show_axis = true`) and `Subscenes` associated with them. +Every Scene also has a transformation, made up of _scale_, _translation_, and _rotation_. -Plots associated with a Scene can be accessed through `scene.plots`, which returns an Array of the plots associated with the `Scene`. Note that if `scene` has no plots (if it was created by layouting, or is an empty scene), then `scene.plots` will be a _0-element array_! +!!! note + Before the introduction of the `Figure` workflow, `Scene`s used to be the main container object which was returned from all plotting functions. + Now, scenes are mostly an implementation detail for many users, unless they want to build custom solutions that go beyond what the default system offers. -If a scene is not explicitly declared prior to one of the `plot!` commands being called, a `Scene` will be created by default as follows: `lines(args...) = lines!(Scene(), args...)`. - -In this example, `lines` becomes the parent of all of the following `plot!` commands since it was called prior to a `Scene` being explicitly created. +A Scene's plots can be accessed via `scene.plots`. A Scene's subscenes (also called children) can be accessed through `scene.children`. This will return an Array of the `Scene`'s child scenes. A child scene can be created by `childscene = Scene(parentscene)`. @@ -22,13 +25,7 @@ Any keyword argument given to the `Scene` will be propagated to its plots; there A subscene is no different than a normal Scene, except that it is linked to a "parent" Scene. It inherits the transformations of the parent Scene, but can then be transformed independently of it. - - -## Current Scene - -Knowing what Scene you are working with at any given moment is paramount as you work with more complex Makie implementations containing multiple Scenes. You can check your current scene by doing `AbstractPlotting.current_scene()` which will return the current active scene (the last scene that got created). - -## Modifying the Scene +## Modifying A Scene Makie offers mutation functions to scale, translate and rotate your Scenes on the fly. diff --git a/docs/src_generation/src-axis.md b/docs/src_generation/src-axis.md index 74d6b6ddc..311f57ad8 100644 --- a/docs/src_generation/src-axis.md +++ b/docs/src_generation/src-axis.md @@ -1,12 +1,19 @@ -# OldAxis +# Integrated Axes (Axis2D / Axis3D) -The axis is just a scene object, making it easy to manipulate and share between plots. -OldAxis objects also contains the mapping you want to apply to the data and can interactively be changed. -An OldAxis object can be created from any boundingbox and inserted into any plot. +!!! note + Axis2D refers to the old Makie workflow in which the `Scene` was the main object for + users to interact with. Back then, the default 2D axis was created like a plot object and + therefore had many usability issues that were resolved with the new layout system and the new `Axis` type. + Currently, the 3D axis still uses the old workflow, although you usually embed a scene with a 3D axis + in a layout using the `LScene` wrapper. -There are two types of axes: `Axis2D` and `Axis3D`. +The Axis2D or Axis3D is just a scene object, making it easy to manipulate and share between plots. +These objects also contain the mapping you want to apply to the data and can interactively be changed. +They can be created from any boundingbox and inserted into any plot. -## Interacting with the OldAxis +There are two types of plot-like axes: `Axis2D` and `Axis3D`. + +## Interacting with the integrated axis One can quite easily interact with the attributes of the axis like with any other plot. @@ -23,3 +30,31 @@ You can access the nested attributes in multiple ways. Take the nested attribute 1. `axis[:names, :axisnames] = ("x", "y", "z")` 1. `axis[:names][:axisnames] = ("x", "y", "z")` 1. `axis = (names = (axisnames = ("x", "y", "z"),),)` + +## Convenience functions for integrated axes + +Makie offers some convenience functions to make manipulating the Axis2D / Axis3D easier. + +```@docs +xlims! +ylims! +zlims! +xlabel! +ylabel! +zlabel! +xticklabels +yticklabels +zticklabels +xtickrange +ytickrange +ztickrange +xticks! +yticks! +zticks! +xtickrotation +ytickrotation +ztickrotation +xtickrotation! +ytickrotation! +ztickrotation! +``` diff --git a/src/figures.jl b/src/figures.jl index 7520b2bec..e36422c4c 100644 --- a/src/figures.jl +++ b/src/figures.jl @@ -84,6 +84,11 @@ function Base.setindex!(fig::Figure, obj, rows, cols, side = GridLayoutBase.Inne obj end +function Base.setindex!(fig::Figure, obj::AbstractArray, rows, cols) + fig.layout[rows, cols] = obj + obj +end + Base.lastindex(f::Figure, i) = lastindex(f.layout, i) Base.lastindex(f::FigurePosition, i) = lastindex(f.fig, i)