Skip to content

Commit

Permalink
better colorbuffer, fix record + window hiding when using save (#3078)
Browse files Browse the repository at this point in the history
* fix issues with saving + record

* add colorbuffer for axis + subscenes

* fixes + tests

* add news entry
  • Loading branch information
SimonDanisch authored Jul 21, 2023
1 parent 7997b50 commit da4414c
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 11 deletions.
9 changes: 7 additions & 2 deletions GLMakie/src/screen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,6 @@ function apply_config!(screen::Screen, config::ScreenConfig; start_renderloop::B
replace_processor!(config.fxaa ? fxaa_postprocessor : empty_postprocessor, 3)
# Set the config
screen.config = config

if start_renderloop
start_renderloop!(screen)
else
Expand Down Expand Up @@ -688,7 +687,13 @@ function Makie.colorbuffer(screen::Screen, format::Makie.ImageStorageFormat = Ma
# GLFW.PollEvents()
# keep current buffer size to allows larger-than-window renders
render_frame(screen, resize_buffers=false) # let it render
glFinish() # block until opengl is done rendering
if screen.config.visible
GLFW.SwapBuffers(to_native(screen))
else
# SwapBuffers blocks as well, but if we don't call that
# We need to call glFinish to wait for all OpenGL changes to finish
glFinish()
end
if size(ctex) != size(screen.framecache)
screen.framecache = Matrix{RGB{N0f8}}(undef, size(ctex))
end
Expand Down
7 changes: 4 additions & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

## master

- Exported colorbuffer, and added `colorbuffer(axis::Axis; include_decorations=false, colorbuffer_kws...)`, to get an image of an axis with or without decorations [#3078](https://github.com/MakieOrg/Makie.jl/pull/3078).
- Fixed an issue where the `linestyle` of some polys was not applied to the stroke in CairoMakie. [#2604](https://github.com/MakieOrg/Makie.jl/pull/2604)
- Add `colorscale = identity` to any plotting function using a colormap. This works with any scaling function like `log10`, `sqrt` etc. Consequently, `scale` for `hexbin` is replaced with `colorscale` [#2900](https://github.com/MakieOrg/Makie.jl/pull/2900).
- Add `alpha=1.0` argument to all basic plots, which supports independently adding an alpha component to colormaps and colors. Multiple alphas like in `plot(alpha=0.2, color=RGBAf(1, 0, 0, 0.5))`, will get multiplied [#2900](https://github.com/MakieOrg/Makie.jl/pull/2900).
- `hexbin` now supports any per-observation weights which StatsBase respects - `<: StatsBase.AbstractWeights`, `Vector{Real}`, or `nothing` (the default). [#2804](https://github.com/MakieOrg/Makie.jl/pulls/2804)
- Added a new Axis type, `PolarAxis`, which is an axis with a polar projection. Input is in `(r, theta)` coordinates and is transformed to `(x, y)` coordinates using the standard polar-to-cartesian transformation.
Generally, its attributes are very similar to the usual `Axis` attributes, but `x` is replaced by `r` and `y` by `θ`.
- Added a new Axis type, `PolarAxis`, which is an axis with a polar projection. Input is in `(r, theta)` coordinates and is transformed to `(x, y)` coordinates using the standard polar-to-cartesian transformation.
Generally, its attributes are very similar to the usual `Axis` attributes, but `x` is replaced by `r` and `y` by `θ`.
It also inherits from the theme of `Axis` in this manner, so should work seamlessly with Makie themes [#2990](https://github.com/MakieOrg/Makie.jl/pull/2990).
- `inherit` now has a new signature `inherit(scene, attrs::NTuple{N, Symbol}, default_value)`, allowing recipe authors to access nested attributes when trying to inherit from the parent Scene.
- `inherit` now has a new signature `inherit(scene, attrs::NTuple{N, Symbol}, default_value)`, allowing recipe authors to access nested attributes when trying to inherit from the parent Scene.
For example, one could inherit from `scene.Axis.yticks` by `inherit(scene, (:Axis, :yticks), $default_value)` [#2990](https://github.com/MakieOrg/Makie.jl/pull/2990).
- Fixed incorrect rendering of 3D heatmaps [#2959](https://github.com/MakieOrg/Makie.jl/pull/2959)
- Deprecated `flatten_plots` in favor of `collect_atomic_plots`. Using the new `collect_atomic_plots` fixed a bug in CairoMakie where the z-level of plots within recipes was not respected. [#2793](https://github.com/MakieOrg/Makie.jl/pull/2793)
Expand Down
25 changes: 25 additions & 0 deletions ReferenceTests/src/tests/short_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,31 @@ end
f
end

@reference_test "colorbuffer for axis" begin
fig = Figure()
ax1 = Axis(fig[1, 1])
ax2 = Axis(fig[1, 2])
ax3 = Axis(fig[2, 2])
ax4 = Axis(fig[2, 1])
scatter!(ax1, 1:10, 1:10; markersize=50, color=1:10)
scatter!(ax2, 1:10, 1:10; markersize=50, color=:red)
heatmap!(ax3, -8:0.1:8, 8:0.1:8, (x, y) -> sin(x) + cos(y))
meshscatter!(ax4, 1:10, 1:10; markersize=1, color=:red)
img1 = colorbuffer(ax1; include_decorations=true)
img2 = colorbuffer(ax2; include_decorations=false)
img3 = colorbuffer(ax3; include_decorations=true)
img4 = colorbuffer(ax4; include_decorations=false)
f, ax5, pl = image(rotr90(img1); axis=(; aspect=DataAspect()))
ax6, pl = image(f[1, 2], rotr90(img2); axis=(; aspect=DataAspect()))
ax7, pl = image(f[2, 2], rotr90(img3); axis=(; aspect=DataAspect()))
ax8, pl = image(f[2, 1], rotr90(img4); axis=(; aspect=DataAspect()))
hidedecorations!(ax5)
hidedecorations!(ax6)
hidedecorations!(ax7)
hidedecorations!(ax8)
f
end


# Needs a way to disable autolimits on show
# @reference_test "interactions after close" begin
Expand Down
2 changes: 1 addition & 1 deletion src/Makie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ export abline! # until deprecation removal

export Stepper, replay_events, record_events, RecordEvents, record, VideoStream
export VideoStream, recordframe!, record, Record
export save
export save, colorbuffer

# colormap stuff from PlotUtils, and showgradients
export cgrad, available_gradients, showgradients
Expand Down
25 changes: 20 additions & 5 deletions src/display.jl
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,8 @@ function FileIO.save(
# If the scene already got displayed, we get the current screen its displayed on
# Else, we create a new scene and update the state of the fig
update && update_state_before_display!(fig)
screen = getscreen(backend, scene, io, mime; visible=false, screen_config...)
visible = !isnothing(getscreen(scene)) # if already has a screen, don't hide it!
screen = getscreen(backend, scene, io, mime; visible=visible, screen_config...)
backend_show(screen, io, mime, scene)
end
catch e
Expand Down Expand Up @@ -408,9 +409,16 @@ function getscreen(backend::Union{Missing, Module}, scene::Scene, args...; scree
end
end

function get_sub_picture(image, format::ImageStorageFormat, rect)
xmin, ymin = minimum(rect) .- (1, 0)
xmax, ymax = maximum(rect)
start = size(image, 1) - ymax
stop = size(image, 1) - ymin
return image[start:stop, xmin:xmax]
end

"""
colorbuffer(scene, format::ImageStorageFormat = JuliaNative; backend=current_backend(), screen_config...)
colorbuffer(screen, format::ImageStorageFormat = JuliaNative)
colorbuffer(scene, format::ImageStorageFormat = JuliaNative; update=true, backend=current_backend(), screen_config...)
Returns the content of the given scene or screen rasterised to a Matrix of
Colors. The return type is backend-dependent, but will be some form of RGB
Expand All @@ -421,12 +429,19 @@ or RGBA.
- `format = GLNative` : Returns a more efficient format buffer for GLMakie which can be directly
used in FFMPEG without conversion
- `screen_config`: Backend dependend, look up via `?Backend.Screen`/`Base.doc(Backend.Screen)`
- `update=true`: resets/updates limits. Set to false, if you want to preserver camera movements.
"""
function colorbuffer(fig::FigureLike, format::ImageStorageFormat = JuliaNative; update=true, backend = current_backend(), screen_config...)
scene = get_scene(fig)
update && update_state_before_display!(fig)
screen = getscreen(backend, scene, format; start_renderloop=false, visible=false, screen_config...)
return colorbuffer(screen, format)
visible = !isnothing(getscreen(scene)) # if already has a screen, don't hide it!
screen = getscreen(backend, scene; start_renderloop=false, visible=visible, screen_config...)
img = colorbuffer(screen, format)
if !isroot(scene)
return get_sub_picture(img, format, pixelarea(scene)[])
else
return img
end
end

# Fallback for any backend that will just use colorbuffer to write out an image
Expand Down
27 changes: 27 additions & 0 deletions src/makielayout/blocks/axis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1785,3 +1785,30 @@ function attribute_examples(::Type{Axis})
],
)
end

function axis_bounds_with_decoration(axis::Axis)
# Filter out the zoomrect + background plot
lims = Makie.data_limits(axis.blockscene.plots, p -> p isa Mesh || p isa Poly)
return Makie.parent_transform(axis.blockscene) * lims
end

"""
colorbuffer(ax::Axis; include_decorations=true, colorbuffer_kws...)
Gets the colorbuffer of the `Axis` in `JuliaNative` image format.
If `include_decorations=false`, only the inside of the axis is fetched.
"""
function colorbuffer(ax::Axis; include_decorations=true, update=true, colorbuffer_kws...)
if update
update_state_before_display!(ax)
end
bb = if include_decorations
bb = axis_bounds_with_decoration(ax)
Rect2{Int}(round.(Int, minimum(bb)) .+ 1, round.(Int, widths(bb)))
else
pixelarea(ax.scene)[]
end

img = colorbuffer(root(ax.scene); update=false, colorbuffer_kws...)
return get_sub_picture(img, JuliaNative, bb)
end

0 comments on commit da4414c

Please sign in to comment.