# Plotting into buffer

**URL:** https://discourse.julialang.org/t/plotting-into-buffer/129641
**Category:** Visualization
**Tags:** makie, cairomakie
**Created:** [June 4, 2025, 1:07pm UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641 "2025-06-04T13:07:31Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [June 4, 2025, 1:07pm UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/1 "2025-06-04T13:07:31Z")

</div>

Is it possible and how to plot into an existing buffer with `Makie.jl` ? My guess is that `Cairomakie.jl` would be the choice, but I can’t find a solution for it.

The reason for this task is, that I want to hand over the buffer to a C library several times.

Here is an example for a 3D plot (from gallery [Beautiful Makie](https://beautiful.makie.org/dev/examples/3d/surfaces/complex_function)) without the buffer:

> ****
>
> ```Julia
> using ImageView
> using CairoMakie
> 
> CairoMakie.activate!()
> x = -2:0.005:2
> y = -2:0.005:2
> f(z) = (z^2 + 1) / (z^2 - 1)
> fvals = [f(u + 1im * v) for u in x, v in y]
> fvalues = abs.(fvals)
> fargs = angle.(fvals)
> indxCut = fvalues .> 3
> fvalues[indxCut] .= 3.01
> fig, ax, pltobj = surface(x, y, fvalues, color = fargs,
> colormap = :roma, colorrange = (-π, π),
> backlight = 1.0f0, highclip = :black,
> figure = (; size = (800, 600), fontsize = 22));
> display(fig)
> imshow(colorbuffer(fig.scene))
> 
> ```

Here is some pseudocode for what I want to do

```Julia
using CairoMakie

CairoMakie.activate!()

buffer=zeros(RGB24, 800, 600)

function draw_into_buffer!(buffer)
	x = -2:0.005:2
	y = -2:0.005:2
	f(z) = (z^2 + 1) / (z^2 - 1)
	fvals = [f(u + 1im * v) for u in x, v in y]
	fvalues = abs.(fvals)
	fargs = angle.(fvals)
	indxCut = fvalues .> 3
	fvalues[indxCut] .= 3.01

	#PSEUDOCODE: plot into existing buffer:
	surface_into_buffer(buffer, x, y, fvalues, color = fargs,
		colormap = :roma, colorrange = (-π, π),
		backlight = 1.0f0, highclip = :black,
		figure = (; size = (1200, 800), fontsize = 22));
end

draw_into_buffer!(buffer);

#provide buffer to some C library as pointer(buffer) 

```

How can I tell CairoMakie to plot into an existing buffer for image pixels?

The prefered idea is not to copy again and again from `colorbuffer(fig.scene)` to `buffer` for performance.

---

<div class="post-metadata">

### Author: ![asinghvi17](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/asinghvi17/32/8272_2.png) [@asinghvi17](https://discourse.julialang.org/u/asinghvi17)
#### Post date: [June 4, 2025, 2:53pm UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/2 "2025-06-04T14:53:55Z")

</div>

You have to go a bit into internals but you can construct a CairoScreen from a CairoARGBSurface that is backed by an array that you create. But the memory layout must be the same.

I can’t send an example now but will try it out in a bit.

---

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [June 4, 2025, 3:22pm UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/3 "2025-06-04T15:22:27Z")

</div>

Thanks a lot, I am waiting for it… I see the idea already but for today I can’t go into my own experiments…

---

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [June 4, 2025, 3:27pm UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/4 "2025-06-04T15:27:31Z")

</div>

```julia
using CairoMakie
using CairoMakie.Colors

sz = (400, 300)
px_per_unit = 2
img = fill(ARGB32(1, 0, 0, 1), ((sz .* px_per_unit) .+ (200, 0))...)
surf = CairoMakie.Cairo.CairoImageSurface(img)

f = Figure(size = sz)
scatter(f[1, 1], cumsum(randn(100)))

conf = Makie.merge_screen_config(CairoMakie.ScreenConfig, Dict(:px_per_unit => px_per_unit))
scr = CairoMakie.Screen(f.scene, conf, surf)
CairoMakie.cairo_draw(scr, f.scene)

save("test.png", img')

```

 ![test](https://global.discourse-cdn.com/julialang/original/3X/b/1/b1cfa06799ad99aa2c69c28f1f31994c3fe70596.png)

The red section on the side is just to visualize that I mutated the original array filled with red

---

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [June 5, 2025, 8:55am UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/5 "2025-06-05T08:55:23Z")

</div>

Thanks for the code.

Yet I am still not happy because the line `CairoMakie.cairo_draw(scr, f.scene)` is so slow, that it doesn’t work very good in my interactive scenario.  
The code I tried now is:

> ****
>
> ```Julia
> using CairoMakie
> using CairoMakie.Colors
> 
> buffer = zeros(UInt32, 800, 600)
> 
> function draw()
> amplitude = 5.0
> sz = (800, 600)
> px_per_unit = 1
> surf = CairoMakie.Cairo.CairoImageSurface(buffer, CairoMakie.Cairo.FORMAT_ARGB32; flipxy=false)
> conf = Makie.merge_screen_config(CairoMakie.ScreenConfig, Dict(:px_per_unit => px_per_unit))
> 
> x = -2:0.005:2
> y = -2:0.005:2
> f(z) = (amplitude/5.0) * (z^2 + 1) / (z^2 - 1)
> fvals = [f(u + 1im * v) for u in x, v in y]
> fvalues = abs.(fvals)
> fargs = angle.(fvals)
> indxCut = fvalues .> 3
> fvalues[indxCut] .= 3.01
> fig, ax, pltobj = surface(x, y, fvalues, color = fargs,
> colormap = :roma, colorrange = (-π, π),
> backlight = 1.0f0, highclip = :black,
> figure = (; size = sz, fontsize = 22));
> 
> resize_to_layout!(fig)
> scr = CairoMakie.Screen(fig.scene, conf, surf)
> CairoMakie.cairo_draw(scr, fig.scene)
> end
> draw()
> 
> ```

The last line in the `draw()` function, `CairoMakie.cairo_draw(scr, fig.scene)`, uses several seconds, which makes interactivity very annoying.

In general it is working quite well: the `buffer` can be passed to the C library and it shows up correctly.

Perhaps `CairoMakie` wasn’t the best choice for a Julia plotting library to plot a 3d function into an existing buffer. What I additionally need is fast rendering into the buffer.

Any suggestions?

---

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [June 5, 2025, 10:10am UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/6 "2025-06-05T10:10:12Z")

</div>

Ah yeah that’s because 3D mesh drawing is the weak point in Cairo, and you’re doing a fairly detailed surface with 640k vertices. Not sure if @sdanisch has a good idea how to do this with GLMakie. But the buffer would be on the GPU there, so a copy would have to be made, whether into an existing buffer or as a separate array like `colorbuffer` does it. I don’t think OpenGL would draw directly into a RAM buffer.

---

<div class="post-metadata">

### Author: ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)
#### Post date: [June 5, 2025, 10:21am UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/7 "2025-06-05T10:21:54Z")

</div>

In GLMakie we already draw in a pre-allocated frame cache, which I guess you could just use?

> <https://github.com/MakieOrg/Makie.jl/blob/master/GLMakie/src/screen.jl#L890>

---

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [June 5, 2025, 10:42am UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/8 "2025-06-05T10:42:34Z")

</div>

Thanks, will try…

---

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [June 5, 2025, 2:49pm UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/9 "2025-06-05T14:49:09Z")

</div>

Something is not as expected.  
The plot renders nicely but the framecache is not the full picture:

```julia
using GLMakie
using GLMakie.Colors

amplitude = 5.0
sz = (800, 600)
px_per_unit = 1

x = -2:0.005:2
y = -2:0.005:2
f(z) = (amplitude/5.0) * (z^2 + 1) / (z^2 - 1)
fvals = [f(u + 1im * v) for u in x, v in y]
fvalues = abs.(fvals)
fargs = angle.(fvals)
indxCut = fvalues .> 3
fvalues[indxCut] .= 3.01
fig, ax, pltobj = surface(x, y, fvalues, color = fargs,
	colormap = :roma, colorrange = (-π, π),
	backlight = 1.0f0, highclip = :black,
	figure = (; size = sz, fontsize = 22));

resize_to_layout!(fig)

scr = GLMakie.Screen(fig.scene);

```

```julia
julia> scr.framecache
10×10 Matrix{RGB{FixedPointNumbers.N0f8}}:
 RGB(0.004, 0.0, 0.0) RGB(0.0, 0.0, 0.02) RGB(0.0, 0.0, 0.0) ...
...

```

Perhaps `scr.framebuffer` can be used, but it’s a more complex structure so I can’t see how?

For those late in the thread:  
How to repeatedly plot (e.g. a nice 3D function) directly into a (predefined) buffer with good performance without displaying the plot? The raw buffer is repeatedly passed to a C library.

---

<div class="post-metadata">

### Author: ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)
#### Post date: [June 5, 2025, 5:48pm UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/10 "2025-06-05T17:48:34Z")

</div>

It only gets filled when calling `colorbuffer(screen)` .  
You can call that or exctract the relevant bits from the linked source!

---

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [June 6, 2025, 5:57pm UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/11 "2025-06-06T17:57:47Z")

</div>

Thanks for all your efforts, but I have trouble doing what I want with Makie:

**CairoMakie** : `CairoMakie.cairo_draw` needs several seconds =\> bad interactivity.

**GLMakie** : `colorbuffer` and `GLMakie.Screen` stalls, probably because the C GUI library uses OpenGL too.

**WGLMakie** : can’t get the pixel buffer without showing the plot, a browser screen must be open.

---

<div class="post-metadata">

### Author: ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)
#### Post date: [June 7, 2025, 6:32am UTC](https://discourse.julialang.org/t/plotting-into-buffer/129641/12 "2025-06-07T06:32:52Z")

</div>

yeah that will be a problem.  
If it uses OpenGL as well, there should be other ways though.  
You could look at the clmgui Makie integration:

> **[Makie integration · CImGui.jl](https://juliaimgui.github.io/ImGuiDocs.jl/cimgui/stable/makie/)**
>
> Documentation for CImGui.jl.
