Plotting text with GLMakie

I am trying to plot text in a GLMakie window.

My code:

    import GLMakie
    fig = GLMakie.Figure(size = (400, 400))
    ax = GLMakie.Axis(fig[1,1])
    GLMakie.text!(0, 20; text="Hello", show_axis = false, fontsize = 30)
    display(GLMakie.Screen(), fig)
    nothing

Simpler, but same behaviour:

    import GLMakie
    fig = GLMakie.text(0, 20; text="Hello", show_axis=false, fontsize = 30)
    display(GLMakie.Screen(), fig)
    nothing

While it prints the text, it also shows an axis which is not what I want.
show_axis = false has no effect.

If I do not create an Axis I get an error message, if I use text instead of text! the text is not getting displayed…

Any idea?

This works:

import GLMakie
fig = GLMakie.Figure(size = (400, 400))
lscene = GLMakie.LScene(fig[1, 1], show_axis=false)
GLMakie.text!(lscene, position =  GLMakie.Point2f( 20, 0), "Hello", fontsize = 30, space=:pixel)
display(GLMakie.Screen(), fig)
nothing

Not very intuitive. Is there any easier solution?

Have you tried Label ?

julia> using GLMakie

julia> fig = Figure()

julia> Label(fig[1,1], "Hello")

image

What does fig[1,1] mean? How can a figure be an array? Is it always an array?
If so, why? If so, of which dimensions?

And yes, I tried Label, but it does not support the keyword arguments position and space…

A Figure contains a GridLayout. Label(fig[1,1],...) tells the Label to use cell (1,1) of the Figures GridLayout. I’d recommend reading through the excellent Makie tutorials:

https://docs.makie.org/stable/tutorials/layout-tutorial/

I was reading the tutorial before. I still don’t find it logical to access array elements without creating an array (with known dimensions) in the first place. This feels like Matlab, you can never get an out-of-bounds error with this scheme, very error prone.

I would find the following syntax much cleaner:

Either

fig=Figure()

if you do not want any grid layout, or

fig=Figure(layout=GridLayout(2,3))

if you want one…

2 Likes

Probably worth a separate topic, but I never understood this choice either. I avoid the figure indexing syntax whenever possible by using AlgebraOfGraphics.jl or direct plotting methods because I get confused every time I see it. Particularly, this statement from the basic tutorial makes no intuitive sense to me:

We’ll learn more about layouts later, but for now the position f[1, 1] will just fill the whole figure.

Well the full GridLayout fills the Figure and it grows on demand. By default it contains only the cell at (1,1).

Personally I find these semantics very convenient for iteratively constructing complicated figures. E.g. if you all of the sudden want another colorbar on the left then you don’t need to shift all subplots over and can just put the colorbar in the 0th column.

2 Likes

Coming back to the original question: Is there an easier solution than this one if you want to display a text in a Makie window and provide the x, y position?

What exactly do you want to achieve? There are many ways to do that, depending on what you’re doing exactly.
Here is one:
https://docs.makie.org/stable/tutorials/scenes/#interaction_with_axis_layouts
You can also use a Scene directly, for a lightweight, low level solution:

scene = Scene()
text!(scene, 20, 0, text="hello")
display(GLMakie.Screen(), scene)

You can also plot into an existing axis/lscene, with e.g. text!(axis, 20, 0, text="hello", space=:pixel)

1 Like

This doesn’t work. The code:

import GLMakie
scene = GLMakie.Scene()
GLMakie.text!(scene, 20, 0, text="hello", fontsize = 30)
display(GLMakie.Screen(), scene)
nothing

just gives a white window, but no text…

OK, this works:

import GLMakie
scene = GLMakie.Scene()
GLMakie.text!(scene, 20, 0, text="hello", fontsize = 30, space=:pixel)
display(GLMakie.Screen(), scene)
nothing

But again, I find it confusing. What is the difference between a Figure and a Scene? How can it be that I can use a Scene instead of a Figure? Why do I need two distinct types if they are interchangeable?

UPDATE:
Scene and Figure are actually NOT interchangeable. In this example I MUST use a Scene and cannot use a Figure. But why?

This also works, and is more logical for me:

import GLMakie
fig = GLMakie.Figure(size = (400, 400))
GLMakie.text!(fig.scene, 20, 0, text="hello", fontsize = 30, space=:pixel)
display(GLMakie.Screen(), fig)

No implicit automatic generation of a Figure in the background…

The design is relatively simple:

A Figure is a Scene plus a GridLayout. You could use a plain Scene for all your drawing in Makie but then you’d have to place all your elements manually where you want them. So the Figure is a Scene that has already been connected to the GridLayout in a way that the layout follows the scene size (think resizing your window in GLMakie). The Figure also has a little bit of a bookkeeping functionality as it holds a vector of Blocks which are just composites of child scenes and plots, but the underlying Scene does not know about that concept at all.

A Figure is not an array, the fig[1, 1] syntax directly forwards to fig.layout[1, 1] which is mostly more annoying to write as you’re going to do this often, and the Figure needs no other indexing behavior, so we made the choice long ago to have one mean the other.

A GridLayout is not an array. The indexing syntax was just the most ergonomic syntax to use. Indexing into it returns an object that describes a position in the layout. It doesn’t yet mutate the layout. Placing an object there by then doing Axis(fig[2, 3]) or whatever does mutate the layout. It does not have a “storage area” like a matrix so there’s no reason not to allow this. It would be very inconvenient when building figures if you had to decide at line 1 how many rows and columns you want to have. You could not make anything iteratively this way.

2 Likes

Thanks for the detailed explanation!

But why is

GLMakie.Label(fig[1,1], text="hello", fontsize = 30)

allowed, but

GLMakie.text!(fig[1,1], 20, 0, text="hello", fontsize = 30, space=:pixel)

is not allowed?

Which commands expect a GridPosition as first parameter, and which commands expect a Scene or LScene?

The documentation is split between Blocks and Plots. Reference · Makie

Blocks like Axis all are layout-aware objects based on Scenes with content that are meant to be rectangular pieces in a Figure. Plots are combinations of Makie’s visual primitives and are meant to live as children of a Scene (when you plot into an Axis you really plot into the child Scene that the Axis owns).

1 Like

I created a pop-up window that shows some statistics about my plots:

Source code: KiteControllers.jl/examples/stats.jl at 2c4eb42a88c16acf71c34c84ad89764b902aa0a2 · aenarete/KiteControllers.jl · GitHub

Thanks for your explanation. But I cannot find this kind of explanation in the documentation.

https://docs.makie.org/stable/explanations/blocks/
https://docs.makie.org/stable/explanations/figure/
https://docs.makie.org/stable/explanations/layouting/
https://docs.makie.org/stable/explanations/scenes/

Yes, a lot of explanations, but not in context, the relation between these four things is not explained, only each on itself. The overview is missing.