diff --git a/CairoMakie/src/CairoMakie.jl b/CairoMakie/src/CairoMakie.jl index b5995fe1f33..cf6e066b425 100644 --- a/CairoMakie/src/CairoMakie.jl +++ b/CairoMakie/src/CairoMakie.jl @@ -30,9 +30,7 @@ include("utils.jl") include("primitives.jl") include("overrides.jl") -function __init__() - activate!() -end +__init__() = activate!() include("precompiles.jl") diff --git a/CairoMakie/src/cairo-extension.jl b/CairoMakie/src/cairo-extension.jl index a2a67344627..21ee92071ce 100644 --- a/CairoMakie/src/cairo-extension.jl +++ b/CairoMakie/src/cairo-extension.jl @@ -1,7 +1,13 @@ # TODO, move those to Cairo? function set_font_matrix(ctx, matrix) - ccall((:cairo_set_font_matrix, Cairo.libcairo), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), ctx.ptr, Ref(matrix)) + return ccall( + (:cairo_set_font_matrix, Cairo.libcairo), + Cvoid, + (Ptr{Cvoid}, Ptr{Cvoid}), + ctx.ptr, + Ref(matrix), + ) end function get_font_matrix(ctx) @@ -11,19 +17,16 @@ function get_font_matrix(ctx) end function cairo_font_face_destroy(font_face) - ccall( - (:cairo_font_face_destroy, Cairo.libcairo), - Cvoid, (Ptr{Cvoid},), - font_face - ) + return ccall((:cairo_font_face_destroy, Cairo.libcairo), Cvoid, (Ptr{Cvoid},), font_face) end function set_ft_font(ctx, font) - font_face = ccall( (:cairo_ft_font_face_create_for_ft_face, Cairo.libcairo), - Ptr{Cvoid}, (Makie.FreeTypeAbstraction.FT_Face, Cint), - font, 0 + Ptr{Cvoid}, + (Makie.FreeTypeAbstraction.FT_Face, Cint), + font, + 0, ) ccall((:cairo_set_font_face, Cairo.libcairo), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), ctx.ptr, font_face) @@ -39,30 +42,44 @@ end function show_glyph(ctx, glyph, x, y) cg = Ref(CairoGlyph(glyph, x, y)) - ccall((:cairo_show_glyphs, Cairo.libcairo), - Nothing, (Ptr{Nothing}, Ptr{CairoGlyph}, Cint), - ctx.ptr, cg, 1) + return ccall( + (:cairo_show_glyphs, Cairo.libcairo), + Nothing, + (Ptr{Nothing}, Ptr{CairoGlyph}, Cint), + ctx.ptr, + cg, + 1, + ) end function glyph_path(ctx, glyph, x, y) cg = Ref(CairoGlyph(glyph, x, y)) - ccall((:cairo_glyph_path, Cairo.libcairo), - Nothing, (Ptr{Nothing}, Ptr{CairoGlyph}, Cint), - ctx.ptr, cg, 1) + return ccall( + (:cairo_glyph_path, Cairo.libcairo), + Nothing, + (Ptr{Nothing}, Ptr{CairoGlyph}, Cint), + ctx.ptr, + cg, + 1, + ) end function surface_set_device_scale(surf, device_x_scale, device_y_scale=device_x_scale) # this sets a scaling factor on the lowest level that is "hidden" so its even # enabled when the drawing space is reset for strokes # that means it can be used to increase or decrease the image resolution - ccall( + return ccall( (:cairo_surface_set_device_scale, Cairo.libcairo), - Cvoid, (Ptr{Nothing}, Cdouble, Cdouble), - surf.ptr, device_x_scale, device_y_scale) + Cvoid, + (Ptr{Nothing}, Cdouble, Cdouble), + surf.ptr, + device_x_scale, + device_y_scale, + ) end function set_miter_limit(ctx, limit) - ccall((:cairo_set_miter_limit, Cairo.libcairo), Cvoid, (Ptr{Nothing}, Cdouble), ctx.ptr, limit) + return ccall((:cairo_set_miter_limit, Cairo.libcairo), Cvoid, (Ptr{Nothing}, Cdouble), ctx.ptr, limit) end function get_render_type(surface::Cairo.CairoSurface) @@ -71,5 +88,5 @@ function get_render_type(surface::Cairo.CairoSurface) typ == Cairo.CAIRO_SURFACE_TYPE_PS && return EPS typ == Cairo.CAIRO_SURFACE_TYPE_SVG && return SVG typ == Cairo.CAIRO_SURFACE_TYPE_IMAGE && return IMAGE - error("Unsupported surface type: $(typ)") + return error("Unsupported surface type: $(typ)") end diff --git a/CairoMakie/src/display.jl b/CairoMakie/src/display.jl index d5cf249942b..e737d9887e9 100644 --- a/CairoMakie/src/display.jl +++ b/CairoMakie/src/display.jl @@ -8,13 +8,12 @@ Try to run a command. Return `true` if `cmd` runs and is successful (exits with a code of `0`). Return `false` otherwise. """ -function tryrun(cmd::Cmd) +tryrun(cmd::Cmd) = try return success(cmd) catch e return false end -end function openurl(url::String) if Sys.isapple() @@ -63,7 +62,7 @@ function Makie.backend_show(screen::Screen{SVG}, io::IO, ::MIME"image/svg+xml", screen2 = Screen(screen, io2, SVG) cairo_draw(screen2, scene) Cairo.flush(screen2.surface) - Cairo.finish(screen2.surface) + return Cairo.finish(screen2.surface) end # for some reason, in the svg, surfaceXXX ids keep counting up, @@ -116,14 +115,9 @@ end # Disabling mimes and showable const DISABLED_MIMES = Set{String}() -const SUPPORTED_MIMES = Set([ - "image/svg+xml", - "application/pdf", - "application/postscript", - "image/png" -]) - -function Makie.backend_showable(::Type{Screen}, ::MIME{SYM}) where SYM +const SUPPORTED_MIMES = Set(["image/svg+xml", "application/pdf", "application/postscript", "image/png"]) + +function Makie.backend_showable(::Type{Screen}, ::MIME{SYM}) where {SYM} supported_mimes = Base.setdiff(SUPPORTED_MIMES, DISABLED_MIMES) return string(SYM) in supported_mimes end @@ -133,7 +127,7 @@ end Converts anything like `"png", :png, "image/png", MIME"image/png"()` to `"image/png"`. """ -function to_mime_string(mime::Union{String, Symbol, MIME}) +function to_mime_string(mime::Union{String,Symbol,MIME}) if mime isa MIME mime_str = string(mime) if !(mime_str in SUPPORTED_MIMES) @@ -156,7 +150,7 @@ The default is automatic, which lets the display system figure out the best mime If set to any other valid mime, will result in `showable(any_other_mime, figurelike)` to return false and only return true for `showable(preferred_mime, figurelike)`. Depending on the display system used, this may result in nothing getting displayed. """ -function disable_mime!(mimes::Union{String, Symbol, MIME}...) +function disable_mime!(mimes::Union{String,Symbol,MIME}...) empty!(DISABLED_MIMES) # always start from 0 if isempty(mimes) # Reset disabled mimes when called with no arguments @@ -170,7 +164,7 @@ function disable_mime!(mimes::Union{String, Symbol, MIME}...) return end -function enable_only_mime!(mimes::Union{String, Symbol, MIME}...) +function enable_only_mime!(mimes::Union{String,Symbol,MIME}...) empty!(DISABLED_MIMES) # always start from 0 if isempty(mimes) # Reset disabled mimes when called with no arguments diff --git a/CairoMakie/src/infrastructure.jl b/CairoMakie/src/infrastructure.jl index ffe6741e10d..22d222cf0dd 100644 --- a/CairoMakie/src/infrastructure.jl +++ b/CairoMakie/src/infrastructure.jl @@ -52,12 +52,12 @@ function cairo_draw(screen::Screen, scene::Scene) return end -function get_all_plots(scene, plots = AbstractPlot[]) +function get_all_plots(scene, plots=AbstractPlot[]) append!(plots, scene.plots) for c in scene.children get_all_plots(c, plots) end - plots + return plots end function prepare_for_scene(screen::Screen, scene::Scene) @@ -90,13 +90,13 @@ function draw_background(screen::Screen, scene::Scene) Cairo.save(cr) if scene.clear[] bg = scene.backgroundcolor[] - Cairo.set_source_rgba(cr, red(bg), green(bg), blue(bg), alpha(bg)); + Cairo.set_source_rgba(cr, red(bg), green(bg), blue(bg), alpha(bg)) r = pixelarea(scene)[] Cairo.rectangle(cr, origin(r)..., widths(r)...) # background fill(cr) end Cairo.restore(cr) - foreach(child_scene-> draw_background(screen, child_scene), scene.children) + return foreach(child_scene -> draw_background(screen, child_scene), scene.children) end function draw_plot(scene::Scene, screen::Screen, primitive::Combined) @@ -120,14 +120,14 @@ end # instead of the whole Scene # - Recognize when a screen is an image surface, and set scale to render the plot # at the scale of the device pixel -function draw_plot_as_image(scene::Scene, screen::Screen, primitive::Combined, scale::Number = 1) +function draw_plot_as_image(scene::Scene, screen::Screen, primitive::Combined, scale::Number=1) # you can provide `p.rasterize = scale::Int` or `p.rasterize = true`, both of which are numbers # Extract scene width in pixels w, h = Int.(scene.px_area[].widths) # Create a new Screen which renders directly to an image surface, # specifically for the plot's parent scene. - scr = Screen(scene; px_per_unit = scale) + scr = Screen(scene; px_per_unit=scale) # Draw the plot to the screen, in the normal way draw_plot(scene, scr, primitive) @@ -150,6 +150,4 @@ function draw_plot_as_image(scene::Scene, screen::Screen, primitive::Combined, s return end -function draw_atomic(::Scene, ::Screen, x) - @warn "$(typeof(x)) is not supported by cairo right now" -end +draw_atomic(::Scene, ::Screen, x) = @warn "$(typeof(x)) is not supported by cairo right now" diff --git a/CairoMakie/src/overrides.jl b/CairoMakie/src/overrides.jl index 3630440ae5a..aa08c1c43aa 100644 --- a/CairoMakie/src/overrides.jl +++ b/CairoMakie/src/overrides.jl @@ -2,7 +2,6 @@ # Poly - the not so primitive, primitive # ################################################################################ - """ Special method for polys so we don't fall back to atomic meshes, which are much more complex and slower to draw than standard paths with single color. @@ -10,34 +9,57 @@ complex and slower to draw than standard paths with single color. function draw_plot(scene::Scene, screen::Screen, poly::Poly) # dispatch on input arguments to poly to use smarter drawing methods than # meshes if possible - draw_poly(scene, screen, poly, to_value.(poly.input_args)...) + return draw_poly(scene, screen, poly, to_value.(poly.input_args)...) end """ Fallback method for args without special treatment. """ -function draw_poly(scene::Scene, screen::Screen, poly, args...) - draw_poly_as_mesh(scene, screen, poly) -end +draw_poly(scene::Scene, screen::Screen, poly, args...) = draw_poly_as_mesh(scene, screen, poly) function draw_poly_as_mesh(scene, screen, poly) draw_plot(scene, screen, poly.plots[1]) - draw_plot(scene, screen, poly.plots[2]) + return draw_plot(scene, screen, poly.plots[2]) end - # in the rare case of per-vertex colors redirect to mesh drawing -function draw_poly(scene::Scene, screen::Screen, poly, points::Vector{<:Point2}, color::AbstractArray, model, strokecolor, strokewidth) - draw_poly_as_mesh(scene, screen, poly) +function draw_poly( + scene::Scene, + screen::Screen, + poly, + points::Vector{<:Point2}, + color::AbstractArray, + model, + strokecolor, + strokewidth, +) + return draw_poly_as_mesh(scene, screen, poly) end function draw_poly(scene::Scene, screen::Screen, poly, points::Vector{<:Point2}) - draw_poly(scene, screen, poly, points, poly.color[], poly.model[], poly.strokecolor[], poly.strokewidth[]) + return draw_poly( + scene, + screen, + poly, + points, + poly.color[], + poly.model[], + poly.strokecolor[], + poly.strokewidth[], + ) end # when color is a Makie.AbstractPattern, we don't need to go to Mesh -function draw_poly(scene::Scene, screen::Screen, poly, points::Vector{<:Point2}, color::Union{Symbol, Colorant, Makie.AbstractPattern}, - model, strokecolor, strokewidth) +function draw_poly( + scene::Scene, + screen::Screen, + poly, + points::Vector{<:Point2}, + color::Union{Symbol,Colorant,Makie.AbstractPattern}, + model, + strokecolor, + strokewidth, +) space = to_value(get(poly, :space, :data)) points = project_position.(Ref(scene), space, points, Ref(model)) Cairo.move_to(screen.context, points[1]...) @@ -47,7 +69,7 @@ function draw_poly(scene::Scene, screen::Screen, poly, points::Vector{<:Point2}, Cairo.close_path(screen.context) if color isa Makie.AbstractPattern cairopattern = Cairo.CairoPattern(color) - Cairo.pattern_set_extend(cairopattern, Cairo.EXTEND_REPEAT); + Cairo.pattern_set_extend(cairopattern, Cairo.EXTEND_REPEAT) Cairo.set_source(screen.context, cairopattern) else Cairo.set_source_rgba(screen.context, rgbatuple(to_color(color))...) @@ -56,14 +78,17 @@ function draw_poly(scene::Scene, screen::Screen, poly, points::Vector{<:Point2}, Cairo.fill_preserve(screen.context) Cairo.set_source_rgba(screen.context, rgbatuple(to_color(strokecolor))...) Cairo.set_line_width(screen.context, strokewidth) - Cairo.stroke(screen.context) + return Cairo.stroke(screen.context) end function draw_poly(scene::Scene, screen::Screen, poly, points_list::Vector{<:Vector{<:Point2}}) - broadcast_foreach(points_list, poly.color[], - poly.strokecolor[], poly.strokewidth[]) do points, color, strokecolor, strokewidth - - draw_poly(scene, screen, poly, points, color, poly.model[], strokecolor, strokewidth) + broadcast_foreach( + points_list, + poly.color[], + poly.strokecolor[], + poly.strokewidth[], + ) do points, color, strokecolor, strokewidth + return draw_poly(scene, screen, poly, points, color, poly.model[], strokecolor, strokewidth) end end @@ -82,7 +107,7 @@ function draw_poly(scene::Scene, screen::Screen, poly, rects::Vector{<:Rect2}) color = to_color(color) elseif color isa Makie.AbstractPattern cairopattern = Cairo.CairoPattern(color) - Cairo.pattern_set_extend(cairopattern, Cairo.EXTEND_REPEAT); + Cairo.pattern_set_extend(cairopattern, Cairo.EXTEND_REPEAT) end strokecolor = poly.strokecolor[] if strokecolor isa AbstractArray{<:Number} @@ -102,7 +127,7 @@ function draw_poly(scene::Scene, screen::Screen, poly, rects::Vector{<:Rect2}) Cairo.fill_preserve(screen.context) Cairo.set_source_rgba(screen.context, rgbatuple(to_color(sc))...) Cairo.set_line_width(screen.context, sw) - Cairo.stroke(screen.context) + return Cairo.stroke(screen.context) end end @@ -151,21 +176,21 @@ function draw_poly(scene::Scene, screen::Screen, poly, polygons::AbstractArray{< Cairo.fill_preserve(screen.context) Cairo.set_source_rgba(screen.context, rgbatuple(sc)...) Cairo.set_line_width(screen.context, sw) - Cairo.stroke(screen.context) + return Cairo.stroke(screen.context) end - end - ################################################################################ # Band # # Override because band is usually a polygon, but because it supports # # gradients as well via `mesh` we have to intercept the poly use # ################################################################################ -function draw_plot(scene::Scene, screen::Screen, - band::Band{<:Tuple{<:AbstractVector{<:Point2},<:AbstractVector{<:Point2}}}) - +function draw_plot( + scene::Scene, + screen::Screen, + band::Band{<:Tuple{<:AbstractVector{<:Point2},<:AbstractVector{<:Point2}}}, +) if !(band.color[] isa AbstractArray) upperpoints = band[1][] lowerpoints = band[2][] @@ -186,7 +211,7 @@ function draw_plot(scene::Scene, screen::Screen, end end - nothing + return nothing end ################################################################################# @@ -197,7 +222,6 @@ end ################################################################################# function draw_plot(scene::Scene, screen::Screen, tric::Tricontourf) - pol = only(tric.plots)::Poly colornumbers = pol.color[] colors = numbers_to_colors(colornumbers, pol) @@ -211,7 +235,7 @@ function draw_plot(scene::Scene, screen::Screen, tric::Tricontourf) function draw_tripolys(polys, colornumbers, colors) for (i, (pol, colnum, col)) in enumerate(zip(polys, colornumbers, colors)) polypath(screen.context, pol) - if i == length(colornumbers) || colnum != colornumbers[i+1] + if i == length(colornumbers) || colnum != colornumbers[i + 1] Cairo.set_source_rgba(screen.context, rgbatuple(col)...) Cairo.fill(screen.context) end diff --git a/CairoMakie/src/primitives.jl b/CairoMakie/src/primitives.jl index 765295e6d0a..3762c9dc28e 100644 --- a/CairoMakie/src/primitives.jl +++ b/CairoMakie/src/primitives.jl @@ -2,7 +2,7 @@ # Lines, LineSegments # ################################################################################ -function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Union{Lines, LineSegments})) +function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Union{Lines,LineSegments})) fields = @get_attribute(primitive, (color, linewidth, linestyle)) linestyle = Makie.convert_attribute(linestyle, Makie.key"linestyle"()) ctx = screen.context @@ -16,7 +16,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio # a vector of tuples of two points. we convert those to a list of points # so they don't trip up the rest of the pipeline # TODO this shouldn't be necessary anymore! - if positions isa SubArray{<:Point3, 1, P, <:Tuple{Array{<:AbstractFace}}} where P + if positions isa SubArray{<:Point3,1,P,<:Tuple{Array{<:AbstractFace}}} where {P} positions = let pos = Point3f[] for tup in positions @@ -30,7 +30,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio space = to_value(get(primitive, :space, :data)) projected_positions = project_position.(Ref(scene), Ref(space), positions, Ref(model)) - if color isa AbstractArray{<: Number} + if color isa AbstractArray{<:Number} color = numbers_to_colors(color, primitive) end @@ -56,10 +56,12 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio # we can hide the gaps by setting the line cap to round Cairo.set_line_cap(ctx, Cairo.CAIRO_LINE_CAP_ROUND) draw_multi( - primitive, ctx, + primitive, + ctx, projected_positions, - color, linewidth, - isnothing(linestyle) ? nothing : diff(Float64.(linestyle)) + color, + linewidth, + isnothing(linestyle) ? nothing : diff(Float64.(linestyle)), ) else # stroke the whole line at once if it has only one color @@ -69,7 +71,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio Cairo.set_source_rgba(ctx, red(color), green(color), blue(color), alpha(color)) draw_single(primitive, ctx, projected_positions) end - nothing + return nothing end function draw_single(primitive::Lines, ctx, positions) @@ -79,28 +81,27 @@ function draw_single(primitive::Lines, ctx, positions) # only take action for non-NaNs if !isnan(p) # new line segment at beginning or if previously NaN - if i == 1 || isnan(positions[i-1]) + if i == 1 || isnan(positions[i - 1]) Cairo.move_to(ctx, p...) else Cairo.line_to(ctx, p...) # complete line segment at end or if next point is NaN - if i == n || isnan(positions[i+1]) + if i == n || isnan(positions[i + 1]) Cairo.stroke(ctx) end end end end # force clearing of path in case of skipped NaN - Cairo.new_path(ctx) + return Cairo.new_path(ctx) end function draw_single(primitive::LineSegments, ctx, positions) - @assert iseven(length(positions)) - @inbounds for i in 1:2:length(positions)-1 + @inbounds for i in 1:2:(length(positions) - 1) p1 = positions[i] - p2 = positions[i+1] + p2 = positions[i + 1] if isnan(p1) || isnan(p2) continue @@ -111,20 +112,27 @@ function draw_single(primitive::LineSegments, ctx, positions) end end # force clearing of path in case of skipped NaN - Cairo.new_path(ctx) + return Cairo.new_path(ctx) end # if linewidth is not an array function draw_multi(primitive, ctx, positions, colors::AbstractArray, linewidth, dash) - draw_multi(primitive, ctx, positions, colors, [linewidth for c in colors], dash) + return draw_multi(primitive, ctx, positions, colors, [linewidth for c in colors], dash) end # if color is not an array function draw_multi(primitive, ctx, positions, color, linewidths::AbstractArray, dash) - draw_multi(primitive, ctx, positions, [color for l in linewidths], linewidths, dash) + return draw_multi(primitive, ctx, positions, [color for l in linewidths], linewidths, dash) end -function draw_multi(primitive::Union{Lines, LineSegments}, ctx, positions, colors::AbstractArray, linewidths::AbstractArray, dash) +function draw_multi( + primitive::Union{Lines,LineSegments}, + ctx, + positions, + colors::AbstractArray, + linewidths::AbstractArray, + dash, +) if primitive isa LineSegments @assert iseven(length(positions)) end @@ -132,32 +140,34 @@ function draw_multi(primitive::Union{Lines, LineSegments}, ctx, positions, color @assert length(linewidths) == length(colors) iterator = if primitive isa Lines - 1:length(positions)-1 + 1:(length(positions) - 1) elseif primitive isa LineSegments 1:2:length(positions) end for i in iterator - if isnan(positions[i+1]) || isnan(positions[i]) + if isnan(positions[i + 1]) || isnan(positions[i]) continue end Cairo.move_to(ctx, positions[i]...) - Cairo.line_to(ctx, positions[i+1]...) - if linewidths[i] != linewidths[i+1] - error("Cairo doesn't support two different line widths ($(linewidths[i]) and $(linewidths[i+1])) at the endpoints of a line.") + Cairo.line_to(ctx, positions[i + 1]...) + if linewidths[i] != linewidths[i + 1] + error( + "Cairo doesn't support two different line widths ($(linewidths[i]) and $(linewidths[i+1])) at the endpoints of a line.", + ) end Cairo.set_line_width(ctx, linewidths[i]) !isnothing(dash) && Cairo.set_dash(ctx, dash .* linewidths[i]) c1 = colors[i] - c2 = colors[i+1] + c2 = colors[i + 1] # we can avoid the more expensive gradient if the colors are the same # this happens if one color was given for each segment if c1 == c2 Cairo.set_source_rgba(ctx, red(c1), green(c1), blue(c1), alpha(c1)) Cairo.stroke(ctx) else - pat = Cairo.pattern_create_linear(positions[i]..., positions[i+1]...) + pat = Cairo.pattern_create_linear(positions[i]..., positions[i + 1]...) Cairo.pattern_add_color_stop_rgba(pat, 0, red(c1), green(c1), blue(c1), alpha(c1)) Cairo.pattern_add_color_stop_rgba(pat, 1, red(c2), green(c2), blue(c2), alpha(c2)) Cairo.set_source(ctx, pat) @@ -166,7 +176,7 @@ function draw_multi(primitive::Union{Lines, LineSegments}, ctx, positions, color end end # force clearing of path in case of skipped NaN - Cairo.new_path(ctx) + return Cairo.new_path(ctx) end ################################################################################ @@ -174,7 +184,10 @@ end ################################################################################ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Scatter)) - fields = @get_attribute(primitive, (color, markersize, strokecolor, strokewidth, marker, marker_offset, rotations)) + fields = @get_attribute( + primitive, + (color, markersize, strokecolor, strokewidth, marker, marker_offset, rotations) + ) @get_attribute(primitive, (transform_marker,)) ctx = screen.context @@ -185,7 +198,7 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Scat font = to_font(to_value(get(primitive, :font, Makie.defaultfont()))) - colors = if color isa AbstractArray{<: Number} + colors = if color isa AbstractArray{<:Number} numbers_to_colors(color, primitive) else color @@ -198,20 +211,64 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Scat marker_conv = _marker_convert(marker) - draw_atomic_scatter(scene, ctx, transfunc, colors, markersize, strokecolor, strokewidth, marker_conv, marker_offset, rotations, model, positions, size_model, font, markerspace, space) + return draw_atomic_scatter( + scene, + ctx, + transfunc, + colors, + markersize, + strokecolor, + strokewidth, + marker_conv, + marker_offset, + rotations, + model, + positions, + size_model, + font, + markerspace, + space, + ) end # an array of markers is converted to string by itself, which is inconvenient for the iteration logic -_marker_convert(markers::AbstractArray) = map(m -> convert_attribute(m, key"marker"(), key"scatter"()), markers) +function _marker_convert(markers::AbstractArray) + return map(m -> convert_attribute(m, key"marker"(), key"scatter"()), markers) +end _marker_convert(marker) = convert_attribute(marker, key"marker"(), key"scatter"()) # image arrays need to be converted as a whole -_marker_convert(marker::AbstractMatrix{<:Colorant}) = [ convert_attribute(marker, key"marker"(), key"scatter"()) ] - -function draw_atomic_scatter(scene, ctx, transfunc, colors, markersize, strokecolor, strokewidth, marker, marker_offset, rotations, model, positions, size_model, font, markerspace, space) - broadcast_foreach(positions, colors, markersize, strokecolor, - strokewidth, marker, marker_offset, remove_billboard(rotations)) do point, col, - markersize, strokecolor, strokewidth, m, mo, rotation +function _marker_convert(marker::AbstractMatrix{<:Colorant}) + return [convert_attribute(marker, key"marker"(), key"scatter"())] +end +function draw_atomic_scatter( + scene, + ctx, + transfunc, + colors, + markersize, + strokecolor, + strokewidth, + marker, + marker_offset, + rotations, + model, + positions, + size_model, + font, + markerspace, + space, +) + broadcast_foreach( + positions, + colors, + markersize, + strokecolor, + strokewidth, + marker, + marker_offset, + remove_billboard(rotations), + ) do point, col, markersize, strokecolor, strokewidth, m, mo, rotation scale = project_scale(scene, markerspace, markersize, size_model) offset = project_scale(scene, markerspace, mo, size_model) @@ -227,12 +284,22 @@ function draw_atomic_scatter(scene, ctx, transfunc, colors, markersize, strokeco # TODO, maybe there's something wrong somewhere else? if !(norm(scale) ≈ 0.0) if marker_converted isa Char - draw_marker(ctx, marker_converted, best_font(m, font), pos, scale, strokecolor, strokewidth, offset, rotation) + draw_marker( + ctx, + marker_converted, + best_font(m, font), + pos, + scale, + strokecolor, + strokewidth, + offset, + rotation, + ) else draw_marker(ctx, marker_converted, pos, scale, strokecolor, strokewidth, offset, rotation) end end - Cairo.restore(ctx) + return Cairo.restore(ctx) end return end @@ -284,20 +351,20 @@ function draw_marker(ctx, marker::Char, font, pos, scale, strokecolor, strokewid # if we use set_ft_font we should destroy the pointer it returns cairo_font_face_destroy(cairoface) - set_font_matrix(ctx, old_matrix) + return set_font_matrix(ctx, old_matrix) end -function draw_marker(ctx, ::Type{<: Circle}, pos, scale, strokecolor, strokewidth, marker_offset, rotation) +function draw_marker(ctx, ::Type{<:Circle}, pos, scale, strokecolor, strokewidth, marker_offset, rotation) marker_offset = marker_offset + scale ./ 2 pos += Point2f(marker_offset[1], -marker_offset[2]) if scale[1] != scale[2] old_matrix = Cairo.get_matrix(ctx) Cairo.scale(ctx, scale[1], scale[2]) - Cairo.translate(ctx, pos[1]/scale[1], pos[2]/scale[2]) - Cairo.arc(ctx, 0, 0, 0.5, 0, 2*pi) + Cairo.translate(ctx, pos[1] / scale[1], pos[2] / scale[2]) + Cairo.arc(ctx, 0, 0, 0.5, 0, 2 * pi) else - Cairo.arc(ctx, pos[1], pos[2], scale[1]/2, 0, 2*pi) + Cairo.arc(ctx, pos[1], pos[2], scale[1] / 2, 0, 2 * pi) end Cairo.fill_preserve(ctx) @@ -308,10 +375,10 @@ function draw_marker(ctx, ::Type{<: Circle}, pos, scale, strokecolor, strokewidt Cairo.set_source_rgba(ctx, rgbatuple(sc)...) Cairo.stroke(ctx) scale[1] != scale[2] && Cairo.set_matrix(ctx, old_matrix) - nothing + return nothing end -function draw_marker(ctx, ::Type{<: Rect}, pos, scale, strokecolor, strokewidth, marker_offset, rotation) +function draw_marker(ctx, ::Type{<:Rect}, pos, scale, strokecolor, strokewidth, marker_offset, rotation) s2 = Point2((scale .* (1, -1))...) pos = pos .+ Point2f(marker_offset[1], -marker_offset[2]) Cairo.rotate(ctx, to_2d_rotation(rotation)) @@ -320,10 +387,19 @@ function draw_marker(ctx, ::Type{<: Rect}, pos, scale, strokecolor, strokewidth, Cairo.set_line_width(ctx, Float64(strokewidth)) sc = to_color(strokecolor) Cairo.set_source_rgba(ctx, rgbatuple(sc)...) - Cairo.stroke(ctx) + return Cairo.stroke(ctx) end -function draw_marker(ctx, beziermarker::BezierPath, pos, scale, strokecolor, strokewidth, marker_offset, rotation) +function draw_marker( + ctx, + beziermarker::BezierPath, + pos, + scale, + strokecolor, + strokewidth, + marker_offset, + rotation, +) Cairo.save(ctx) Cairo.translate(ctx, pos[1], pos[2]) Cairo.rotate(ctx, to_2d_rotation(rotation)) @@ -334,7 +410,7 @@ function draw_marker(ctx, beziermarker::BezierPath, pos, scale, strokecolor, str Cairo.set_source_rgba(ctx, rgbatuple(sc)...) Cairo.set_line_width(ctx, Float64(strokewidth)) Cairo.stroke(ctx) - Cairo.restore(ctx) + return Cairo.restore(ctx) end draw_path(ctx, bp::BezierPath) = foreach(x -> path_command(ctx, x), bp.commands) @@ -352,43 +428,52 @@ function path_command(ctx, c::EllipticalArc) else Cairo.arc_negative(ctx, 0, 0, c.r1, c.a1, c.a2) end - Cairo.restore(ctx) + return Cairo.restore(ctx) end - -function draw_marker(ctx, marker::Matrix{T}, pos, scale, - strokecolor #= unused =#, strokewidth #= unused =#, - marker_offset, rotation) where T<:Colorant +function draw_marker( + ctx, + marker::Matrix{T}, + pos, + scale, + strokecolor, + strokewidth, #= unused =# + marker_offset, + rotation, +) where {T<:Colorant} # convert marker to Cairo compatible image data - marker = permutedims(marker, (2,1)) + marker = permutedims(marker, (2, 1)) marker_surf = to_cairo_image(marker, ()) w, h = size(marker) - Cairo.translate(ctx, - scale[1]/2 + pos[1] + marker_offset[1], - scale[2]/2 + pos[2] + marker_offset[2]) + Cairo.translate(ctx, scale[1] / 2 + pos[1] + marker_offset[1], scale[2] / 2 + pos[2] + marker_offset[2]) Cairo.rotate(ctx, to_2d_rotation(rotation)) Cairo.scale(ctx, scale[1] / w, scale[2] / h) - Cairo.set_source_surface(ctx, marker_surf, -w/2, -h/2) - Cairo.paint(ctx) + Cairo.set_source_surface(ctx, marker_surf, -w / 2, -h / 2) + return Cairo.paint(ctx) end - ################################################################################ # Text # ################################################################################ -function p3_to_p2(p::Point3{T}) where T +function p3_to_p2(p::Point3{T}) where {T} if p[3] == 0 || isnan(p[3]) - Point2{T}(p[Vec(1,2)]...) + Point2{T}(p[Vec(1, 2)]...) else error("Can't reduce Point3 to Point2 with nonzero third component $(p[3]).") end end -function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Text{<:Tuple{<:Union{AbstractArray{<:Makie.GlyphCollection}, Makie.GlyphCollection}}})) +function draw_atomic( + scene::Scene, + screen::Screen, + @nospecialize( + primitive::Text{<:Tuple{<:Union{AbstractArray{<:Makie.GlyphCollection},Makie.GlyphCollection}}} + ) +) ctx = screen.context @get_attribute(primitive, (rotation, model, space, markerspace, offset)) position = primitive.position[] @@ -396,32 +481,60 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Text glyph_collection = to_value(primitive[1]) draw_glyph_collection( - scene, ctx, position, glyph_collection, remove_billboard(rotation), - model, space, markerspace, offset + scene, + ctx, + position, + glyph_collection, + remove_billboard(rotation), + model, + space, + markerspace, + offset, ) - nothing + return nothing end - function draw_glyph_collection( - scene, ctx, positions, glyph_collections::AbstractArray, rotation, - model::Mat, space, markerspace, offset - ) + scene, + ctx, + positions, + glyph_collections::AbstractArray, + rotation, + model::Mat, + space, + markerspace, + offset, +) # TODO: why is the Ref around model necessary? doesn't broadcast_foreach handle staticarrays matrices? - broadcast_foreach(positions, glyph_collections, rotation, Ref(model), space, - markerspace, offset) do pos, glayout, ro, mo, sp, msp, off - - draw_glyph_collection(scene, ctx, pos, glayout, ro, mo, sp, msp, off) + broadcast_foreach( + positions, + glyph_collections, + rotation, + Ref(model), + space, + markerspace, + offset, + ) do pos, glayout, ro, mo, sp, msp, off + return draw_glyph_collection(scene, ctx, pos, glayout, ro, mo, sp, msp, off) end end _deref(x) = x _deref(x::Ref) = x[] -function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation, _model, space, markerspace, offsets) - +function draw_glyph_collection( + scene, + ctx, + position, + glyph_collection, + rotation, + _model, + space, + markerspace, + offsets, +) glyphs = glyph_collection.glyphs glyphoffsets = glyph_collection.origins fonts = glyph_collection.fonts @@ -441,14 +554,23 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation, Makie.clip_to_space(scene.camera, markerspace) * Makie.space_to_clip(scene.camera, space) * - model * to_ndim(Point4f, to_ndim(Point3f, p, 0), 1) + model * + to_ndim(Point4f, to_ndim(Point3f, p, 0), 1) end Cairo.save(ctx) - broadcast_foreach(glyphs, glyphoffsets, fonts, rotations, scales, colors, strokewidths, strokecolors, offsets) do glyph, - glyphoffset, font, rotation, scale, color, strokewidth, strokecolor, offset - + broadcast_foreach( + glyphs, + glyphoffsets, + fonts, + rotations, + scales, + colors, + strokewidths, + strokecolors, + offsets, + ) do glyph, glyphoffset, font, rotation, scale, color, strokewidth, strokecolor, offset cairoface = set_ft_font(ctx, font) old_matrix = get_font_matrix(ctx) @@ -481,11 +603,7 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation, xdiff = xproj - glyphpos ydiff = yproj - glyphpos - mat = Cairo.CairoMatrix( - xdiff[1], xdiff[2], - ydiff[1], ydiff[2], - 0, 0, - ) + mat = Cairo.CairoMatrix(xdiff[1], xdiff[2], ydiff[1], ydiff[2], 0, 0) Cairo.save(ctx) set_font_matrix(ctx, mat) @@ -505,7 +623,7 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation, Cairo.restore(ctx) cairo_font_face_destroy(cairoface) - set_font_matrix(ctx, old_matrix) + return set_font_matrix(ctx, old_matrix) end Cairo.restore(ctx) @@ -524,7 +642,7 @@ If not, returns array unchanged. function regularly_spaced_array_to_range(arr) diffs = unique!(sort!(diff(arr))) step = sum(diffs) ./ length(diffs) - if all(x-> x ≈ step, diffs) + if all(x -> x ≈ step, diffs) m, M = extrema(arr) if step < zero(step) m, M = M, m @@ -538,29 +656,27 @@ end regularly_spaced_array_to_range(arr::AbstractRange) = arr -function premultiplied_rgba(a::AbstractArray{<:ColorAlpha}) - map(premultiplied_rgba, a) -end +premultiplied_rgba(a::AbstractArray{<:ColorAlpha}) = map(premultiplied_rgba, a) premultiplied_rgba(a::AbstractArray{<:Color}) = RGBA.(a) premultiplied_rgba(r::RGBA) = RGBA(r.r * r.alpha, r.g * r.alpha, r.b * r.alpha, r.alpha) premultiplied_rgba(c::Colorant) = premultiplied_rgba(RGBA(c)) -function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Union{Heatmap, Image})) +function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Union{Heatmap,Image})) ctx = screen.context image = primitive[3][] xs, ys = primitive[1][], primitive[2][] if !(xs isa AbstractVector) l, r = extrema(xs) N = size(image, 1) - xs = range(l, r, length = N+1) + xs = range(l, r, length=N + 1) else xs = regularly_spaced_array_to_range(xs) end if !(ys isa AbstractVector) l, r = extrema(ys) N = size(image, 2) - ys = range(l, r, length = N+1) + ys = range(l, r, length=N + 1) else ys = regularly_spaced_array_to_range(ys) end @@ -574,15 +690,20 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio # Vector backends don't support FILTER_NEAREST for interp == false, so in that case we also need to draw rects is_vector = is_vector_backend(ctx) t = Makie.transform_func_obs(primitive)[] - identity_transform = (t === identity || t isa Tuple && all(x-> x === identity, t)) && (abs(model[1, 2]) < 1e-15) + identity_transform = + (t === identity || t isa Tuple && all(x -> x === identity, t)) && (abs(model[1, 2]) < 1e-15) regular_grid = xs isa AbstractRange && ys isa AbstractRange if interpolate if !regular_grid - error("$(typeof(primitive).parameters[1]) with interpolate = true with a non-regular grid is not supported right now.") + error( + "$(typeof(primitive).parameters[1]) with interpolate = true with a non-regular grid is not supported right now.", + ) end if !identity_transform - error("$(typeof(primitive).parameters[1]) with interpolate = true with a non-identity transform is not supported right now.") + error( + "$(typeof(primitive).parameters[1]) with interpolate = true with a non-identity transform is not supported right now.", + ) end end @@ -602,7 +723,9 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio weird_cairo_limit = (2^15) - 23 if s.width > weird_cairo_limit || s.height > weird_cairo_limit - error("Cairo stops rendering images bigger than $(weird_cairo_limit), which is likely a bug in Cairo. Please resample your image/heatmap with e.g. `ImageTransformations.imresize`") + error( + "Cairo stops rendering images bigger than $(weird_cairo_limit), which is likely a bug in Cairo. Please resample your image/heatmap with e.g. `ImageTransformations.imresize`", + ) end Cairo.rectangle(ctx, xy..., w, h) Cairo.save(ctx) @@ -626,7 +749,9 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio # Note: xs and ys should have size ni+1, nj+1 ni, nj = size(image) if ni + 1 != length(xs) || nj + 1 != length(ys) - error("Error in conversion pipeline. xs and ys should have size ni+1, nj+1. Found: xs: $(length(xs)), ys: $(length(ys)), ni: $(ni), nj: $(nj)") + error( + "Error in conversion pipeline. xs and ys should have size ni+1, nj+1. Found: xs: $(length(xs)), ys: $(length(ys)), ni: $(ni), nj: $(nj)", + ) end _draw_rect_heatmap(ctx, xys, ni, nj, colors) end @@ -635,9 +760,9 @@ end function _draw_rect_heatmap(ctx, xys, ni, nj, colors) @inbounds for i in 1:ni, j in 1:nj p1 = xys[i, j] - p2 = xys[i+1, j] - p3 = xys[i+1, j+1] - p4 = xys[i, j+1] + p2 = xys[i + 1, j] + p3 = xys[i + 1, j + 1] + p4 = xys[i, j + 1] # Rectangles and polygons that are directly adjacent usually show # white lines between them due to anti aliasing. To avoid this we @@ -649,10 +774,10 @@ function _draw_rect_heatmap(ctx, xys, ni, nj, colors) # model matrix.) (i!=1) etc is used to avoid increasing the # outer extent of the heatmap. center = 0.25f0 * (p1 + p2 + p3 + p4) - p1 += sign.(p1 - center) .* Point2f(0.5f0 * (i!=1), 0.5f0 * (j!=1)) - p2 += sign.(p2 - center) .* Point2f(0.5f0 * (i!=ni), 0.5f0 * (j!=1)) - p3 += sign.(p3 - center) .* Point2f(0.5f0 * (i!=ni), 0.5f0 * (j!=nj)) - p4 += sign.(p4 - center) .* Point2f(0.5f0 * (i!=1), 0.5f0 * (j!=nj)) + p1 += sign.(p1 - center) .* Point2f(0.5f0 * (i != 1), 0.5f0 * (j != 1)) + p2 += sign.(p2 - center) .* Point2f(0.5f0 * (i != ni), 0.5f0 * (j != 1)) + p3 += sign.(p3 - center) .* Point2f(0.5f0 * (i != ni), 0.5f0 * (j != nj)) + p4 += sign.(p4 - center) .* Point2f(0.5f0 * (i != 1), 0.5f0 * (j != nj)) end Cairo.set_line_width(ctx, 0) @@ -666,15 +791,13 @@ function _draw_rect_heatmap(ctx, xys, ni, nj, colors) end end - ################################################################################ # Mesh # ################################################################################ - function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Makie.Mesh)) mesh = primitive[1][] - if Makie.cameracontrols(scene) isa Union{Camera2D, Makie.PixelCamera, Makie.EmptyCamera} + if Makie.cameracontrols(scene) isa Union{Camera2D,Makie.PixelCamera,Makie.EmptyCamera} draw_mesh2D(scene, screen, primitive, mesh) else if !haskey(primitive, :faceculling) @@ -688,35 +811,41 @@ end function draw_mesh2D(scene, screen, @nospecialize(plot), @nospecialize(mesh)) @get_attribute(plot, (color,)) color = to_color(hasproperty(mesh, :color) ? mesh.color : color) - vs = decompose(Point2f, mesh)::Vector{Point2f} + vs = decompose(Point2f, mesh)::Vector{Point2f} fs = decompose(GLTriangleFace, mesh)::Vector{GLTriangleFace} - uv = decompose_uv(mesh)::Union{Nothing, Vector{Vec2f}} + uv = decompose_uv(mesh)::Union{Nothing,Vector{Vec2f}} model = plot.model[]::Mat4f colormap = haskey(plot, :colormap) ? to_colormap(plot.colormap[]) : nothing - colorrange = convert_attribute(to_value(get(plot, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f} + colorrange = + convert_attribute(to_value(get(plot, :colorrange, nothing)), key"colorrange"())::Union{Nothing,Vec2f} lowclip = get_color_attr(plot, :lowclip) highclip = get_color_attr(plot, :highclip) nan_color = get_color_attr(plot, :nan_color) - cols = per_face_colors( - color, colormap, colorrange, nothing, fs, nothing, uv, - lowclip, highclip, nan_color) + cols = + per_face_colors(color, colormap, colorrange, nothing, fs, nothing, uv, lowclip, highclip, nan_color) space = to_value(get(plot, :space, :data))::Symbol return draw_mesh2D(scene, screen, cols, space, vs, fs, model) end -function draw_mesh2D(scene, screen, per_face_cols, space::Symbol, - vs::Vector{Point2f}, fs::Vector{GLTriangleFace}, model::Mat4f) - +function draw_mesh2D( + scene, + screen, + per_face_cols, + space::Symbol, + vs::Vector{Point2f}, + fs::Vector{GLTriangleFace}, + model::Mat4f, +) ctx = screen.context # Priorize colors of the mesh if present # This is a hack, which needs cleaning up in the Mesh plot type! for (f, (c1, c2, c3)) in zip(fs, per_face_cols) pattern = Cairo.CairoPatternMesh() - t1, t2, t3 = project_position.(scene, space, vs[f], (model,)) #triangle points + t1, t2, t3 = project_position.(scene, space, vs[f], (model,)) #triangle points Cairo.mesh_pattern_begin_patch(pattern) Cairo.mesh_pattern_move_to(pattern, t1...) @@ -738,53 +867,86 @@ end function average_z(positions, face) vs = positions[face] - sum(v -> v[3], vs) / length(vs) + return sum(v -> v[3], vs) / length(vs) end nan2zero(x) = !isnan(x) * x - -function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f0) +function draw_mesh3D(scene, screen, attributes, mesh; pos=Vec4f(0), scale=1.0f0) # Priorize colors of the mesh if present @get_attribute(attributes, (color,)) colormap = haskey(attributes, :colormap) ? to_colormap(attributes.colormap[]) : nothing - colorrange = convert_attribute(to_value(get(attributes, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f} + colorrange = convert_attribute( + to_value(get(attributes, :colorrange, nothing)), + key"colorrange"(), + )::Union{Nothing,Vec2f} matcap = to_value(get(attributes, :matcap, nothing)) color = hasproperty(mesh, :color) ? mesh.color : color meshpoints = decompose(Point3f, mesh)::Vector{Point3f} meshfaces = decompose(GLTriangleFace, mesh)::Vector{GLTriangleFace} meshnormals = decompose_normals(mesh)::Vector{Vec3f} - meshuvs = texturecoordinates(mesh)::Union{Nothing, Vector{Vec2f}} + meshuvs = texturecoordinates(mesh)::Union{Nothing,Vector{Vec2f}} lowclip = get_color_attr(attributes, :lowclip) highclip = get_color_attr(attributes, :highclip) nan_color = get_color_attr(attributes, :nan_color) per_face_col = per_face_colors( - color, colormap, colorrange, matcap, meshfaces, meshnormals, meshuvs, - lowclip, highclip, nan_color + color, + colormap, + colorrange, + matcap, + meshfaces, + meshnormals, + meshuvs, + lowclip, + highclip, + nan_color, ) - @get_attribute(attributes, (shading, diffuse, - specular, shininess, faceculling)) + @get_attribute(attributes, (shading, diffuse, specular, shininess, faceculling)) model = attributes.model[]::Mat4f space = to_value(get(attributes, :space, :data))::Symbol - draw_mesh3D( - scene, screen, space, meshpoints, meshfaces, meshnormals, per_face_col, pos, scale, - model, shading::Bool, diffuse::Vec3f, - specular::Vec3f, shininess::Float32, faceculling::Int + return draw_mesh3D( + scene, + screen, + space, + meshpoints, + meshfaces, + meshnormals, + per_face_col, + pos, + scale, + model, + shading::Bool, + diffuse::Vec3f, + specular::Vec3f, + shininess::Float32, + faceculling::Int, ) end function draw_mesh3D( - scene, screen, space, meshpoints, meshfaces, meshnormals, per_face_col, pos, scale, - model, shading, diffuse, - specular, shininess, faceculling - ) + scene, + screen, + space, + meshpoints, + meshfaces, + meshnormals, + per_face_col, + pos, + scale, + model, + shading, + diffuse, + specular, + shininess, + faceculling, +) ctx = screen.context view = ifelse(is_data_space(space), scene.camera.view[], Mat4f(I)) projection = Makie.space_to_clip(scene.camera, space, false) @@ -799,8 +961,8 @@ function draw_mesh3D( vs = broadcast(meshpoints, (func,)) do v, f # Should v get a nan2zero? v = Makie.apply_transform(f, v, space) - p4d = to_ndim(Vec4f, scale .* to_ndim(Vec3f, v, 0f0), 1f0) - view * (model * p4d .+ to_ndim(Vec4f, pos, 0f0)) + p4d = to_ndim(Vec4f, scale .* to_ndim(Vec3f, v, 0.0f0), 1.0f0) + return view * (model * p4d .+ to_ndim(Vec4f, pos, 0.0f0)) end ns = map(n -> normalize(normalmatrix * n), meshnormals) @@ -828,7 +990,7 @@ function draw_mesh3D( @inbounds begin p = (clip ./ clip[4])[Vec(1, 2)] p_yflip = Vec2f(p[1], -p[2]) - p_0_to_1 = (p_yflip .+ 1f0) ./ 2f0 + p_0_to_1 = (p_yflip .+ 1.0f0) ./ 2.0f0 end p = p_0_to_1 .* scene.camera.resolution[] return Vec3f(p[1], p[2], clip[3]) @@ -841,23 +1003,51 @@ function draw_mesh3D( # Face culling zorder = filter(i -> any(last.(ns[meshfaces[i]]) .> faceculling), zorder) - draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightpos, shininess, diffuse, ambient, specular) + draw_pattern( + ctx, + zorder, + shading, + meshfaces, + ts, + per_face_col, + ns, + vs, + lightpos, + shininess, + diffuse, + ambient, + specular, + ) return end function _calculate_shaded_vertexcolors(N, v, c, lightpos, ambient, diffuse, specular, shininess) - L = normalize(lightpos .- v[Vec(1,2,3)]) - diff_coeff = max(dot(L, N), 0f0) + L = normalize(lightpos .- v[Vec(1, 2, 3)]) + diff_coeff = max(dot(L, N), 0.0f0) H = normalize(L + normalize(-v[Vec(1, 2, 3)])) - spec_coeff = max(dot(H, N), 0f0)^shininess + spec_coeff = max(dot(H, N), 0.0f0)^shininess c = RGBAf(c) # if this is one expression it introduces allocations?? new_c_part1 = (ambient .+ diff_coeff .* diffuse) .* Vec3f(c.r, c.g, c.b) #.+ new_c = new_c_part1 .+ specular * spec_coeff - RGBAf(new_c..., c.alpha) + return RGBAf(new_c..., c.alpha) end -function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightpos, shininess, diffuse, ambient, specular) +function draw_pattern( + ctx, + zorder, + shading, + meshfaces, + ts, + per_face_col, + ns, + vs, + lightpos, + shininess, + diffuse, + ambient, + specular, +) for k in reverse(zorder) pattern = Cairo.CairoPatternMesh() @@ -904,14 +1094,12 @@ function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, Cairo.paint(ctx) Cairo.destroy(pattern) end - end ################################################################################ # Surface # ################################################################################ - function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Makie.Surface)) # Pretend the surface plot is a mesh plot and plot that instead mesh = surface2mesh(primitive[1][], primitive[2][], primitive[3][]) @@ -928,10 +1116,10 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki end function surface2mesh(xs, ys, zs::AbstractMatrix) - ps = Makie.matrix_grid(p-> nan2zero.(p), xs, ys, zs) + ps = Makie.matrix_grid(p -> nan2zero.(p), xs, ys, zs) rect = Tesselation(Rect2f(0, 0, 1, 1), size(zs)) faces = decompose(QuadFace{Int}, rect) - uv = map(x-> Vec2f(1f0 - x[2], 1f0 - x[1]), decompose_uv(rect)) + uv = map(x -> Vec2f(1.0f0 - x[2], 1.0f0 - x[1]), decompose_uv(rect)) uvm = GeometryBasics.Mesh(GeometryBasics.meta(ps; uv=uv), faces) return GeometryBasics.normal_mesh(uvm) end @@ -940,11 +1128,10 @@ end # MeshScatter # ################################################################################ - function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Makie.MeshScatter)) @get_attribute(primitive, (color, model, marker, markersize, rotations)) - if color isa AbstractArray{<: Number} + if color isa AbstractArray{<:Number} color = numbers_to_colors(color, primitive) end @@ -954,8 +1141,8 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki model = copy(model) view = scene.camera.view[] - zorder = sortperm(pos, by = p -> begin - p4d = to_ndim(Vec4f, to_ndim(Vec3f, p, 0f0), 1f0) + zorder = sortperm(pos, by=p -> begin + p4d = to_ndim(Vec4f, to_ndim(Vec3f, p, 0.0f0), 1.0f0) cam_pos = view * model * p4d cam_pos[3] / cam_pos[4] end, rev=false) @@ -963,9 +1150,11 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki submesh = Attributes( model=model, color=color, - shading=primitive.shading, diffuse=primitive.diffuse, - specular=primitive.specular, shininess=primitive.shininess, - faceculling=get(primitive, :faceculling, -10) + shading=primitive.shading, + diffuse=primitive.diffuse, + specular=primitive.specular, + shininess=primitive.shininess, + faceculling=get(primitive, :faceculling, -10), ) if !(rotations isa Vector) @@ -986,8 +1175,12 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki scale = markersize isa Vector ? markersize[i] : markersize draw_mesh3D( - scene, screen, submesh, m, pos = p, - scale = scale isa Real ? Vec3f(scale) : to_ndim(Vec3f, scale, 1f0) + scene, + screen, + submesh, + m, + pos=p, + scale=scale isa Real ? Vec3f(scale) : to_ndim(Vec3f, scale, 1.0f0), ) end diff --git a/CairoMakie/src/screen.jl b/CairoMakie/src/screen.jl index 2dd3f7232df..f6e72d69a0b 100644 --- a/CairoMakie/src/screen.jl +++ b/CairoMakie/src/screen.jl @@ -2,8 +2,8 @@ using Base.Docs: doc @enum RenderType SVG IMAGE PDF EPS -Base.convert(::Type{RenderType}, ::MIME{SYM}) where SYM = mime_to_rendertype(SYM) -function Base.convert(::Type{RenderType}, type::String) +Base.convert(::Type{RenderType}, ::MIME{SYM}) where {SYM} = mime_to_rendertype(SYM) +Base.convert(::Type{RenderType}, type::String) = if type == "png" return IMAGE elseif type == "svg" @@ -15,7 +15,6 @@ function Base.convert(::Type{RenderType}, type::String) else error("Unsupported cairo render type: $type") end -end "Convert a rendering type to a MIME type" function to_mime(type::RenderType) @@ -40,15 +39,13 @@ function mime_to_rendertype(mime::Symbol)::RenderType end end -function surface_from_output_type(mime::MIME{M}, io, w, h) where M - surface_from_output_type(M, io, w, h) -end +surface_from_output_type(mime::MIME{M}, io, w, h) where {M} = surface_from_output_type(M, io, w, h) function surface_from_output_type(mime::Symbol, io, w, h) - surface_from_output_type(mime_to_rendertype(mime), io, w, h) + return surface_from_output_type(mime_to_rendertype(mime), io, w, h) end -function surface_from_output_type(type::RenderType, io, w, h) +surface_from_output_type(type::RenderType, io, w, h) = if type === SVG return Cairo.CairoSVGSurface(io, w, h) elseif type === PDF @@ -61,7 +58,6 @@ function surface_from_output_type(type::RenderType, io, w, h) else error("No available Cairo surface for mode $type") end -end """ Supported options: `[:best => Cairo.ANTIALIAS_BEST, :good => Cairo.ANTIALIAS_GOOD, :subpixel => Cairo.ANTIALIAS_SUBPIXEL, :none => Cairo.ANTIALIAS_NONE]` @@ -71,7 +67,7 @@ function to_cairo_antialias(sym::Symbol) sym == :good && return Cairo.ANTIALIAS_GOOD sym == :subpixel && return Cairo.ANTIALIAS_SUBPIXEL sym == :none && return Cairo.ANTIALIAS_NONE - error("Wrong antialias setting: $(sym). Allowed: :best, :good, :subpixel, :none") + return error("Wrong antialias setting: $(sym). Allowed: :best, :good, :subpixel, :none") end to_cairo_antialias(aa::Int) = aa @@ -161,19 +157,17 @@ function Base.empty!(screen::Screen) Cairo.set_operator(ctx, Cairo.OPERATOR_CLEAR) Cairo.rectangle(ctx, 0, 0, size(screen)...) Cairo.paint_with_alpha(ctx, 1.0) - Cairo.restore(ctx) + return Cairo.restore(ctx) end Base.close(screen::Screen) = empty!(screen) function destroy!(screen::Screen) Cairo.destroy(screen.surface) - Cairo.destroy(screen.context) + return Cairo.destroy(screen.context) end -function Base.isopen(screen::Screen) - return !(screen.surface.ptr == C_NULL || screen.context.ptr == C_NULL) -end +Base.isopen(screen::Screen) = !(screen.surface.ptr == C_NULL || screen.context.ptr == C_NULL) Base.size(screen::Screen) = round.(Int, (screen.surface.width, screen.surface.height)) # we render the scene directly, since we have @@ -186,9 +180,7 @@ function Base.delete!(screen::Screen, scene::Scene, plot::AbstractPlot) # do something here. end -function Base.show(io::IO, ::MIME"text/plain", screen::Screen{S}) where S - println(io, "CairoMakie.Screen{$S}") -end +Base.show(io::IO, ::MIME"text/plain", screen::Screen{S}) where {S} = println(io, "CairoMakie.Screen{$S}") function path_to_type(path) type = splitext(path)[2][2:end] @@ -196,7 +188,6 @@ function path_to_type(path) end to_mime(screen::Screen) = to_mime(screen.typ) - ######################################## # Constructor # ######################################## @@ -222,7 +213,12 @@ function scaled_scene_resolution(typ::RenderType, config::ScreenConfig, scene::S end function Makie.apply_screen_config!( - screen::Screen{SCREEN_RT}, config::ScreenConfig, scene::Scene, io::Union{Nothing, IO}, m::MIME{SYM}) where {SYM, SCREEN_RT} + screen::Screen{SCREEN_RT}, + config::ScreenConfig, + scene::Scene, + io::Union{Nothing,IO}, + m::MIME{SYM}, +) where {SYM,SCREEN_RT} # the surface size is the scene size scaled by the device scaling factor new_rendertype = mime_to_rendertype(SYM) # we need to re-create the screen if the rendertype changes, or for all vector backends @@ -241,7 +237,7 @@ end function Makie.apply_screen_config!(screen::Screen, config::ScreenConfig, scene::Scene, args...) # No mime as an argument implies we want an image based surface - Makie.apply_screen_config!(screen, config, scene, nothing, MIME"image/png"()) + return Makie.apply_screen_config!(screen, config, scene, nothing, MIME"image/png"()) end function Screen(scene::Scene; screen_config...) @@ -251,7 +247,7 @@ end Screen(scene::Scene, config::ScreenConfig) = Screen(scene, config, nothing, IMAGE) -function Screen(screen::Screen, io_or_path::Union{Nothing, String, IO}, typ::Union{MIME, Symbol, RenderType}) +function Screen(screen::Screen, io_or_path::Union{Nothing,String,IO}, typ::Union{MIME,Symbol,RenderType}) rtype = convert(RenderType, typ) # the resolution may change between rendertypes, so, we can't just use `size(screen)` here for recreating the Screen: w, h = scaled_scene_resolution(rtype, screen.config, screen.scene) @@ -259,7 +255,12 @@ function Screen(screen::Screen, io_or_path::Union{Nothing, String, IO}, typ::Uni return Screen(screen.scene, screen.config, surface) end -function Screen(scene::Scene, config::ScreenConfig, io_or_path::Union{Nothing, String, IO}, typ::Union{MIME, Symbol, RenderType}) +function Screen( + scene::Scene, + config::ScreenConfig, + io_or_path::Union{Nothing,String,IO}, + typ::Union{MIME,Symbol,RenderType}, +) rtype = convert(RenderType, typ) w, h = scaled_scene_resolution(rtype, config, scene) surface = surface_from_output_type(rtype, io_or_path, w, h) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index 695f957aa0e..94909a62e56 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -2,38 +2,36 @@ # Projection utilities # ################################################################################ -function project_position(scene, transform_func::T, space, point, model, yflip::Bool = true) where T +function project_position(scene, transform_func::T, space, point, model, yflip::Bool=true) where {T} # use transform func point = Makie.apply_transform(transform_func, point, space) - _project_position(scene, space, point, model, yflip) + return _project_position(scene, space, point, model, yflip) end function _project_position(scene, space, point, model, yflip) res = scene.camera.resolution[] - p4d = to_ndim(Vec4f, to_ndim(Vec3f, point, 0f0), 1f0) + p4d = to_ndim(Vec4f, to_ndim(Vec3f, point, 0.0f0), 1.0f0) clip = Makie.space_to_clip(scene.camera, space) * model * p4d @inbounds begin # between -1 and 1 p = (clip ./ clip[4])[Vec(1, 2)] # flip y to match cairo - p_yflip = Vec2f(p[1], (1f0 - 2f0 * yflip) * p[2]) + p_yflip = Vec2f(p[1], (1.0f0 - 2.0f0 * yflip) * p[2]) # normalize to between 0 and 1 - p_0_to_1 = (p_yflip .+ 1f0) ./ 2f0 + p_0_to_1 = (p_yflip .+ 1.0f0) ./ 2.0f0 end # multiply with scene resolution for final position return p_0_to_1 .* res end -function project_position(scene, space, point, model, yflip::Bool = true) - project_position(scene, scene.transformation.transform_func[], space, point, model, yflip) +function project_position(scene, space, point, model, yflip::Bool=true) + return project_position(scene, scene.transformation.transform_func[], space, point, model, yflip) end -function project_scale(scene::Scene, space, s::Number, model = Mat4f(I)) - project_scale(scene, space, Vec2f(s), model) -end +project_scale(scene::Scene, space, s::Number, model=Mat4f(I)) = project_scale(scene, space, Vec2f(s), model) -function project_scale(scene::Scene, space, s, model = Mat4f(I)) - p4d = model * to_ndim(Vec4f, s, 0f0) +function project_scale(scene::Scene, space, s, model=Mat4f(I)) + p4d = model * to_ndim(Vec4f, s, 0.0f0) if is_data_space(space) @inbounds p = (scene.camera.projectionview[] * p4d)[Vec(1, 2)] return p .* scene.camera.resolution[] .* 0.5 @@ -52,10 +50,10 @@ function project_rect(scene, space, rect::Rect, model) return Rect(mini, maxi .- mini) end -function project_polygon(scene, space, poly::P, model) where P <: Polygon +function project_polygon(scene, space, poly::P, model) where {P<:Polygon} ext = decompose(Point2f, poly.exterior) interiors = decompose.(Point2f, poly.interiors) - Polygon( + return Polygon( Point2f.(project_position.(Ref(scene), space, ext, Ref(model))), [Point2f.(project_position.(Ref(scene), space, interior, Ref(model))) for interior in interiors], ) @@ -74,7 +72,7 @@ end function to_2d_rotation(::Makie.Billboard) @warn "This should not be reachable!" - 0 + return 0 end remove_billboard(x) = x @@ -93,14 +91,13 @@ to_2d_rotation(vec::Vec2f) = atan(vec[1], vec[2]) to_2d_rotation(n::Real) = n - ################################################################################ # Color handling # ################################################################################ function rgbatuple(c::Colorant) rgba = RGBA(c) - red(rgba), green(rgba), blue(rgba), alpha(rgba) + return red(rgba), green(rgba), blue(rgba), alpha(rgba) end function rgbatuple(c) @@ -117,21 +114,21 @@ to_uint32_color(c) = reinterpret(UInt32, convert(ARGB32, premultiplied_rgba(c))) # Image/heatmap -> ARGBSurface # ######################################## -function to_cairo_image(img::AbstractMatrix{<: AbstractFloat}, attributes) - to_cairo_image(to_rgba_image(img, attributes), attributes) +function to_cairo_image(img::AbstractMatrix{<:AbstractFloat}, attributes) + return to_cairo_image(to_rgba_image(img, attributes), attributes) end -function to_rgba_image(img::AbstractMatrix{<: AbstractFloat}, attributes) +function to_rgba_image(img::AbstractMatrix{<:AbstractFloat}, attributes) Makie.@get_attribute attributes (colormap, colorrange, nan_color, lowclip, highclip) nan_color = Makie.to_color(nan_color) lowclip = isnothing(lowclip) ? lowclip : Makie.to_color(lowclip) highclip = isnothing(highclip) ? highclip : Makie.to_color(highclip) - [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in img] + return [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in img] end -to_rgba_image(img::AbstractMatrix{<: Colorant}, attributes) = RGBAf.(img) +to_rgba_image(img::AbstractMatrix{<:Colorant}, attributes) = RGBAf.(img) function get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) vmin, vmax = colorrange @@ -146,8 +143,8 @@ function get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highcli end end -function to_cairo_image(img::AbstractMatrix{<: Colorant}, attributes) - to_cairo_image(to_uint32_color.(img), attributes) +function to_cairo_image(img::AbstractMatrix{<:Colorant}, attributes) + return to_cairo_image(to_uint32_color.(img), attributes) end function to_cairo_image(img::Matrix{UInt32}, attributes) @@ -156,52 +153,56 @@ function to_cairo_image(img::Matrix{UInt32}, attributes) return Cairo.CairoARGBSurface(permutedims(img)) end - ################################################################################ # Mesh handling # ################################################################################ -struct FaceIterator{Iteration, T, F, ET} <: AbstractVector{ET} +struct FaceIterator{Iteration,T,F,ET} <: AbstractVector{ET} data::T faces::F end -function (::Type{FaceIterator{Typ}})(data::T, faces::F) where {Typ, T, F} - FaceIterator{Typ, T, F}(data, faces) +(::Type{FaceIterator{Typ}})(data::T, faces::F) where {Typ,T,F} = FaceIterator{Typ,T,F}(data, faces) +function (::Type{FaceIterator{Typ,T,F}})(data::AbstractVector, faces::F) where {Typ,F,T} + return FaceIterator{Typ,T,F,NTuple{3,eltype(data)}}(data, faces) end -function (::Type{FaceIterator{Typ, T, F}})(data::AbstractVector, faces::F) where {Typ, F, T} - FaceIterator{Typ, T, F, NTuple{3, eltype(data)}}(data, faces) +function (::Type{FaceIterator{Typ,T,F}})(data::T, faces::F) where {Typ,T,F} + return FaceIterator{Typ,T,F,NTuple{3,T}}(data, faces) end -function (::Type{FaceIterator{Typ, T, F}})(data::T, faces::F) where {Typ, T, F} - FaceIterator{Typ, T, F, NTuple{3, T}}(data, faces) -end -function FaceIterator(data::AbstractVector, faces) +FaceIterator(data::AbstractVector, faces) = if length(data) == length(faces) FaceIterator{:PerFace}(data, faces) else FaceIterator{:PerVert}(data, faces) end -end Base.size(fi::FaceIterator) = size(fi.faces) Base.getindex(fi::FaceIterator{:PerFace}, i::Integer) = fi.data[i] Base.getindex(fi::FaceIterator{:PerVert}, i::Integer) = fi.data[fi.faces[i]] -Base.getindex(fi::FaceIterator{:Const}, i::Integer) = ntuple(i-> fi.data, 3) +Base.getindex(fi::FaceIterator{:Const}, i::Integer) = ntuple(i -> fi.data, 3) color_or_nothing(c) = isnothing(c) ? nothing : to_color(c) -function get_color_attr(attributes, attribute)::Union{Nothing, RGBAf} +function get_color_attr(attributes, attribute)::Union{Nothing,RGBAf} return color_or_nothing(to_value(get(attributes, attribute, nothing))) end function per_face_colors( - color, colormap, colorrange, matcap, faces, normals, uv, - lowclip=nothing, highclip=nothing, nan_color=nothing - ) + color, + colormap, + colorrange, + matcap, + faces, + normals, + uv, + lowclip=nothing, + highclip=nothing, + nan_color=nothing, +) if matcap !== nothing wsize = reverse(size(matcap)) wh = wsize .- 1 cvec = map(normals) do n - muv = 0.5n[Vec(1,2)] .+ Vec2f(0.5) + muv = 0.5n[Vec(1, 2)] .+ Vec2f(0.5) x, y = clamp.(round.(Int, Tuple(muv) .* wh) .+ 1, 1, wh) return matcap[end - (y - 1), x] end @@ -209,9 +210,9 @@ function per_face_colors( elseif color isa Colorant return FaceIterator{:Const}(color, faces) elseif color isa AbstractArray - if color isa AbstractVector{<: Colorant} + if color isa AbstractVector{<:Colorant} return FaceIterator(color, faces) - elseif color isa AbstractArray{<: Number} + elseif color isa AbstractArray{<:Number} low, high = extrema(colorrange) cvec = map(color[:]) do c if isnan(c) && nan_color !== nothing @@ -228,7 +229,7 @@ function per_face_colors( elseif color isa Makie.AbstractPattern # let next level extend and fill with CairoPattern return color - elseif color isa AbstractMatrix{<: Colorant} && uv !== nothing + elseif color isa AbstractMatrix{<:Colorant} && uv !== nothing wsize = reverse(size(color)) wh = wsize .- 1 cvec = map(uv) do uv @@ -240,11 +241,11 @@ function per_face_colors( return FaceIterator(cvec, faces) end end - error("Unsupported Color type: $(typeof(color))") + return error("Unsupported Color type: $(typeof(color))") end function mesh_pattern_set_corner_color(pattern, id, c::Colorant) - Cairo.mesh_pattern_set_corner_color_rgba(pattern, id, rgbatuple(c)...) + return Cairo.mesh_pattern_set_corner_color_rgba(pattern, id, rgbatuple(c)...) end # not piracy @@ -260,7 +261,7 @@ end Finds a font that can represent the unicode character! Returns Makie.defaultfont() if not representable! """ -function best_font(c::Char, font = Makie.defaultfont()) +function best_font(c::Char, font=Makie.defaultfont()) if Makie.FreeType.FT_Get_Char_Index(font, c) == 0 for afont in Makie.alternativefonts() if Makie.FreeType.FT_Get_Char_Index(afont, c) != 0 diff --git a/CairoMakie/test/rasterization_tests.jl b/CairoMakie/test/rasterization_tests.jl index 8554bfad939..5bc9d682137 100644 --- a/CairoMakie/test/rasterization_tests.jl +++ b/CairoMakie/test/rasterization_tests.jl @@ -1,6 +1,6 @@ # guard against some future changes silently making simple vector graphics be # rasterized if they are using features unsupported by the SVG spec -function svg_has_image(x) +svg_has_image(x) = mktempdir() do path path = joinpath(path, "test.svg") save(path, x) @@ -8,13 +8,12 @@ function svg_has_image(x) # if an image element is present in the svg return !occursin(" png" begin # Now that scene.current_screens contains a CairoMakie screen after save @@ -34,7 +33,6 @@ include(joinpath(@__DIR__, "rasterization_tests.jl")) @test isfile("test.png") rm("test.png") rm("test.svg") - end @testset "saving pdf two times" begin @@ -72,7 +70,7 @@ include(joinpath(@__DIR__, "rasterization_tests.jl")) @testset "changing resolution of same format" begin # see: https://github.com/MakieOrg/Makie.jl/issues/2433 # and: https://github.com/MakieOrg/AlgebraOfGraphics.jl/pull/441 - scene = Scene(resolution=(800, 800)); + scene = Scene(resolution=(800, 800)) load_save(s; kw...) = (save("test.png", s; kw...); load("test.png")) @test size(load_save(scene, px_per_unit=2)) == (1600, 1600) @test size(load_save(scene, px_per_unit=1)) == (800, 800) @@ -105,7 +103,11 @@ end @testset "VideoStream & screen options" begin N = 3 points = Observable(Point2f[]) - f, ax, pl = scatter(points, axis=(type=Axis, aspect=DataAspect(), limits=(0.4, N + 0.6, 0.4, N + 0.6),), figure=(resolution=(600, 800),)) + f, ax, pl = scatter( + points, + axis=(type=Axis, aspect=DataAspect(), limits=(0.4, N + 0.6, 0.4, N + 0.6)), + figure=(resolution=(600, 800),), + ) vio = Makie.VideoStream(f; format="mp4", px_per_unit=2.0, backend=CairoMakie) @test vio.screen isa CairoMakie.Screen{CairoMakie.IMAGE} @test size(vio.screen) == size(f.scene) .* 2 @@ -167,15 +169,15 @@ excludes = Set([ "fast pixel marker", "scatter with glow", "scatter with stroke", - "heatmaps & surface" + "heatmaps & surface", ]) functions = [:volume, :volume!, :uv_mesh] @testset "refimages" begin - CairoMakie.activate!(type = "png") + CairoMakie.activate!(type="png") ReferenceTests.mark_broken_tests(excludes, functions=functions) recorded_files, recording_dir = @include_reference_tests "refimages.jl" missing_images, scores = ReferenceTests.record_comparison(recording_dir) - ReferenceTests.test_comparison(scores; threshold = 0.032) + ReferenceTests.test_comparison(scores; threshold=0.032) end diff --git a/CairoMakie/test/svg_tests.jl b/CairoMakie/test/svg_tests.jl index 580d11dbc46..fa8f25fb5a0 100644 --- a/CairoMakie/test/svg_tests.jl +++ b/CairoMakie/test/svg_tests.jl @@ -1,6 +1,6 @@ # guard against some future changes silently making simple vector graphics be # rasterized if they are using features unsupported by the SVG spec -function svg_isnt_rasterized(x) +svg_isnt_rasterized(x) = mktempdir() do path path = joinpath(path, "test.svg") save(path, x) @@ -8,11 +8,14 @@ function svg_isnt_rasterized(x) # if an image element is present in the svg return !occursin(" display -mesh(Sphere(Point3f(0), 1f0), color=:red, ambient=Vec3f(0.9)) +display(mesh(Sphere(Point3f(0), 1.0f0))) +mesh(Sphere(Point3f(0), 1.0f0), color=:red, ambient=Vec3f(0.9)) tocolor(x) = RGBf(x...) -positions = Observable(decompose(Point3f, Sphere(Point3f(0), 1f0))) -triangles = Observable(decompose(GLTriangleFace, Sphere(Point3f(0), 1f0))) -uv = Observable(GeometryBasics.decompose_uv(Sphere(Point3f(0), 1f0))) +positions = Observable(decompose(Point3f, Sphere(Point3f(0), 1.0f0))) +triangles = Observable(decompose(GLTriangleFace, Sphere(Point3f(0), 1.0f0))) +uv = Observable(GeometryBasics.decompose_uv(Sphere(Point3f(0), 1.0f0))) xyz_vertex_color = Observable(tocolor.(positions[])) texture = Observable(rand(RGBAf, 10, 10)) @@ -24,7 +24,7 @@ GeometryBasics.coordinates(mesh); using ShaderAbstractions: data -posmeta = Buffer(meta(data(pos_buff); color = data(vert_color_buff))) +posmeta = Buffer(meta(data(pos_buff); color=data(vert_color_buff))) program = disp.renderlist[1][3].vertexarray.program @@ -43,10 +43,7 @@ p = ShaderAbstractions.Program( println(p.vertex_source) -uniforms = Dict{Symbol, Any}( - :texturecoordinates => Vec2f(0), - :image => nothing -) +uniforms = Dict{Symbol,Any}(:texturecoordinates => Vec2f(0), :image => nothing) rshader = GLMakie.GLAbstraction.gl_convert(shader, uniforms) vbo = GLMakie.GLAbstraction.GLVertexArray(program, posmeta, triangles_buff) @@ -54,77 +51,85 @@ vbo = GLMakie.GLAbstraction.GLVertexArray(program, posmeta, triangles_buff) m = GeometryBasics.Mesh(posmeta, triangles_buff) disp = display(Makie.mesh(m, show_axis=false)); - mesh_normals = GeometryBasics.normals(positions, triangles) coords = meta(positions, color=xyz_vertex_color, normals=mesh_normals) vertexcolor_mesh = GeometryBasics.Mesh(coords, triangles) -scren = mesh(vertexcolor_mesh, show_axis=false) |> display - +scren = display(mesh(vertexcolor_mesh, show_axis=false)) function getter_function(io::IO, ::Fragment, sampler::Sampler, name::Symbol) index_t = type_string(context, sampler.values) sampler_t = type_string(context, sampler.colors) - println(io, """ - in $(value_t) fragment_$(name)_index; - uniform $(sampler_t) $(name)_texture; + return println( + io, + """ +in $(value_t) fragment_$(name)_index; +uniform $(sampler_t) $(name)_texture; - vec4 get_$(name)(){ - return texture($(name)_texture, fragment_$(name)_index); - } - """) +vec4 get_$(name)(){ + return texture($(name)_texture, fragment_$(name)_index); +} +""", + ) end function getter_function(io::IO, ::Vertex, sampler::Sampler, name::Symbol) index_t = type_string(context, sampler.values) - println(io, """ - in $(index_t) $(name)_index; - out $(index_t) fragment_$(name)_index; - - vec4 get_$(name)(){ - fragment_uv = uv; - // color gets calculated in fragment! - return vec4(0); - } - """) + return println( + io, + """ +in $(index_t) $(name)_index; +out $(index_t) fragment_$(name)_index; + +vec4 get_$(name)(){ + fragment_uv = uv; + // color gets calculated in fragment! + return vec4(0); +} +""", + ) end -function getter_function(io::IO, ::Fragment, ::AbstractVector{T}, name) where T +function getter_function(io::IO, ::Fragment, ::AbstractVector{T}, name) where {T} t_str = type_string(context, T) - println(io, """ - in $(t_str) fragment_$(name); - $(t_str) get_$(name)(){ - return fragment_$(name); - } - """) + return println( + io, + """ +in $(t_str) fragment_$(name); +$(t_str) get_$(name)(){ + return fragment_$(name); +} +""", + ) end -function getter_function(io::IO, ::Vertex, ::AbstractVector{T}, name) where T +function getter_function(io::IO, ::Vertex, ::AbstractVector{T}, name) where {T} t_str = type_string(context, T) - println(io, """ - in $(t_str) $(name); - out $(t_str) fragment_$(name); - - $(t_str) get_$(name)(){ - fragment_$(name) = $(name); - return $(name); - } - """) + return println( + io, + """ +in $(t_str) $(name); +out $(t_str) fragment_$(name); + +$(t_str) get_$(name)(){ + fragment_$(name) = $(name); + return $(name); +} +""", + ) end texsampler = Makie.sampler(rand(RGBf, 4, 4), uv) coords = meta(positions, color=texsampler, normals=mesh_normals) texture_mesh = GeometryBasics.Mesh(coords, triangles) -scren = mesh(texture_mesh, show_axis=false) |> display +scren = display(mesh(texture_mesh, show_axis=false)) texsampler = Makie.sampler(:viridis, rand(length(positions))) coords = meta(positions, color=texsampler, normals=mesh_normals) texture_mesh = GeometryBasics.Mesh(coords, triangles) -scren = mesh(texture_mesh, show_axis=false) |> display - - +scren = display(mesh(texture_mesh, show_axis=false)) glsl""" diff --git a/GLMakie/src/GLAbstraction/AbstractGPUArray.jl b/GLMakie/src/GLAbstraction/AbstractGPUArray.jl index b016ec28854..6d224cc6287 100644 --- a/GLMakie/src/GLAbstraction/AbstractGPUArray.jl +++ b/GLMakie/src/GLAbstraction/AbstractGPUArray.jl @@ -9,42 +9,43 @@ import Base: map import Base: size import Base: iterate -abstract type GPUArray{T, NDim} <: AbstractArray{T, NDim} end +abstract type GPUArray{T,NDim} <: AbstractArray{T,NDim} end size(A::GPUArray) = A.size -function checkdimensions(value::Array, ranges::Union{Integer, UnitRange}...) - array_size = size(value) +function checkdimensions(value::Array, ranges::Union{Integer,UnitRange}...) + array_size = size(value) indexes_size = map(length, ranges) - (array_size != indexes_size) && throw(DimensionMismatch("asigning a $array_size to a $(indexes_size) location")) + (array_size != indexes_size) && + throw(DimensionMismatch("asigning a $array_size to a $(indexes_size) location")) return true end -function to_range(index) +to_range(index) = map(index) do val isa(val, Integer) && return val:val isa(val, AbstractRange) && return val - error("Indexing only defined for integers or ranges. Found: $val") + return error("Indexing only defined for integers or ranges. Found: $val") end -end -setindex!(A::GPUArray{T, N}, value::Union{T, Array{T, N}}) where {T, N} = (A[1] = value) +setindex!(A::GPUArray{T,N}, value::Union{T,Array{T,N}}) where {T,N} = (A[1] = value) -function setindex!(A::GPUArray{T, N}, value, indices::Vararg{<: Integer, N}) where {T, N} - v = Array{T, N}(undef, ntuple(i-> 1, N)) +function setindex!(A::GPUArray{T,N}, value, indices::Vararg{<:Integer,N}) where {T,N} + v = Array{T,N}(undef, ntuple(i -> 1, N)) v[1] = convert(T, value) - setindex!(A, v, (:).(indices, indices)...) + return setindex!(A, v, (:).(indices, indices)...) end -function setindex!(A::GPUArray{T, N}, value, indexes...) where {T, N} +function setindex!(A::GPUArray{T,N}, value, indexes...) where {T,N} ranges = to_range(Base.to_indices(A, indexes)) v = isa(value, T) ? [value] : convert(Array{T,N}, value) - setindex!(A, v, ranges...) + return setindex!(A, v, ranges...) end -setindex!(A::GPUArray{T, 2}, value::Vector{T}, i::Integer, range::UnitRange) where {T} = - (A[i, range] = reshape(value, (length(value),1))) +function setindex!(A::GPUArray{T,2}, value::Vector{T}, i::Integer, range::UnitRange) where {T} + return (A[i, range] = reshape(value, (length(value), 1))) +end -function setindex!(A::GPUArray{T, N}, value::Array{T, N}, ranges::UnitRange...) where {T, N} +function setindex!(A::GPUArray{T,N}, value::Array{T,N}, ranges::UnitRange...) where {T,N} checkbounds(A, ranges...) checkdimensions(value, ranges...) gpu_setindex!(A, value, ranges...) @@ -52,10 +53,8 @@ function setindex!(A::GPUArray{T, N}, value::Array{T, N}, ranges::UnitRange...) end ShaderAbstractions.switch_context!(A::GPUArray) = switch_context!(A.context) -function update!(A::GPUArray{T, N}, value::AbstractArray{T2, N}) where {T, N, T2} - update!(A, convert(Array{T, N}, value)) -end -function update!(A::GPUArray{T, N}, value::AbstractArray{T, N}) where {T, N} +update!(A::GPUArray{T,N}, value::AbstractArray{T2,N}) where {T,N,T2} = update!(A, convert(Array{T,N}, value)) +function update!(A::GPUArray{T,N}, value::AbstractArray{T,N}) where {T,N} switch_context!(A) if length(A) != length(value) if isa(A, GLBuffer) @@ -68,70 +67,69 @@ function update!(A::GPUArray{T, N}, value::AbstractArray{T, N}) where {T, N} error("Dynamic resizing not implemented for $(typeof(A))") end end - dims = map(x-> 1:x, size(A)) + dims = map(x -> 1:x, size(A)) A[dims...] = value return end update!(A::GPUArray, value::ShaderAbstractions.Sampler) = update!(A, value.data) -function getindex(A::GPUArray{T, N}, i::Int) where {T, N} +function getindex(A::GPUArray{T,N}, i::Int) where {T,N} checkbounds(A, i) - gpu_getindex(A, i:i)[1] # not as bad as its looks, as so far gpu data must be loaded into an array anyways + return gpu_getindex(A, i:i)[1] # not as bad as its looks, as so far gpu data must be loaded into an array anyways end -function getindex(A::GPUArray{T, N}, ranges::UnitRange...) where {T, N} +function getindex(A::GPUArray{T,N}, ranges::UnitRange...) where {T,N} checkbounds(A, ranges...) - gpu_getindex(A, ranges...) + return gpu_getindex(A, ranges...) end -mutable struct GPUVector{T} <: GPUArray{T, 1} - buffer - size - real_length +mutable struct GPUVector{T} <: GPUArray{T,1} + buffer::Any + size::Any + real_length::Any end GPUVector(x::GPUArray) = GPUVector{eltype(x)}(x, size(x), length(x)) -function update!(A::GPUVector{T}, value::AbstractVector{T}) where T +function update!(A::GPUVector{T}, value::AbstractVector{T}) where {T} if isa(A, GLBuffer) && (length(A) != length(value)) resize!(A, length(value)) end - dims = map(x->1:x, size(A)) + dims = map(x -> 1:x, size(A)) A.buffer[dims...] = value return end size(v::GPUVector) = v.size -iterate(b::GPUVector, state = 1) = iterate(b.buffer, state) +iterate(b::GPUVector, state=1) = iterate(b.buffer, state) gpu_data(A::GPUVector) = A.buffer[1:length(A)] getindex(v::GPUVector, index::Int) = v.buffer[index] getindex(v::GPUVector, index::UnitRange) = v.buffer[index] setindex!(v::GPUVector{T}, value::T, index::Int) where {T} = v.buffer[index] = value setindex!(v::GPUVector{T}, value::T, index::UnitRange) where {T} = v.buffer[index] = value - function grow_dimensions(real_length::Int, _size::Int, additonal_size::Int, growfactor::Real=1.5) - new_dim = round(Int, real_length*growfactor) - return max(new_dim, additonal_size+_size) + new_dim = round(Int, real_length * growfactor) + return max(new_dim, additonal_size + _size) end -function Base.push!(v::GPUVector{T}, x::AbstractVector{T}) where T +function Base.push!(v::GPUVector{T}, x::AbstractVector{T}) where {T} lv, lx = length(v), length(x) - if (v.real_length < lv+lx) + if (v.real_length < lv + lx) resize!(v.buffer, grow_dimensions(v.real_length, lv, lx)) end - v.buffer[lv+1:(lv+lx)] = x - v.real_length = length(v.buffer) - v.size = (lv+lx,) - v + v.buffer[(lv + 1):(lv + lx)] = x + v.real_length = length(v.buffer) + v.size = (lv + lx,) + return v end push!(v::GPUVector{T}, x::T) where {T} = push!(v, [x]) push!(v::GPUVector{T}, x::T...) where {T} = push!(v, [x...]) append!(v::GPUVector{T}, x::Vector{T}) where {T} = push!(v, x) -resize!(A::GPUArray{T, NDim}, dims::Int...) where {T, NDim} = resize!(A, dims) -function resize!(A::GPUArray{T, NDim}, newdims::NTuple{NDim, Int}) where {T, NDim} +resize!(A::GPUArray{T,NDim}, dims::Int...) where {T,NDim} = resize!(A, dims) +function resize!(A::GPUArray{T,NDim}, newdims::NTuple{NDim,Int}) where {T,NDim} newdims == size(A) && return A gpu_resize!(A, newdims) - A + return A end function resize!(v::GPUVector, newlength::Int) @@ -139,24 +137,24 @@ function resize!(v::GPUVector, newlength::Int) v.size = (max(0, newlength),) return v end - resize!(v.buffer, grow_dimensions(v.real_length, length(v), newlength-length(v))) - v.size = (newlength,) - v.real_length = length(v.buffer) + resize!(v.buffer, grow_dimensions(v.real_length, length(v), newlength - length(v))) + v.size = (newlength,) + return v.real_length = length(v.buffer) end function grow_at(v::GPUVector, index::Int, amount::Int) - resize!(v, length(v)+amount) - copy!(v, index, v, index+amount, amount) + resize!(v, length(v) + amount) + return copy!(v, index, v, index + amount, amount) end -function splice!(v::GPUVector{T}, index::UnitRange, x::Vector=T[]) where T +function splice!(v::GPUVector{T}, index::UnitRange, x::Vector=T[]) where {T} lenv = length(v) - elements_to_grow = length(x)-length(index) # -1 - buffer = similar(v.buffer, length(v)+elements_to_grow) - copy!(v.buffer, 1, buffer, 1, first(index)-1) # copy first half - copy!(v.buffer, last(index)+1, buffer, first(index)+length(x), lenv-last(index)) # shift second half - v.buffer = buffer + elements_to_grow = length(x) - length(index) # -1 + buffer = similar(v.buffer, length(v) + elements_to_grow) + copy!(v.buffer, 1, buffer, 1, first(index) - 1) # copy first half + copy!(v.buffer, last(index) + 1, buffer, first(index) + length(x), lenv - last(index)) # shift second half + v.buffer = buffer v.real_length = length(buffer) - v.size = (v.real_length,) + v.size = (v.real_length,) copy!(x, 1, buffer, first(index), length(x)) # copy contents of insertion vector return end @@ -164,36 +162,69 @@ end splice!(v::GPUVector{T}, index::Int, x::T) where {T} = v[index] = x splice!(v::GPUVector{T}, index::Int, x::Vector=T[]) where {T} = splice!(v, index:index, map(T, x)) +function copy!(a::GPUVector, a_offset::Int, b::Vector, b_offset::Int, amount::Int) + return copy!(a.buffer, a_offset, b, b_offset, amount) +end +function copy!(a::GPUVector, a_offset::Int, b::GPUVector, b_offset::Int, amount::Int) + return copy!(a.buffer, a_offset, b.buffer, b_offset, amount) +end -copy!(a::GPUVector, a_offset::Int, b::Vector, b_offset::Int, amount::Int) = copy!(a.buffer, a_offset, b, b_offset, amount) -copy!(a::GPUVector, a_offset::Int, b::GPUVector, b_offset::Int, amount::Int)= copy!(a.buffer, a_offset, b.buffer, b_offset, amount) - - -copy!(a::GPUArray, a_offset::Int, b::Vector, b_offset::Int, amount::Int) = _copy!(a, a_offset, b, b_offset, amount) -copy!(a::Vector, a_offset::Int, b::GPUArray, b_offset::Int, amount::Int) = _copy!(a, a_offset, b, b_offset, amount) -copy!(a::GPUArray, a_offset::Int, b::GPUArray, b_offset::Int, amount::Int) = _copy!(a, a_offset, b, b_offset, amount) +function copy!(a::GPUArray, a_offset::Int, b::Vector, b_offset::Int, amount::Int) + return _copy!(a, a_offset, b, b_offset, amount) +end +function copy!(a::Vector, a_offset::Int, b::GPUArray, b_offset::Int, amount::Int) + return _copy!(a, a_offset, b, b_offset, amount) +end +function copy!(a::GPUArray, a_offset::Int, b::GPUArray, b_offset::Int, amount::Int) + return _copy!(a, a_offset, b, b_offset, amount) +end #don't overwrite Base.copy! with a::Vector, b::Vector -function _copy!(a::Union{Vector, GPUArray}, a_offset::Int, b::Union{Vector, GPUArray}, b_offset::Int, amount::Int) +function _copy!( + a::Union{Vector,GPUArray}, + a_offset::Int, + b::Union{Vector,GPUArray}, + b_offset::Int, + amount::Int, +) (amount <= 0) && return nothing - @assert a_offset > 0 && (a_offset-1) + amount <= length(a) "a_offset $a_offset, amount $amount, lengtha $(length(a))" - @assert b_offset > 0 && (b_offset-1) + amount <= length(b) "b_offset $b_offset, amount $amount, lengthb $(length(b))" + @assert a_offset > 0 && (a_offset - 1) + amount <= length(a) "a_offset $a_offset, amount $amount, lengtha $(length(a))" + @assert b_offset > 0 && (b_offset - 1) + amount <= length(b) "b_offset $b_offset, amount $amount, lengthb $(length(b))" unsafe_copy!(a, a_offset, b, b_offset, amount) return nothing end # Interface: -gpu_data(t) = error("gpu_data not implemented for: $(typeof(t)). This happens, when you call data on an array, without implementing the GPUArray interface") -gpu_resize!(t) = error("gpu_resize! not implemented for: $(typeof(t)). This happens, when you call resize! on an array, without implementing the GPUArray interface") -gpu_getindex(t) = error("gpu_getindex not implemented for: $(typeof(t)). This happens, when you call getindex on an array, without implementing the GPUArray interface") -gpu_setindex!(t) = error("gpu_setindex! not implemented for: $(typeof(t)). This happens, when you call setindex! on an array, without implementing the GPUArray interface") -max_dim(t) = error("max_dim not implemented for: $(typeof(t)). This happens, when you call setindex! on an array, without implementing the GPUArray interface") - +function gpu_data(t) + return error( + "gpu_data not implemented for: $(typeof(t)). This happens, when you call data on an array, without implementing the GPUArray interface", + ) +end +function gpu_resize!(t) + return error( + "gpu_resize! not implemented for: $(typeof(t)). This happens, when you call resize! on an array, without implementing the GPUArray interface", + ) +end +function gpu_getindex(t) + return error( + "gpu_getindex not implemented for: $(typeof(t)). This happens, when you call getindex on an array, without implementing the GPUArray interface", + ) +end +function gpu_setindex!(t) + return error( + "gpu_setindex! not implemented for: $(typeof(t)). This happens, when you call setindex! on an array, without implementing the GPUArray interface", + ) +end +function max_dim(t) + return error( + "max_dim not implemented for: $(typeof(t)). This happens, when you call setindex! on an array, without implementing the GPUArray interface", + ) +end -function (::Type{GPUArrayType})(data::Observable; kw...) where GPUArrayType <: GPUArray +function (::Type{GPUArrayType})(data::Observable; kw...) where {GPUArrayType<:GPUArray} gpu_mem = GPUArrayType(data[]; kw...) # TODO merge these and handle update tracking during contruction - obs1 = on(_-> gpu_mem.requires_update[] = true, data) + obs1 = on(_ -> gpu_mem.requires_update[] = true, data) obs2 = on(new_data -> update!(gpu_mem, new_data), data) if GPUArrayType <: TextureBuffer push!(gpu_mem.buffer.observers, obs1, obs2) diff --git a/GLMakie/src/GLAbstraction/GLAbstraction.jl b/GLMakie/src/GLAbstraction/GLAbstraction.jl index 67657c15191..ec77d0a215d 100644 --- a/GLMakie/src/GLAbstraction/GLAbstraction.jl +++ b/GLMakie/src/GLAbstraction/GLAbstraction.jl @@ -63,7 +63,8 @@ export opengl_compatible # infers if a type is opengl compatible and retu export cardinality # returns the cardinality of the elements of a buffer export mergedefault! # merges a style dict via a given style -export TOrSignal, VecOrSignal, ArrayOrSignal, MatOrSignal, VolumeOrSignal, ArrayTypes, VectorTypes, MatTypes, VolumeTypes +export TOrSignal, + VecOrSignal, ArrayOrSignal, MatOrSignal, VolumeOrSignal, ArrayTypes, VectorTypes, MatTypes, VolumeTypes export MouseButton, MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT include("GLExtendedFunctions.jl") @@ -87,7 +88,6 @@ export toglsltype_string # infers a glsl type string from a julia type. E # only difference to GLSL: first character is uppercase uppercase export gl_convert - include("GLRender.jl") export render #renders arbitrary objects export enabletransparency # can be pushed to an renderobject, enables transparency diff --git a/GLMakie/src/GLAbstraction/GLBuffer.jl b/GLMakie/src/GLAbstraction/GLBuffer.jl index cc071d589bc..dc1f32b807d 100644 --- a/GLMakie/src/GLAbstraction/GLBuffer.jl +++ b/GLMakie/src/GLAbstraction/GLBuffer.jl @@ -1,6 +1,6 @@ -mutable struct GLBuffer{T} <: GPUArray{T, 1} +mutable struct GLBuffer{T} <: GPUArray{T,1} id::GLuint - size::NTuple{1, Int} + size::NTuple{1,Int} buffertype::GLenum usage::GLenum context::GLContext @@ -8,7 +8,7 @@ mutable struct GLBuffer{T} <: GPUArray{T, 1} requires_update::Observable{Bool} observers::Vector{Observables.ObserverFunction} - function GLBuffer{T}(ptr::Ptr{T}, buff_length::Int, buffertype::GLenum, usage::GLenum) where T + function GLBuffer{T}(ptr::Ptr{T}, buff_length::Int, buffertype::GLenum, usage::GLenum) where {T} id = glGenBuffers() glBindBuffer(buffertype, id) # size of 0 can segfault it seems @@ -17,11 +17,17 @@ mutable struct GLBuffer{T} <: GPUArray{T, 1} glBindBuffer(buffertype, 0) obj = new( - id, (buff_length,), buffertype, usage, current_context(), - Observable(true), Observables.ObserverFunction[]) + id, + (buff_length,), + buffertype, + usage, + current_context(), + Observable(true), + Observables.ObserverFunction[], + ) finalizer(free, obj) - obj + return obj end end @@ -29,41 +35,44 @@ function bind(buffer::GLBuffer) if buffer.id == 0 error("Binding freed GLBuffer{$(eltype(buffer))}") end - glBindBuffer(buffer.buffertype, buffer.id) + return glBindBuffer(buffer.buffertype, buffer.id) end #used to reset buffer target bind(buffer::GLBuffer, other_target) = glBindBuffer(buffer.buffertype, other_target) -function similar(x::GLBuffer{T}, buff_length::Int) where T - GLBuffer{T}(Ptr{T}(C_NULL), buff_length, x.buffertype, x.usage) +function similar(x::GLBuffer{T}, buff_length::Int) where {T} + return GLBuffer{T}(Ptr{T}(C_NULL), buff_length, x.buffertype, x.usage) end cardinality(::GLBuffer{T}) where {T} = cardinality(T) #Function to deal with any Immutable type with Real as Subtype function GLBuffer( - buffer::Union{Base.ReinterpretArray{T, 1}, DenseVector{T}}; - buffertype::GLenum = GL_ARRAY_BUFFER, usage::GLenum = GL_STATIC_DRAW - ) where T <: GLArrayEltypes + buffer::Union{Base.ReinterpretArray{T,1},DenseVector{T}}; + buffertype::GLenum=GL_ARRAY_BUFFER, + usage::GLenum=GL_STATIC_DRAW, +) where {T<:GLArrayEltypes} GC.@preserve buffer begin return GLBuffer{T}(pointer(buffer), length(buffer), buffertype, usage) end end function GLBuffer( - buffer::DenseVector{T}; - buffertype::GLenum = GL_ARRAY_BUFFER, usage::GLenum = GL_STATIC_DRAW - ) where T <: GLArrayEltypes + buffer::DenseVector{T}; + buffertype::GLenum=GL_ARRAY_BUFFER, + usage::GLenum=GL_STATIC_DRAW, +) where {T<:GLArrayEltypes} GC.@preserve buffer begin return GLBuffer{T}(pointer(buffer), length(buffer), buffertype, usage) end end function GLBuffer( - buffer::ShaderAbstractions.Buffer{T}; - buffertype::GLenum = GL_ARRAY_BUFFER, usage::GLenum = GL_STATIC_DRAW - ) where T <: GLArrayEltypes + buffer::ShaderAbstractions.Buffer{T}; + buffertype::GLenum=GL_ARRAY_BUFFER, + usage::GLenum=GL_STATIC_DRAW, +) where {T<:GLArrayEltypes} b = GLBuffer(ShaderAbstractions.data(buffer); buffertype=buffertype, usage=usage) obsfunc = ShaderAbstractions.connect!(buffer, b) push!(b.observers, obsfunc) @@ -74,57 +83,48 @@ end GLBuffer(buffer::GLBuffer) = buffer GLBuffer{T}(buffer::GLBuffer{T}) where {T} = buffer -function GLBuffer( - buffer::AbstractVector{T}; - kw_args... - ) where T <: GLArrayEltypes - GLBuffer(collect(buffer); kw_args...) +function GLBuffer(buffer::AbstractVector{T}; kw_args...) where {T<:GLArrayEltypes} + return GLBuffer(collect(buffer); kw_args...) end -function GLBuffer{T}( - buffer::AbstractVector; - kw_args... - ) where T <: GLArrayEltypes - GLBuffer(convert(Vector{T}, buffer); kw_args...) +function GLBuffer{T}(buffer::AbstractVector; kw_args...) where {T<:GLArrayEltypes} + return GLBuffer(convert(Vector{T}, buffer); kw_args...) end function GLBuffer( - ::Type{T}, len::Int; - buffertype::GLenum = GL_ARRAY_BUFFER, usage::GLenum = GL_STATIC_DRAW - ) where T <: GLArrayEltypes - GLBuffer{T}(Ptr{T}(C_NULL), len, buffertype, usage) + ::Type{T}, + len::Int; + buffertype::GLenum=GL_ARRAY_BUFFER, + usage::GLenum=GL_STATIC_DRAW, +) where {T<:GLArrayEltypes} + return GLBuffer{T}(Ptr{T}(C_NULL), len, buffertype, usage) end - -function indexbuffer( - buffer::VectorTypes{T}; - usage::GLenum = GL_STATIC_DRAW - ) where T <: GLArrayEltypes - GLBuffer(buffer, buffertype = GL_ELEMENT_ARRAY_BUFFER, usage=usage) +function indexbuffer(buffer::VectorTypes{T}; usage::GLenum=GL_STATIC_DRAW) where {T<:GLArrayEltypes} + return GLBuffer(buffer, buffertype=GL_ELEMENT_ARRAY_BUFFER, usage=usage) end # GPUArray interface -function gpu_data(b::GLBuffer{T}) where T +function gpu_data(b::GLBuffer{T}) where {T} data = Vector{T}(undef, length(b)) bind(b) glGetBufferSubData(b.buffertype, 0, sizeof(data), data) bind(b, 0) - data + return data end - # Resize buffer -function gpu_resize!(buffer::GLBuffer{T}, newdims::NTuple{1, Int}) where T +function gpu_resize!(buffer::GLBuffer{T}, newdims::NTuple{1,Int}) where {T} #TODO make this safe! newlength = newdims[1] - oldlen = length(buffer) + oldlen = length(buffer) if oldlen > 0 old_data = gpu_data(buffer) end bind(buffer) - glBufferData(buffer.buffertype, newlength*sizeof(T), C_NULL, buffer.usage) + glBufferData(buffer.buffertype, newlength * sizeof(T), C_NULL, buffer.usage) bind(buffer, 0) buffer.size = newdims - if oldlen>0 + if oldlen > 0 max_len = min(length(old_data), newlength) #might also shrink buffer[1:max_len] = old_data[1:max_len] end @@ -133,86 +133,87 @@ function gpu_resize!(buffer::GLBuffer{T}, newdims::NTuple{1, Int}) where T # unsafe_copy!(buffer, 1, newbuff, 1, length(buffer)) # buffer.id = newbuff.id # buffer.size = newbuff.size - nothing + return nothing end -function gpu_setindex!(b::GLBuffer{T}, value::Vector{T}, offset::Integer) where T +function gpu_setindex!(b::GLBuffer{T}, value::Vector{T}, offset::Integer) where {T} multiplicator = sizeof(T) bind(b) - glBufferSubData(b.buffertype, multiplicator*(offset-1), sizeof(value), value) - bind(b, 0) + glBufferSubData(b.buffertype, multiplicator * (offset - 1), sizeof(value), value) + return bind(b, 0) end -function gpu_setindex!(b::GLBuffer{T}, value::Vector{T}, offset::UnitRange{Int}) where T +function gpu_setindex!(b::GLBuffer{T}, value::Vector{T}, offset::UnitRange{Int}) where {T} multiplicator = sizeof(T) bind(b) - glBufferSubData(b.buffertype, multiplicator*(first(offset)-1), sizeof(value), value) + glBufferSubData(b.buffertype, multiplicator * (first(offset) - 1), sizeof(value), value) bind(b, 0) return nothing end # copy between two buffers # could be a setindex! operation, with subarrays for buffers -function unsafe_copy!(a::GLBuffer{T}, readoffset::Int, b::GLBuffer{T}, writeoffset::Int, len::Int) where T +function unsafe_copy!(a::GLBuffer{T}, readoffset::Int, b::GLBuffer{T}, writeoffset::Int, len::Int) where {T} multiplicator = sizeof(T) @assert a.id != 0 & b.id != 0 glBindBuffer(GL_COPY_READ_BUFFER, a.id) glBindBuffer(GL_COPY_WRITE_BUFFER, b.id) glCopyBufferSubData( - GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, - multiplicator*(readoffset-1), - multiplicator*(writeoffset-1), - multiplicator*len + GL_COPY_READ_BUFFER, + GL_COPY_WRITE_BUFFER, + multiplicator * (readoffset - 1), + multiplicator * (writeoffset - 1), + multiplicator * len, ) glBindBuffer(GL_COPY_READ_BUFFER, 0) glBindBuffer(GL_COPY_WRITE_BUFFER, 0) return nothing end -function Base.iterate(buffer::GLBuffer{T}, i=1) where T +function Base.iterate(buffer::GLBuffer{T}, i=1) where {T} i > length(buffer) && return nothing - return gpu_getindex(buffer, i:i)[], i+1 + return gpu_getindex(buffer, i:i)[], i + 1 end #copy inside one buffer -function unsafe_copy!(buffer::GLBuffer{T}, readoffset::Int, writeoffset::Int, len::Int) where T +function unsafe_copy!(buffer::GLBuffer{T}, readoffset::Int, writeoffset::Int, len::Int) where {T} len <= 0 && return nothing bind(buffer) ptr = Ptr{T}(glMapBuffer(buffer.buffertype, GL_READ_WRITE)) - for i=1:len+1 - unsafe_store!(ptr, unsafe_load(ptr, i+readoffset-1), i+writeoffset-1) + for i in 1:(len + 1) + unsafe_store!(ptr, unsafe_load(ptr, i + readoffset - 1), i + writeoffset - 1) end glUnmapBuffer(buffer.buffertype) - bind(buffer,0) + bind(buffer, 0) return nothing end -function unsafe_copy!(a::Vector{T}, readoffset::Int, b::GLBuffer{T}, writeoffset::Int, len::Int) where T +function unsafe_copy!(a::Vector{T}, readoffset::Int, b::GLBuffer{T}, writeoffset::Int, len::Int) where {T} bind(b) ptr = Ptr{T}(glMapBuffer(b.buffertype, GL_WRITE_ONLY)) - for i=1:len - unsafe_store!(ptr, a[i+readoffset-1], i+writeoffset-1) + for i in 1:len + unsafe_store!(ptr, a[i + readoffset - 1], i + writeoffset - 1) end glUnmapBuffer(b.buffertype) - bind(b,0) + return bind(b, 0) end -function unsafe_copy!(a::GLBuffer{T}, readoffset::Int, b::Vector{T}, writeoffset::Int, len::Int) where T +function unsafe_copy!(a::GLBuffer{T}, readoffset::Int, b::Vector{T}, writeoffset::Int, len::Int) where {T} bind(a) ptr = Ptr{T}(glMapBuffer(a.buffertype, GL_READ_ONLY)) for i in 1:len - b[i+writeoffset-1] = unsafe_load(ptr, i+readoffset-2) #-2 => -1 to zero offset, -1 gl indexing starts at 0 + b[i + writeoffset - 1] = unsafe_load(ptr, i + readoffset - 2) #-2 => -1 to zero offset, -1 gl indexing starts at 0 end glUnmapBuffer(a.buffertype) - bind(a,0) + return bind(a, 0) end -function gpu_getindex(b::GLBuffer{T}, range::UnitRange) where T +function gpu_getindex(b::GLBuffer{T}, range::UnitRange) where {T} multiplicator = sizeof(T) - offset = first(range)-1 + offset = first(range) - 1 value = Vector{T}(undef, length(range)) bind(b) - glGetBufferSubData(b.buffertype, multiplicator*offset, sizeof(value), value) + glGetBufferSubData(b.buffertype, multiplicator * offset, sizeof(value), value) bind(b, 0) return value end diff --git a/GLMakie/src/GLAbstraction/GLExtendedFunctions.jl b/GLMakie/src/GLAbstraction/GLExtendedFunctions.jl index 95235c2a67f..cf8600fed12 100644 --- a/GLMakie/src/GLAbstraction/GLExtendedFunctions.jl +++ b/GLMakie/src/GLAbstraction/GLExtendedFunctions.jl @@ -6,21 +6,21 @@ Its also to do some more complex error handling, not handled by the debug callba function glGetShaderiv(shaderID::GLuint, variable::GLenum) result = Ref{GLint}(-1) glGetShaderiv(shaderID, variable, result) - result[] + return result[] end function glShaderSource(shaderID::GLuint, shadercode::Vector{UInt8}) shader_code_ptrs = Ptr{UInt8}[pointer(shadercode)] - len = Ref{GLint}(length(shadercode)) - glShaderSource(shaderID, 1, shader_code_ptrs, len) + len = Ref{GLint}(length(shadercode)) + return glShaderSource(shaderID, 1, shader_code_ptrs, len) end glShaderSource(shaderID::GLuint, shadercode::String) = glShaderSource(shaderID, Vector{UInt8}(shadercode)) function glGetAttachedShaders(program::GLuint) - shader_count = glGetProgramiv(program, GL_ATTACHED_SHADERS) + shader_count = glGetProgramiv(program, GL_ATTACHED_SHADERS) length_written = GLsizei[0] - shaders = zeros(GLuint, shader_count) + shaders = zeros(GLuint, shader_count) glGetAttachedShaders(program, shader_count, length_written, shaders) - shaders[1:first(length_written)] + return shaders[1:first(length_written)] end get_attribute_location(program::GLuint, name) = get_attribute_location(program, ascii(name)) @@ -33,43 +33,37 @@ function get_attribute_location(program::GLuint, name::String) # the name starts with the reserved prefix gl_\n" # ) elseif location == GL_INVALID_OPERATION - error( - "program is not a value generated by OpenGL or\n - program is not a program object or\n - program has not been successfully linked" - ) + error("program is not a value generated by OpenGL or\n + program is not a program object or\n + program has not been successfully linked") end - location + return location end - get_uniform_location(program::GLuint, name::Symbol) = get_uniform_location(program, String(name)) function get_uniform_location(program::GLuint, name::String) location = glGetUniformLocation(program, name) if location == -1 - error( - """Named uniform (:$(name)) is not an active attribute in the specified program object or - the name starts with the reserved prefix gl_""" - ) + error("""Named uniform (:$(name)) is not an active attribute in the specified program object or + the name starts with the reserved prefix gl_""") elseif location == GL_INVALID_OPERATION error("""program is not a value generated by OpenGL or program is not a program object or - program has not been successfully linked""" - ) + program has not been successfully linked""") end - location + return location end function glGetActiveUniform(programID::GLuint, index::Integer) - actualLength = GLsizei[1] - uniformSize = GLint[1] - typ = GLenum[1] - maxcharsize = glGetProgramiv(programID, GL_ACTIVE_UNIFORM_MAX_LENGTH) - name = Vector{GLchar}(undef, maxcharsize) + actualLength = GLsizei[1] + uniformSize = GLint[1] + typ = GLenum[1] + maxcharsize = glGetProgramiv(programID, GL_ACTIVE_UNIFORM_MAX_LENGTH) + name = Vector{GLchar}(undef, maxcharsize) glGetActiveUniform(programID, index, maxcharsize, actualLength, uniformSize, typ, name) - actualLength[1] <= 0 && error("No active uniform at given index. Index: ", index) + actualLength[1] <= 0 && error("No active uniform at given index. Index: ", index) uname = unsafe_string(pointer(name), actualLength[1]) uname = Symbol(replace(uname, r"\[\d*\]" => "")) # replace array brackets. This is not really a good solution. @@ -77,11 +71,11 @@ function glGetActiveUniform(programID::GLuint, index::Integer) end function glGetActiveAttrib(programID::GLuint, index::Integer) - actualLength = GLsizei[1] - attributeSize = GLint[1] - typ = GLenum[1] - maxcharsize = glGetProgramiv(programID, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) - name = Vector{GLchar}(undef, maxcharsize) + actualLength = GLsizei[1] + attributeSize = GLint[1] + typ = GLenum[1] + maxcharsize = glGetProgramiv(programID, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) + name = Vector{GLchar}(undef, maxcharsize) glGetActiveAttrib(programID, index, maxcharsize, actualLength, attributeSize, typ, name) @@ -118,7 +112,7 @@ function glGenVertexArrays() result = GLuint[0] glGenVertexArrays(1, result) id = result[1] - if id <=0 + if id <= 0 error("glGenVertexArrays returned invalid id. OpenGL Context active?") end return id @@ -146,23 +140,23 @@ end function glDeleteTextures(id::GLuint) arr = [id] - glDeleteTextures(1, arr) + return glDeleteTextures(1, arr) end function glDeleteVertexArrays(id::GLuint) arr = [id] - glDeleteVertexArrays(1, arr) + return glDeleteVertexArrays(1, arr) end function glDeleteBuffers(id::GLuint) arr = [id] - glDeleteBuffers(1, arr) + return glDeleteBuffers(1, arr) end function glGetTexLevelParameteriv(target::GLenum, level, name::GLenum) result = GLint[0] glGetTexLevelParameteriv(target, level, name, result) - result[1] + return result[1] end glViewport(x::Rect2) = glViewport(minimum(x)..., widths(x)...) @@ -177,14 +171,25 @@ function glGenRenderbuffers(format::GLenum, attachment::GLenum, dimensions) return renderbuffer[1] end -function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, h::Integer, d::Integer, border::Integer, format::GLenum, datatype::GLenum, data) +function glTexImage( + ttype::GLenum, + level::Integer, + internalFormat::GLenum, + w::Integer, + h::Integer, + d::Integer, + border::Integer, + format::GLenum, + datatype::GLenum, + data, +) glTexImage3D(GL_PROXY_TEXTURE_3D, level, internalFormat, w, h, d, border, format, datatype, C_NULL) - for l in 0:level + for l in 0:level result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, l, GL_TEXTURE_WIDTH) if result == 0 error("glTexImage 3D: width too large. Width: ", w) end - result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, l,GL_TEXTURE_HEIGHT) + result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, l, GL_TEXTURE_HEIGHT) if result == 0 error("glTexImage 3D: height too large. height: ", h) end @@ -197,10 +202,20 @@ function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::In error("glTexImage 3D: internal format not valid. format: ", GLENUM(internalFormat).name) end end - glTexImage3D(ttype, level, internalFormat, w, h, d, border, format, datatype, data) + return glTexImage3D(ttype, level, internalFormat, w, h, d, border, format, datatype, data) end -function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, h::Integer, border::Integer, format::GLenum, datatype::GLenum, data) +function glTexImage( + ttype::GLenum, + level::Integer, + internalFormat::GLenum, + w::Integer, + h::Integer, + border::Integer, + format::GLenum, + datatype::GLenum, + data, +) maxsize = glGetIntegerv(GL_MAX_TEXTURE_SIZE) glTexImage2D(GL_PROXY_TEXTURE_2D, level, internalFormat, w, h, border, format, datatype, C_NULL) for l in 0:level @@ -217,10 +232,19 @@ function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::In error("glTexImage 2D: internal format not valid. format: ", GLENUM(internalFormat).name) end end - glTexImage2D(ttype, level, internalFormat, w, h, border, format, datatype, data) + return glTexImage2D(ttype, level, internalFormat, w, h, border, format, datatype, data) end -function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, border::Integer, format::GLenum, datatype::GLenum, data) +function glTexImage( + ttype::GLenum, + level::Integer, + internalFormat::GLenum, + w::Integer, + border::Integer, + format::GLenum, + datatype::GLenum, + data, +) glTexImage1D(GL_PROXY_TEXTURE_1D, level, internalFormat, w, border, format, datatype, C_NULL) for l in 0:level result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_1D, l, GL_TEXTURE_WIDTH) @@ -232,7 +256,7 @@ function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::In error("glTexImage 1D: internal format not valid. format: ", GLENUM(internalFormat).name) end end - glTexImage1D(ttype, level, internalFormat, w, border, format, datatype, data) + return glTexImage1D(ttype, level, internalFormat, w, border, format, datatype, data) end function glsl_version_number() @@ -255,7 +279,9 @@ end function glsl_version_string() glsl = glsl_version_number() - glsl.major == 1 && glsl.minor <= 2 && error("OpenGL shading Language version too low. Try updating graphic driver!") + glsl.major == 1 && + glsl.minor <= 2 && + error("OpenGL shading Language version too low. Try updating graphic driver!") glsl_version = string(glsl.major) * rpad(string(glsl.minor), 2, "0") return "#version $(glsl_version)\n" end diff --git a/GLMakie/src/GLAbstraction/GLInfo.jl b/GLMakie/src/GLAbstraction/GLInfo.jl index c72c677807f..fbf40c6a7b9 100644 --- a/GLMakie/src/GLAbstraction/GLInfo.jl +++ b/GLMakie/src/GLAbstraction/GLInfo.jl @@ -1,8 +1,8 @@ getnames(check_function::Function) = filter(check_function, uint32(0:65534)) # gets all the names currently boundo to programs -getProgramNames() = getnames(glIsProgram) -getShaderNames() = getnames(glIsShader) +getProgramNames() = getnames(glIsProgram) +getShaderNames() = getnames(glIsShader) getVertexArrayNames() = getnames(glIsVertexArray) # display info for all active uniforms in a program @@ -16,9 +16,9 @@ function getUniformsInfo(p::GLProgram) size = Ref{GLint}(0) type = Ref{GLenum}() - for i=0:activeUnif-1 + for i in 0:(activeUnif - 1) glGetActiveUniform(program, i, bufSize, buflen, size, type, name) - println(String(name), " ", buflen[], " ", size[], " ", GLENUM(type[]).name) + println(String(name), " ", buflen[], " ", size[], " ", GLENUM(type[]).name) end end @@ -29,7 +29,7 @@ function uniform_name_type(p::GLProgram, location) size = Ref{GLint}(0) type = Ref{GLenum}() glGetActiveUniform(p.id, location, bufSize, buflen, size, type, name) - println(String(name), " ", buflen[], " ", size[], " ", GLENUM(type[]).name) + return println(String(name), " ", buflen[], " ", size[], " ", GLENUM(type[]).name) end # display the values for uniforms in the default block @@ -40,7 +40,6 @@ function getUniformInfo(p::GLProgram, uniName::Symbol) @show name, typ, uniform_size = glGetActiveUniform(program, loc) end - # display the values for a uniform in a named block function getUniformInBlockInfo(p::GLProgram, blockName, uniName) program = p.id @@ -60,21 +59,18 @@ function getUniformInBlockInfo(p::GLProgram, blockName, uniName) @show uniMatStride = glGetActiveUniformsiv(program, uniIndex, GL_UNIFORM_MATRIX_STRIDE) end - # display information for a program's attributes function getAttributesInfo(p::GLProgram) - program = p.id # how many attribs? @show activeAttr = glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES) # get location and type for each attrib - for i=0:activeAttr-1 - @show name, typ, siz = glGetActiveAttrib(program, i) + for i in 0:(activeAttr - 1) + @show name, typ, siz = glGetActiveAttrib(program, i) @show loc = glGetAttribLocation(program, name) end end - # display program's information function getProgramInfo(p::GLProgram) # check if name is really a program diff --git a/GLMakie/src/GLAbstraction/GLRender.jl b/GLMakie/src/GLAbstraction/GLRender.jl index 72581554e46..8d90b003575 100644 --- a/GLMakie/src/GLAbstraction/GLRender.jl +++ b/GLMakie/src/GLAbstraction/GLRender.jl @@ -7,7 +7,7 @@ end """ When rendering a specialised list of Renderables, we can do some optimizations """ -function render(list::Vector{RenderObject{Pre}}) where Pre +function render(list::Vector{RenderObject{Pre}}) where {Pre} isempty(list) && return nothing first(list).prerenderfunction() vertexarray = first(list).vertexarray @@ -56,7 +56,7 @@ a lot of objects. """ function render(renderobject::RenderObject, vertexarray=renderobject.vertexarray) renderobject.requires_update = false - + if renderobject.visible renderobject.prerenderfunction() program = vertexarray.program @@ -73,7 +73,8 @@ function render(renderobject::RenderObject, vertexarray=renderobject.vertexarray error("Uniform tuple too long: $(length(value))") end catch e - @warn error("uniform $key doesn't work with value $(renderobject.uniforms[key])") exception=(e, Base.catch_backtrace()) + @warn error("uniform $key doesn't work with value $(renderobject.uniforms[key])") exception = + (e, Base.catch_backtrace()) end end end @@ -84,31 +85,32 @@ function render(renderobject::RenderObject, vertexarray=renderobject.vertexarray return end - """ Renders a vertexarray, which consists of the usual buffers plus a vector of unitranges which defines the segments of the buffers to be rendered """ -function render(vao::GLVertexArray{T}, mode::GLenum=GL_TRIANGLES) where T <: VecOrSignal{UnitRange{Int}} +function render(vao::GLVertexArray{T}, mode::GLenum=GL_TRIANGLES) where {T<:VecOrSignal{UnitRange{Int}}} for elem in to_value(vao.indices) glDrawArrays(mode, max(first(elem) - 1, 0), length(elem) + 1) end return nothing end -function render(vao::GLVertexArray{T}, mode::GLenum=GL_TRIANGLES) where T <: TOrSignal{UnitRange{Int}} +function render(vao::GLVertexArray{T}, mode::GLenum=GL_TRIANGLES) where {T<:TOrSignal{UnitRange{Int}}} r = to_value(vao.indices) offset = first(r) - 1 # 1 based -> 0 based ndraw = length(r) nverts = length(vao) if (offset < 0 || offset + ndraw > nverts) - error("Bounds error for drawrange. Offset $(offset) and length $(ndraw) aren't a valid range for vertexarray with length $(nverts)") + error( + "Bounds error for drawrange. Offset $(offset) and length $(ndraw) aren't a valid range for vertexarray with length $(nverts)", + ) end glDrawArrays(mode, offset, ndraw) return nothing end -function render(vao::GLVertexArray{T}, mode::GLenum=GL_TRIANGLES) where T <: TOrSignal{Int} +function render(vao::GLVertexArray{T}, mode::GLenum=GL_TRIANGLES) where {T<:TOrSignal{Int}} r = to_value(vao.indices) glDrawArrays(mode, 0, r) return nothing @@ -117,12 +119,11 @@ end """ Renders a vertex array which supplies an indexbuffer """ -function render(vao::GLVertexArray{GLBuffer{T}}, mode::GLenum=GL_TRIANGLES) where T <: Union{Integer,AbstractFace} - glDrawElements( - mode, - length(vao.indices) * cardinality(vao.indices), - julia2glenum(T), C_NULL - ) +function render( + vao::GLVertexArray{GLBuffer{T}}, + mode::GLenum=GL_TRIANGLES, +) where {T<:Union{Integer,AbstractFace}} + glDrawElements(mode, length(vao.indices) * cardinality(vao.indices), julia2glenum(T), C_NULL) return end @@ -142,8 +143,18 @@ renderinstanced(vao::GLVertexArray, a, primitive=GL_TRIANGLES) = renderinstanced """ Renders `amount` instances of an indexed geometry """ -function renderinstanced(vao::GLVertexArray{GLBuffer{T}}, amount::Integer, primitive=GL_TRIANGLES) where T <: Union{Integer,AbstractFace} - glDrawElementsInstanced(primitive, length(vao.indices) * cardinality(vao.indices), julia2glenum(T), C_NULL, amount) +function renderinstanced( + vao::GLVertexArray{GLBuffer{T}}, + amount::Integer, + primitive=GL_TRIANGLES, +) where {T<:Union{Integer,AbstractFace}} + glDrawElementsInstanced( + primitive, + length(vao.indices) * cardinality(vao.indices), + julia2glenum(T), + C_NULL, + amount, + ) return end diff --git a/GLMakie/src/GLAbstraction/GLRenderObject.jl b/GLMakie/src/GLAbstraction/GLRenderObject.jl index fe644f5c586..b22468210c8 100644 --- a/GLMakie/src/GLAbstraction/GLRenderObject.jl +++ b/GLMakie/src/GLAbstraction/GLRenderObject.jl @@ -1,6 +1,4 @@ -function Base.show(io::IO, obj::RenderObject) - println(io, "RenderObject with ID: ", obj.id) -end +Base.show(io::IO, obj::RenderObject) = println(io, "RenderObject with ID: ", obj.id) Base.getindex(obj::RenderObject, symbol::Symbol) = obj.uniforms[symbol] Base.setindex!(obj::RenderObject, value, symbol::Symbol) = obj.uniforms[symbol] = value @@ -9,8 +7,8 @@ Base.getindex(obj::RenderObject, symbol::Symbol, x::Function) = getindex(obj, Va Base.getindex(obj::RenderObject, ::Val{:prerender}, x::Function) = obj.prerenderfunctions[x] Base.getindex(obj::RenderObject, ::Val{:postrender}, x::Function) = obj.postrenderfunctions[x] -Base.setindex!(obj::RenderObject, value, symbol::Symbol, x::Function) = setindex!(obj, value, Val(symbol), x) -Base.setindex!(obj::RenderObject, value, ::Val{:prerender}, x::Function) = obj.prerenderfunctions[x] = value +Base.setindex!(obj::RenderObject, value, symbol::Symbol, x::Function) = setindex!(obj, value, Val(symbol), x) +Base.setindex!(obj::RenderObject, value, ::Val{:prerender}, x::Function) = obj.prerenderfunctions[x] = value Base.setindex!(obj::RenderObject, value, ::Val{:postrender}, x::Function) = obj.postrenderfunctions[x] = value """ @@ -64,9 +62,7 @@ struct StandardPostrender primitive::GLenum end -function (sp::StandardPostrender)() - render(sp.vao, sp.primitive) -end +(sp::StandardPostrender)() = render(sp.vao, sp.primitive) struct StandardPostrenderInstanced{T} main::T @@ -74,9 +70,7 @@ struct StandardPostrenderInstanced{T} primitive::GLenum end -function (sp::StandardPostrenderInstanced)() - renderinstanced(sp.vao, to_value(sp.main), sp.primitive) -end +(sp::StandardPostrenderInstanced)() = renderinstanced(sp.vao, to_value(sp.main), sp.primitive) struct EmptyPrerender end diff --git a/GLMakie/src/GLAbstraction/GLShader.jl b/GLMakie/src/GLAbstraction/GLShader.jl index edbc7efff8c..737992b0b99 100644 --- a/GLMakie/src/GLAbstraction/GLShader.jl +++ b/GLMakie/src/GLAbstraction/GLShader.jl @@ -22,9 +22,9 @@ end function getinfolog(obj::GLuint) # Return the info log for obj, whether it be a shader or a program. - isShader = glIsShader(obj) - getiv = isShader == GL_TRUE ? glGetShaderiv : glGetProgramiv - get_log = isShader == GL_TRUE ? glGetShaderInfoLog : glGetProgramInfoLog + isShader = glIsShader(obj) + getiv = isShader == GL_TRUE ? glGetShaderiv : glGetProgramiv + get_log = isShader == GL_TRUE ? glGetShaderInfoLog : glGetProgramInfoLog # Get the maximum possible length for the descriptive error message maxlength = GLint[0] @@ -52,12 +52,12 @@ islinked(program::GLuint) = glGetProgramiv(program, GL_LINK_STATUS) == GL_TRUE function createshader(shadertype::GLenum) shaderid = glCreateShader(shadertype) @assert shaderid > 0 "opengl context is not active or shader type not accepted. Shadertype: $(GLENUM(shadertype).name)" - shaderid::GLuint + return shaderid::GLuint end function createprogram() program = glCreateProgram() @assert program > 0 "couldn't create program. Most likely, opengl context is not active" - program::GLuint + return program::GLuint end shadertype(s::Shader) = s.typ @@ -66,11 +66,11 @@ function shadertype(ext::AbstractString) ext == ".vert" && return GL_VERTEX_SHADER ext == ".frag" && return GL_FRAGMENT_SHADER ext == ".geom" && return GL_GEOMETRY_SHADER - error("$ext not a valid shader extension") + return error("$ext not a valid shader extension") end -function uniformlocations(nametypedict::Dict{Symbol, GLenum}, program) - result = Dict{Symbol, Tuple}() +function uniformlocations(nametypedict::Dict{Symbol,GLenum}, program) + result = Dict{Symbol,Tuple}() texturetarget = -1 # start -1, as texture samplers start at 0 for (name, typ) in nametypedict loc = get_uniform_location(program, name) @@ -88,37 +88,35 @@ struct ShaderCache # path --> template keys # cache for template keys per file context::Any - template_cache::Dict{String, Vector{String}} + template_cache::Dict{String,Vector{String}} # path --> Dict{template_replacements --> Shader) - shader_cache::Dict{String, Dict{Any, Shader}} - program_cache::Dict{Any, GLProgram} + shader_cache::Dict{String,Dict{Any,Shader}} + program_cache::Dict{Any,GLProgram} end function ShaderCache(context) - ShaderCache( + return ShaderCache( context, - Dict{String, Vector{String}}(), - Dict{String, Dict{Any, Shader}}(), - Dict{Any, GLProgram}() + Dict{String,Vector{String}}(), + Dict{String,Dict{Any,Shader}}(), + Dict{Any,GLProgram}(), ) end - abstract type AbstractLazyShader end struct LazyShader <: AbstractLazyShader shader_cache::ShaderCache paths::Tuple - kw_args::Dict{Symbol, Any} + kw_args::Dict{Symbol,Any} function LazyShader(cache::ShaderCache, paths...; kw_args...) - args = Dict{Symbol, Any}(kw_args) - get!(args, :view, Dict{String, String}()) - new(cache, paths, args) + args = Dict{Symbol,Any}(kw_args) + get!(args, :view, Dict{String,String}()) + return new(cache, paths, args) end end gl_convert(shader::GLProgram, data) = shader - # TODO remove this silly constructor function compile_shader(source::Vector{UInt8}, typ, name) shaderid = createshader(typ) @@ -155,9 +153,7 @@ function get_template!(cache::ShaderCache, path, view, attributes) typ = shadertype(ext) template_source = read(path, String) - source, replacements = template2source( - template_source, view, attributes - ) + source, replacements = template2source(template_source, view, attributes) s = compile_shader(path, source) template_keys = collect(keys(replacements)) template_replacements = collect(values(replacements)) @@ -168,13 +164,12 @@ function get_template!(cache::ShaderCache, path, view, attributes) end end - function compile_program(shaders, fragdatalocation) # Remove old shaders program = createprogram() #attach new ones foreach(shaders) do shader - glAttachShader(program, shader.id) + return glAttachShader(program, shader.id) end #Bind frag data @@ -187,7 +182,9 @@ function compile_program(shaders, fragdatalocation) if !GLAbstraction.islinked(program) error( "program $program not linked. Error in: \n", - join(map(x-> string(x.name), shaders), " or "), "\n", getinfolog(program) + join(map(x -> string(x.name), shaders), " or "), + "\n", + getinfolog(program), ) end # Can be deleted, as they will still be linked to Program and released after program gets released @@ -195,52 +192,47 @@ function compile_program(shaders, fragdatalocation) # generate the link locations nametypedict = uniform_name_type(program) uniformlocationdict = uniformlocations(nametypedict, program) - GLProgram(program, shaders, nametypedict, uniformlocationdict) + return GLProgram(program, shaders, nametypedict, uniformlocationdict) end function get_view(kw_dict) _view = kw_dict[:view] extension = Sys.isapple() ? "" : "#extension GL_ARB_draw_instanced : enable\n" - _view["GLSL_EXTENSION"] = extension*get(_view, "GLSL_EXTENSIONS", "") + _view["GLSL_EXTENSION"] = extension * get(_view, "GLSL_EXTENSIONS", "") _view["GLSL_VERSION"] = glsl_version_string() - _view + return _view end gl_convert(lazyshader::AbstractLazyShader, data) = error("gl_convert shader") -function gl_convert(lazyshader::LazyShader, data) - gl_convert(lazyshader.shader_cache, lazyshader, data) -end +gl_convert(lazyshader::LazyShader, data) = gl_convert(lazyshader.shader_cache, lazyshader, data) function gl_convert(cache::ShaderCache, lazyshader::AbstractLazyShader, data) kw_dict = lazyshader.kw_args paths = lazyshader.paths - if all(x-> isa(x, Shader), paths) - fragdatalocation = get(kw_dict, :fragdatalocation, Tuple{Int, String}[]) + if all(x -> isa(x, Shader), paths) + fragdatalocation = get(kw_dict, :fragdatalocation, Tuple{Int,String}[]) ShaderAbstractions.switch_context!(cache.context) return compile_program([paths...], fragdatalocation) end v = get_view(kw_dict) - fragdatalocation = get(kw_dict, :fragdatalocation, Tuple{Int, String}[]) + fragdatalocation = get(kw_dict, :fragdatalocation, Tuple{Int,String}[]) # Tuple(Source, ShaderType) if all(paths) do x - isa(x, Tuple) && length(x) == 2 && - isa(first(x), AbstractString) && - isa(last(x), GLenum) - end + return isa(x, Tuple) && length(x) == 2 && isa(first(x), AbstractString) && isa(last(x), GLenum) + end # we don't cache view & templates for shader strings! shaders = map(paths) do source_typ source, typ = source_typ src, _ = template2source(source, v, data) ShaderAbstractions.switch_context!(cache.context) - compile_shader(Vector{UInt8}(src), typ, :from_string) + return compile_shader(Vector{UInt8}(src), typ, :from_string) end ShaderAbstractions.switch_context!(cache.context) return compile_program([shaders...], fragdatalocation) end if !all(x -> isa(x, AbstractString), paths) error("Please supply only paths or tuples of (source, typ) for Lazy Shader - Found: $paths" - ) + Found: $paths") end template_keys = Vector{Vector{String}}(undef, length(paths)) replacements = Vector{Vector{String}}(undef, length(paths)) @@ -258,27 +250,27 @@ function gl_convert(cache::ShaderCache, lazyshader::AbstractLazyShader, data) shaders[i] = get_shader!(cache, path, tr) end ShaderAbstractions.switch_context!(cache.context) - compile_program(shaders, fragdatalocation) + return compile_program(shaders, fragdatalocation) end end function insert_from_view(io, replace_view::Function, keyword::AbstractString) print(io, replace_view(keyword)) - nothing + return nothing end function insert_from_view(io, replace_view::Dict, keyword::AbstractString) if haskey(replace_view, keyword) print(io, replace_view[keyword]) end - nothing + return nothing end """ Replaces {{keyword}} with the key in `replace_view`, or replace_view(key) in a string """ -function mustache_replace(replace_view::Union{Dict, Function}, string) +function mustache_replace(replace_view::Union{Dict,Function}, string) io = IOBuffer() replace_started = false open_mustaches = 0 @@ -296,7 +288,7 @@ function mustache_replace(replace_view::Union{Dict, Function}, string) if char == '}' closed_mustaches += 1 if closed_mustaches == 2 # we found a complete mustache! - insert_from_view(io, replace_view, SubString(string, replace_begin+1, i-2)) + insert_from_view(io, replace_view, SubString(string, replace_begin + 1, i - 2)) open_mustaches = 0 closed_mustaches = 0 replace_started = false @@ -321,10 +313,9 @@ function mustache_replace(replace_view::Union{Dict, Function}, string) end last_char = char end - String(take!(io)) + return String(take!(io)) end - function mustache2replacement(mustache_key, view, attributes) haskey(view, mustache_key) && return view[mustache_key] for postfix in ("_type", "_calculation") @@ -335,7 +326,8 @@ function mustache2replacement(mustache_key, view, attributes) if !isa(val, AbstractString) if postfix == "_type" return toglsltype_string(val)::String - else postfix == "_calculation" + else + postfix == "_calculation" return glsl_variable_access(keystring, val) end end @@ -346,9 +338,11 @@ function mustache2replacement(mustache_key, view, attributes) end # Takes a shader template and renders the template and returns shader source -template2source(source::Vector{UInt8}, view, attributes::Dict{Symbol, Any}) = template2source(String(source), attributes, view) -function template2source(source::AbstractString, view, attributes::Dict{Symbol, Any}) - replacements = Dict{String, String}() +function template2source(source::Vector{UInt8}, view, attributes::Dict{Symbol,Any}) + return template2source(String(source), attributes, view) +end +function template2source(source::AbstractString, view, attributes::Dict{Symbol,Any}) + replacements = Dict{String,String}() source = mustache_replace(source) do mustache_key r = mustache2replacement(mustache_key, view, attributes) replacements[mustache_key] = r diff --git a/GLMakie/src/GLAbstraction/GLTexture.jl b/GLMakie/src/GLAbstraction/GLTexture.jl index 51ebdbb628e..366b481f5d2 100644 --- a/GLMakie/src/GLAbstraction/GLTexture.jl +++ b/GLMakie/src/GLAbstraction/GLTexture.jl @@ -1,33 +1,33 @@ struct TextureParameters{NDim} minfilter::Symbol magfilter::Symbol # magnification - repeat ::NTuple{NDim, Symbol} + repeat::NTuple{NDim,Symbol} anisotropic::Float32 swizzle_mask::Vector{GLenum} end -abstract type OpenglTexture{T, NDIM} <: GPUArray{T, NDIM} end - -mutable struct Texture{T <: GLArrayEltypes, NDIM} <: OpenglTexture{T, NDIM} - id ::GLuint - texturetype ::GLenum - pixeltype ::GLenum - internalformat ::GLenum - format ::GLenum - parameters ::TextureParameters{NDIM} - size ::NTuple{NDIM, Int} - context ::GLContext - requires_update ::Observable{Bool} - observers ::Vector{Observables.ObserverFunction} - function Texture{T, NDIM}( - id ::GLuint, - texturetype ::GLenum, - pixeltype ::GLenum, - internalformat ::GLenum, - format ::GLenum, - parameters ::TextureParameters{NDIM}, - size ::NTuple{NDIM, Int} - ) where {T, NDIM} +abstract type OpenglTexture{T,NDIM} <: GPUArray{T,NDIM} end + +mutable struct Texture{T<:GLArrayEltypes,NDIM} <: OpenglTexture{T,NDIM} + id::GLuint + texturetype::GLenum + pixeltype::GLenum + internalformat::GLenum + format::GLenum + parameters::TextureParameters{NDIM} + size::NTuple{NDIM,Int} + context::GLContext + requires_update::Observable{Bool} + observers::Vector{Observables.ObserverFunction} + function Texture{T,NDIM}( + id::GLuint, + texturetype::GLenum, + pixeltype::GLenum, + internalformat::GLenum, + format::GLenum, + parameters::TextureParameters{NDIM}, + size::NTuple{NDIM,Int}, + ) where {T,NDIM} tex = new( id, texturetype, @@ -38,22 +38,22 @@ mutable struct Texture{T <: GLArrayEltypes, NDIM} <: OpenglTexture{T, NDIM} size, current_context(), Observable(true), - Observables.ObserverFunction[] + Observables.ObserverFunction[], ) finalizer(free, tex) - tex + return tex end end # for bufferSampler, aka Texture Buffer -mutable struct TextureBuffer{T <: GLArrayEltypes} <: OpenglTexture{T, 1} - texture::Texture{T, 1} +mutable struct TextureBuffer{T<:GLArrayEltypes} <: OpenglTexture{T,1} + texture::Texture{T,1} buffer::GLBuffer{T} requires_update::Observable{Bool} - function TextureBuffer(texture::Texture{T, 1}, buffer::GLBuffer{T}) where T + function TextureBuffer(texture::Texture{T,1}, buffer::GLBuffer{T}) where {T} x = map((_, _) -> true, buffer.requires_update, texture.requires_update) - new{T}(texture, buffer, x) + return new{T}(texture, buffer, x) end end Base.size(t::TextureBuffer) = size(t.buffer) @@ -63,7 +63,7 @@ function bind(t::Texture) if t.id == 0 error("Binding freed Texture{$(eltype(t))}") end - glBindTexture(t.texturetype, t.id) + return glBindTexture(t.texturetype, t.id) end bind(t::Texture, id) = glBindTexture(t.texturetype, id) @@ -72,30 +72,31 @@ ShaderAbstractions.switch_context!(t::TextureBuffer) = switch_context!(t.texture function unsafe_free(tb::TextureBuffer) unsafe_free(tb.texture) unsafe_free(tb.buffer) - Observables.clear(tb.requires_update) + return Observables.clear(tb.requires_update) end is_texturearray(t::Texture) = t.texturetype == GL_TEXTURE_2D_ARRAY is_texturebuffer(t::Texture) = t.texturetype == GL_TEXTURE_BUFFER colordim(::Type{T}) where {T} = cardinality(T) -colordim(::Type{T}) where {T <: Real} = 1 +colordim(::Type{T}) where {T<:Real} = 1 function set_packing_alignment(a) # at some point we should specialize to array/ptr a glPixelStorei(GL_UNPACK_ALIGNMENT, 1) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0) glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0) - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0) + return glPixelStorei(GL_UNPACK_SKIP_ROWS, 0) end function Texture( - data::Ptr{T}, dims::NTuple{NDim, Int}; - internalformat::GLenum = default_internalcolorformat(T), - texturetype ::GLenum = default_texturetype(NDim), - format ::GLenum = default_colorformat(T), - mipmap = false, - parameters... # rest should be texture parameters - ) where {T, NDim} + data::Ptr{T}, + dims::NTuple{NDim,Int}; + internalformat::GLenum=default_internalcolorformat(T), + texturetype::GLenum=default_texturetype(NDim), + format::GLenum=default_colorformat(T), + mipmap=false, + parameters..., # rest should be texture parameters +) where {T,NDim} texparams = TextureParameters(T, NDim; parameters...) id = glGenTextures() glBindTexture(texturetype, id) @@ -103,21 +104,17 @@ function Texture( numbertype = julia2glenum(eltype(T)) glTexImage(texturetype, 0, internalformat, dims..., 0, format, numbertype, data) mipmap && glGenerateMipmap(texturetype) - texture = Texture{T, NDim}( - id, texturetype, numbertype, internalformat, format, - texparams, - dims - ) + texture = Texture{T,NDim}(id, texturetype, numbertype, internalformat, format, texparams, dims) set_parameters(texture) - texture::Texture{T, NDim} + return texture::Texture{T,NDim} end export resize_nocopy! -function resize_nocopy!(t::Texture{T, ND}, newdims::NTuple{ND, Int}) where {T, ND} +function resize_nocopy!(t::Texture{T,ND}, newdims::NTuple{ND,Int}) where {T,ND} bind(t) glTexImage(t.texturetype, 0, t.internalformat, newdims..., 0, t.format, t.pixeltype, C_NULL) t.size = newdims bind(t, 0) - t + return t end """ @@ -125,8 +122,9 @@ Constructor for empty initialization with NULL pointer instead of an array with You just need to pass the wanted color/vector type and the dimensions. To which values the texture gets initialized is driver dependent """ -Texture(::Type{T}, dims::NTuple{N, Int}; kw_args...) where {T <: GLArrayEltypes, N} = - Texture(convert(Ptr{T}, C_NULL), dims; kw_args...)::Texture{T, N} +function Texture(::Type{T}, dims::NTuple{N,Int}; kw_args...) where {T<:GLArrayEltypes,N} + return Texture(convert(Ptr{T}, C_NULL), dims; kw_args...)::Texture{T,N} +end """ Constructor for a normal array, with color or Abstract Arrays as elements. @@ -134,15 +132,21 @@ So Array{Real, 2} == Texture2D with 1D Colorant dimension Array{Vec1/2/3/4, 2} == Texture2D with 1/2/3/4D Colorant dimension Colors from Colors.jl should mostly work as well """ -Texture(image::Array{T, NDim}; kw_args...) where {T <: GLArrayEltypes, NDim} = - Texture(pointer(image), size(image); kw_args...)::Texture{T, NDim} +function Texture(image::Array{T,NDim}; kw_args...) where {T<:GLArrayEltypes,NDim} + return Texture(pointer(image), size(image); kw_args...)::Texture{T,NDim} +end -function Texture(s::ShaderAbstractions.Sampler{T, N}; kwargs...) where {T, N} +function Texture(s::ShaderAbstractions.Sampler{T,N}; kwargs...) where {T,N} tex = Texture( - pointer(s.data), size(s.data), - minfilter = s.minfilter, magfilter = s.magfilter, - x_repeat = s.repeat[1], y_repeat = s.repeat[min(2, N)], z_repeat = s.repeat[min(3, N)], - anisotropic = s.anisotropic; kwargs... + pointer(s.data), + size(s.data), + minfilter=s.minfilter, + magfilter=s.magfilter, + x_repeat=s.repeat[1], + y_repeat=s.repeat[min(2, N)], + z_repeat=s.repeat[min(3, N)], + anisotropic=s.anisotropic; + kwargs..., ) obsfunc = ShaderAbstractions.connect!(s, tex) push!(tex.observers, obsfunc) @@ -153,12 +157,12 @@ end Constructor for Array Texture """ function Texture( - data::Vector{Array{T, 2}}; - internalformat::GLenum = default_internalcolorformat(T), - texturetype::GLenum = GL_TEXTURE_2D_ARRAY, - format::GLenum = default_colorformat(T), - parameters... - ) where T <: GLArrayEltypes + data::Vector{Array{T,2}}; + internalformat::GLenum=default_internalcolorformat(T), + texturetype::GLenum=GL_TEXTURE_2D_ARRAY, + format::GLenum=default_colorformat(T), + parameters..., +) where {T<:GLArrayEltypes} texparams = TextureParameters(T, 2; parameters...) id = glGenTextures() @@ -166,47 +170,45 @@ function Texture( numbertype = julia2glenum(eltype(T)) - layers = length(data) - dims = map(size, data) - maxdims = foldl(dims, init = (0,0)) do v0, x + layers = length(data) + dims = map(size, data) + maxdims = foldl(dims, init=(0, 0)) do v0, x a = max(v0[1], x[1]) b = max(v0[2], x[2]) - (a,b) + return (a, b) end set_packing_alignment(data) glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, internalformat, maxdims..., layers) for (layer, texel) in enumerate(data) width, height = size(texel) - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer-1, width, height, 1, format, numbertype, texel) + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer - 1, width, height, 1, format, numbertype, texel) end - texture = Texture{T, 2}( - id, texturetype, numbertype, - internalformat, format, texparams, - tuple(maxdims...) - ) + texture = Texture{T,2}(id, texturetype, numbertype, internalformat, format, texparams, tuple(maxdims...)) set_parameters(texture) - texture + return texture end - - -function TextureBuffer(buffer::GLBuffer{T}) where T <: GLArrayEltypes +function TextureBuffer(buffer::GLBuffer{T}) where {T<:GLArrayEltypes} texture_type = GL_TEXTURE_BUFFER id = glGenTextures() glBindTexture(texture_type, id) internalformat = default_internalcolorformat(T) glTexBuffer(texture_type, internalformat, buffer.id) - tex = Texture{T, 1}( - id, texture_type, julia2glenum(T), internalformat, - default_colorformat(T), TextureParameters(T, 1), - size(buffer) + tex = Texture{T,1}( + id, + texture_type, + julia2glenum(T), + internalformat, + default_colorformat(T), + TextureParameters(T, 1), + size(buffer), ) - TextureBuffer(tex, buffer) + return TextureBuffer(tex, buffer) end -function TextureBuffer(buffer::Vector{T}) where T <: GLArrayEltypes - buff = GLBuffer(buffer, buffertype = GL_TEXTURE_BUFFER, usage = GL_DYNAMIC_DRAW) - TextureBuffer(buff) +function TextureBuffer(buffer::Vector{T}) where {T<:GLArrayEltypes} + buff = GLBuffer(buffer, buffertype=GL_TEXTURE_BUFFER, usage=GL_DYNAMIC_DRAW) + return TextureBuffer(buff) end #= @@ -244,30 +246,48 @@ end function Base.show(io::IO, ::MIME"text/plain", t::Texture{T,D}) where {T,D} println(io, "Texture$(D)D: ") println(io, " ID: ", t.id) - println(io, " Size: ", reduce(size(t), init = "Dimensions: ") do v0, v1 - v0*"x"*string(v1) + println(io, " Size: ", reduce(size(t), init="Dimensions: ") do v0, v1 + return v0 * "x" * string(v1) end) println(io, " Julia pixel type: ", T) println(io, " OpenGL pixel type: ", GLENUM(t.pixeltype).name) println(io, " Format: ", GLENUM(t.format).name) println(io, " Internal format: ", GLENUM(t.internalformat).name) - println(io, " Parameters: ", t.parameters) + return println(io, " Parameters: ", t.parameters) end # GPUArray interface: -function unsafe_copy!(a::Vector{T}, readoffset::Int, b::TextureBuffer{T}, writeoffset::Int, len::Int) where T +function unsafe_copy!( + a::Vector{T}, + readoffset::Int, + b::TextureBuffer{T}, + writeoffset::Int, + len::Int, +) where {T} copy!(a, readoffset, b.buffer, writeoffset, len) bind(b.texture) - glTexBuffer(b.texture.texturetype, b.texture.internalformat, b.buffer.id) # update texture + return glTexBuffer(b.texture.texturetype, b.texture.internalformat, b.buffer.id) # update texture end -function unsafe_copy!(a::TextureBuffer{T}, readoffset::Int, b::Vector{T}, writeoffset::Int, len::Int) where T +function unsafe_copy!( + a::TextureBuffer{T}, + readoffset::Int, + b::Vector{T}, + writeoffset::Int, + len::Int, +) where {T} copy!(a.buffer, readoffset, b, writeoffset, len) bind(a.texture) - glTexBuffer(a.texture.texturetype, a.texture.internalformat, a.buffer.id) # update texture + return glTexBuffer(a.texture.texturetype, a.texture.internalformat, a.buffer.id) # update texture end -function unsafe_copy!(a::TextureBuffer{T}, readoffset::Int, b::TextureBuffer{T}, writeoffset::Int, len::Int) where T +function unsafe_copy!( + a::TextureBuffer{T}, + readoffset::Int, + b::TextureBuffer{T}, + writeoffset::Int, + len::Int, +) where {T} unsafe_copy!(a.buffer, readoffset, b.buffer, writeoffset, len) bind(a.texture) @@ -275,48 +295,40 @@ function unsafe_copy!(a::TextureBuffer{T}, readoffset::Int, b::TextureBuffer{T}, bind(b.texture) glTexBuffer(b.texture.texturetype, b.texture.internalformat, b.buffer.id) # update texture - bind(t.texture, 0) + return bind(t.texture, 0) end -function gpu_setindex!(t::TextureBuffer{T}, newvalue::Vector{T}, indexes::UnitRange{I}) where {T, I <: Integer} +function gpu_setindex!(t::TextureBuffer{T}, newvalue::Vector{T}, indexes::UnitRange{I}) where {T,I<:Integer} bind(t.texture) t.buffer[indexes] = newvalue # set buffer indexes glTexBuffer(t.texture.texturetype, t.texture.internalformat, t.buffer.id) # update texture - bind(t.texture, 0) + return bind(t.texture, 0) end -function gpu_setindex!(t::Texture{T, 1}, newvalue::Array{T, 1}, indexes::UnitRange{I}) where {T, I <: Integer} +function gpu_setindex!(t::Texture{T,1}, newvalue::Array{T,1}, indexes::UnitRange{I}) where {T,I<:Integer} bind(t) texsubimage(t, newvalue, indexes) - bind(t, 0) + return bind(t, 0) end -function gpu_setindex!(t::Texture{T, N}, newvalue::Array{T, N}, indexes::Union{UnitRange,Integer}...) where {T, N} +function gpu_setindex!( + t::Texture{T,N}, + newvalue::Array{T,N}, + indexes::Union{UnitRange,Integer}..., +) where {T,N} bind(t) texsubimage(t, newvalue, indexes...) - bind(t, 0) + return bind(t, 0) end - -function gpu_setindex!(target::Texture{T, 2}, source::Texture{T, 2}, fbo=glGenFramebuffers()) where T +function gpu_setindex!(target::Texture{T,2}, source::Texture{T,2}, fbo=glGenFramebuffers()) where {T} glBindFramebuffer(GL_FRAMEBUFFER, fbo) - glFramebufferTexture2D( - GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, source.id, 0 - ) - glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, - GL_TEXTURE_2D, target.id, 0 - ) - glDrawBuffer(GL_COLOR_ATTACHMENT1); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, source.id, 0) + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, target.id, 0) + glDrawBuffer(GL_COLOR_ATTACHMENT1) w, h = map(minimum, zip(size(target), size(source))) - glBlitFramebuffer( - 0, 0, w, h, 0, 0, w, h, - GL_COLOR_BUFFER_BIT, GL_NEAREST - ) + return glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST) end - - #= function gpu_setindex!{T}(target::Texture{T, 2}, source::Texture{T, 2}, fbo=glGenFramebuffers()) w, h = map(minimum, zip(size(target), size(source))) @@ -327,48 +339,49 @@ function gpu_setindex!{T}(target::Texture{T, 2}, source::Texture{T, 2}, fbo=glGe end =# # Implementing the GPUArray interface -function gpu_data(t::Texture{T, ND}) where {T, ND} - result = Array{T, ND}(undef, size(t)) +function gpu_data(t::Texture{T,ND}) where {T,ND} + result = Array{T,ND}(undef, size(t)) unsafe_copy!(result, t) return result end -function unsafe_copy!(dest::Array{T, N}, source::Texture{T, N}) where {T,N} +function unsafe_copy!(dest::Array{T,N}, source::Texture{T,N}) where {T,N} bind(source) glGetTexImage(source.texturetype, 0, source.format, source.pixeltype, dest) bind(source, 0) - nothing + return nothing end gpu_data(t::TextureBuffer{T}) where {T} = gpu_data(t.buffer) gpu_getindex(t::TextureBuffer{T}, i::UnitRange{Int64}) where {T} = t.buffer[i] -similar(t::Texture{T, NDim}, newdims::Int...) where {T, NDim} = similar(t, newdims) -function similar(t::TextureBuffer{T}, newdims::NTuple{1, Int}) where T +similar(t::Texture{T,NDim}, newdims::Int...) where {T,NDim} = similar(t, newdims) +function similar(t::TextureBuffer{T}, newdims::NTuple{1,Int}) where {T} buff = similar(t.buffer, newdims...) return TextureBuffer(buff) end -function similar(t::Texture{T, NDim}, newdims::NTuple{NDim, Int}) where {T, NDim} - Texture( +function similar(t::Texture{T,NDim}, newdims::NTuple{NDim,Int}) where {T,NDim} + return Texture( Ptr{T}(C_NULL), - newdims, t.texturetype, + newdims, + t.texturetype, t.pixeltype, t.internalformat, t.format, - t.parameters + t.parameters, ) end # Resize Texture -function gpu_resize!(t::TextureBuffer{T}, newdims::NTuple{1, Int}) where T +function gpu_resize!(t::TextureBuffer{T}, newdims::NTuple{1,Int}) where {T} resize!(t.buffer, newdims) bind(t.texture) glTexBuffer(t.texture.texturetype, t.texture.internalformat, t.buffer.id) #update data in texture - t.texture.size = newdims + t.texture.size = newdims bind(t.texture, 0) - t + return t end # Resize Texture -function gpu_resize!(t::Texture{T, ND}, newdims::NTuple{ND, Int}) where {T, ND} +function gpu_resize!(t::Texture{T,ND}, newdims::NTuple{ND,Int}) where {T,ND} # dangerous code right here...Better write a few tests for this newtex = similar(t, newdims) old_size = size(t) @@ -379,32 +392,68 @@ function gpu_resize!(t::Texture{T, ND}, newdims::NTuple{ND, Int}) where {T, ND} return t end -texsubimage(t::Texture{T, 1}, newvalue::Array{T, 1}, xrange::UnitRange, level=0) where {T} = glTexSubImage1D( - t.texturetype, level, first(xrange)-1, length(xrange), t.format, t.pixeltype, newvalue -) -function texsubimage(t::Texture{T, 2}, newvalue::Array{T, 2}, xrange::UnitRange, yrange::UnitRange, level=0) where T - glTexSubImage2D( - t.texturetype, level, - first(xrange)-1, first(yrange)-1, length(xrange), length(yrange), - t.format, t.pixeltype, newvalue +function texsubimage(t::Texture{T,1}, newvalue::Array{T,1}, xrange::UnitRange, level=0) where {T} + return glTexSubImage1D( + t.texturetype, + level, + first(xrange) - 1, + length(xrange), + t.format, + t.pixeltype, + newvalue, + ) +end +function texsubimage( + t::Texture{T,2}, + newvalue::Array{T,2}, + xrange::UnitRange, + yrange::UnitRange, + level=0, +) where {T} + return glTexSubImage2D( + t.texturetype, + level, + first(xrange) - 1, + first(yrange) - 1, + length(xrange), + length(yrange), + t.format, + t.pixeltype, + newvalue, + ) +end +function texsubimage( + t::Texture{T,3}, + newvalue::Array{T,3}, + xrange::UnitRange, + yrange::UnitRange, + zrange::UnitRange, + level=0, +) where {T} + return glTexSubImage3D( + t.texturetype, + level, + first(xrange) - 1, + first(yrange) - 1, + first(zrange) - 1, + length(xrange), + length(yrange), + length(zrange), + t.format, + t.pixeltype, + newvalue, ) end -texsubimage(t::Texture{T, 3}, newvalue::Array{T, 3}, xrange::UnitRange, yrange::UnitRange, zrange::UnitRange, level=0) where {T} = glTexSubImage3D( - t.texturetype, level, - first(xrange)-1, first(yrange)-1, first(zrange)-1, length(xrange), length(yrange), length(zrange), - t.format, t.pixeltype, newvalue -) - Base.iterate(t::TextureBuffer{T}) where {T} = iterate(t.buffer) -function Base.iterate(t::TextureBuffer{T}, state::Tuple{Ptr{T}, Int}) where T +function Base.iterate(t::TextureBuffer{T}, state::Tuple{Ptr{T},Int}) where {T} v_idx = iterate(t.buffer, state) if v_idx === nothing bind(t) glTexBuffer(t.texturetype, t.internalformat, t.buffer.id) bind(t, 0) end - v_idx + return v_idx end function default_colorformat_sym(colordim::Integer, isinteger::Bool, colororder::AbstractString) colordim > 4 && error("no colors with dimension > 4 allowed. Dimension given: ", colordim) @@ -417,20 +466,26 @@ function default_colorformat_sym(colordim::Integer, isinteger::Bool, colororder: return Symbol(sym) end -default_colorformat_sym(::Type{T}) where {T <: Real} = default_colorformat_sym(1, T <: Integer, "RED") -default_colorformat_sym(::Type{T}) where {T <: AbstractArray} = default_colorformat_sym(cardinality(T), eltype(T) <: Integer, "RGBA") -default_colorformat_sym(::Type{T}) where {T <: StaticVector} = default_colorformat_sym(cardinality(T), eltype(T) <: Integer, "RGBA") -default_colorformat_sym(::Type{T}) where {T <: Colorant} = default_colorformat_sym(cardinality(T), eltype(T) <: Integer, string(Base.typename(T).name)) +default_colorformat_sym(::Type{T}) where {T<:Real} = default_colorformat_sym(1, T <: Integer, "RED") +function default_colorformat_sym(::Type{T}) where {T<:AbstractArray} + return default_colorformat_sym(cardinality(T), eltype(T) <: Integer, "RGBA") +end +function default_colorformat_sym(::Type{T}) where {T<:StaticVector} + return default_colorformat_sym(cardinality(T), eltype(T) <: Integer, "RGBA") +end +function default_colorformat_sym(::Type{T}) where {T<:Colorant} + return default_colorformat_sym(cardinality(T), eltype(T) <: Integer, string(Base.typename(T).name)) +end -@generated function default_colorformat(::Type{T}) where T +@generated function default_colorformat(::Type{T}) where {T} sym = default_colorformat_sym(T) if !isdefined(ModernGL, sym) error("$T doesn't have a propper mapping to an OpenGL format") end - :($sym) + return :($sym) end -function default_internalcolorformat_sym(::Type{T}) where T +function default_internalcolorformat_sym(::Type{T}) where {T} cdim = colordim(T) if cdim > 4 || cdim < 1 error("$(cdim)-dimensional colors not supported") @@ -449,33 +504,30 @@ function default_internalcolorformat_sym(::Type{T}) where T elseif eltyp <: Unsigned sym *= "UI" end - Symbol(sym) + return Symbol(sym) end # for I = 1:4 # for -@generated function default_internalcolorformat(::Type{T}) where T +@generated function default_internalcolorformat(::Type{T}) where {T} sym = default_internalcolorformat_sym(T) if !isdefined(ModernGL, sym) error("$T doesn't have a propper mapping to an OpenGL format") end - :($sym) + return :($sym) end - #Supported texture modes/dimensions function default_texturetype(ndim::Integer) ndim == 1 && return GL_TEXTURE_1D ndim == 2 && return GL_TEXTURE_2D ndim == 3 && return GL_TEXTURE_3D - error("Dimensionality: $(ndim), not supported for OpenGL texture") + return error("Dimensionality: $(ndim), not supported for OpenGL texture") end - -map_texture_paramers(s::NTuple{N, Symbol}) where {N} = map(map_texture_paramers, s) +map_texture_paramers(s::NTuple{N,Symbol}) where {N} = map(map_texture_paramers, s) function map_texture_paramers(s::Symbol) - s == :clamp_to_edge && return GL_CLAMP_TO_EDGE s == :mirrored_repeat && return GL_MIRRORED_REPEAT s == :repeat && return GL_REPEAT @@ -487,18 +539,22 @@ function map_texture_paramers(s::Symbol) s == :nearest_mipmap_linear && return GL_NEAREST_MIPMAP_LINEAR s == :linear_mipmap_linear && return GL_LINEAR_MIPMAP_LINEAR - error("$s is not a valid texture parameter") + return error("$s is not a valid texture parameter") end -function TextureParameters(T, NDim; - minfilter = T <: Integer ? :nearest : :linear, - magfilter = minfilter, # magnification - x_repeat = :clamp_to_edge, #wrap_s - y_repeat = x_repeat, #wrap_t - z_repeat = x_repeat, #wrap_r - anisotropic = 1f0 - ) - T <: Integer && (minfilter == :linear || magfilter == :linear) && error("Wrong Texture Parameter: Integer texture can't interpolate. Try :nearest") +function TextureParameters( + T, + NDim; + minfilter=T <: Integer ? :nearest : :linear, + magfilter=minfilter, # magnification + x_repeat=:clamp_to_edge, #wrap_s + y_repeat=x_repeat, #wrap_t + z_repeat=x_repeat, #wrap_r + anisotropic=1.0f0, +) + T <: Integer && + (minfilter == :linear || magfilter == :linear) && + error("Wrong Texture Parameter: Integer texture can't interpolate. Try :nearest") repeat = (x_repeat, y_repeat, z_repeat) swizzle_mask = if T <: Gray GLenum[GL_RED, GL_RED, GL_RED, GL_ONE] @@ -507,21 +563,16 @@ function TextureParameters(T, NDim; else GLenum[] end - TextureParameters( - minfilter, magfilter, ntuple(i->repeat[i], NDim), - anisotropic, swizzle_mask - ) -end -function TextureParameters(t::Texture{T, NDim}; kw_args...) where {T, NDim} - TextureParameters(T, NDim; kw_args...) + return TextureParameters(minfilter, magfilter, ntuple(i -> repeat[i], NDim), anisotropic, swizzle_mask) end +TextureParameters(t::Texture{T,NDim}; kw_args...) where {T,NDim} = TextureParameters(T, NDim; kw_args...) const GL_TEXTURE_MAX_ANISOTROPY_EXT = GLenum(0x84FE) -function set_parameters(t::Texture{T, N}, params::TextureParameters=t.parameters) where {T, N} +function set_parameters(t::Texture{T,N}, params::TextureParameters=t.parameters) where {T,N} fnames = (:minfilter, :magfilter, :repeat) data = Dict([(name, map_texture_paramers(getfield(params, name))) for name in fnames]) - result = Tuple{GLenum, Any}[] + result = Tuple{GLenum,Any}[] push!(result, (GL_TEXTURE_MIN_FILTER, data[:minfilter])) push!(result, (GL_TEXTURE_MAG_FILTER, data[:magfilter])) push!(result, (GL_TEXTURE_WRAP_S, data[:repeat][1])) @@ -540,21 +591,15 @@ function set_parameters(t::Texture{T, N}, params::TextureParameters=t.parameters e.code == GLFW.NO_CURRENT_CONTEXT || rethrow(e) end t.parameters = params - set_parameters(t, result) -end -function texparameter(t::Texture, key::GLenum, val::GLenum) - glTexParameteri(t.texturetype, key, val) + return set_parameters(t, result) end -function texparameter(t::Texture, key::GLenum, val::Vector) - glTexParameteriv(t.texturetype, key, val) -end -function texparameter(t::Texture, key::GLenum, val::Float32) - glTexParameterf(t.texturetype, key, val) -end -function set_parameters(t::Texture, parameters::Vector{Tuple{GLenum, Any}}) +texparameter(t::Texture, key::GLenum, val::GLenum) = glTexParameteri(t.texturetype, key, val) +texparameter(t::Texture, key::GLenum, val::Vector) = glTexParameteriv(t.texturetype, key, val) +texparameter(t::Texture, key::GLenum, val::Float32) = glTexParameterf(t.texturetype, key, val) +function set_parameters(t::Texture, parameters::Vector{Tuple{GLenum,Any}}) bind(t) for elem in parameters texparameter(t, elem...) end - bind(t, 0) + return bind(t, 0) end diff --git a/GLMakie/src/GLAbstraction/GLTypes.jl b/GLMakie/src/GLAbstraction/GLTypes.jl index 3c6e860191a..9c66c0cd0d1 100644 --- a/GLMakie/src/GLAbstraction/GLTypes.jl +++ b/GLMakie/src/GLAbstraction/GLTypes.jl @@ -1,7 +1,7 @@ ############################################################################ const TOrSignal{T} = Union{Observable{T},T} -const ArrayOrSignal{T,N} = TOrSignal{X} where X <: AbstractArray{T,N} +const ArrayOrSignal{T,N} = TOrSignal{X} where {X<:AbstractArray{T,N}} const VecOrSignal{T} = ArrayOrSignal{T,1} const MatOrSignal{T} = ArrayOrSignal{T,2} const VolumeOrSignal{T} = ArrayOrSignal{T,3} @@ -19,7 +19,7 @@ Returns the cardinality of a type. falls back to length """ cardinality(x) = length(x) cardinality(x::Number) = 1 -cardinality(x::Type{T}) where {T <: Number} = 1 +cardinality(x::Type{T}) where {T<:Number} = 1 struct Shader name::Symbol @@ -27,32 +27,23 @@ struct Shader typ::GLenum id::GLuint context::GLContext - function Shader(name, source, typ, id) - new(name, source, typ, id, current_context()) - end + Shader(name, source, typ, id) = new(name, source, typ, id, current_context()) end -function Shader(name, source::Vector{UInt8}, typ) - compile_shader(source, typ, name) -end +Shader(name, source::Vector{UInt8}, typ) = compile_shader(source, typ, name) name(s::Shader) = s.name import Base: == -function (==)(a::Shader, b::Shader) - a.source == b.source && a.typ == b.typ && a.id == b.id && a.context == b.context -end - -function Base.hash(s::Shader, h::UInt64) - hash((s.source, s.typ, s.id, s.context), h) -end +(==)(a::Shader, b::Shader) = a.source == b.source && a.typ == b.typ && a.id == b.id && a.context == b.context +Base.hash(s::Shader, h::UInt64) = hash((s.source, s.typ, s.id, s.context), h) function Base.show(io::IO, shader::Shader) println(io, GLENUM(shader.typ).name, " shader: $(shader.name))") println(io, "source:") - print_with_lines(io, String(shader.source)) + return print_with_lines(io, String(shader.source)) end mutable struct GLProgram @@ -61,10 +52,15 @@ mutable struct GLProgram nametype::Dict{Symbol,GLenum} uniformloc::Dict{Symbol,Tuple} context::GLContext - function GLProgram(id::GLuint, shader::Vector{Shader}, nametype::Dict{Symbol,GLenum}, uniformloc::Dict{Symbol,Tuple}) + function GLProgram( + id::GLuint, + shader::Vector{Shader}, + nametype::Dict{Symbol,GLenum}, + uniformloc::Dict{Symbol,Tuple}, + ) obj = new(id, shader, nametype, uniformloc, current_context()) finalizer(free, obj) - obj + return obj end end @@ -93,7 +89,7 @@ struct RenderBuffer glGenRenderbuffers(1, id) glBindRenderbuffer(GL_RENDERBUFFER, id[1]) glRenderbufferStorage(GL_RENDERBUFFER, format, dimension...) - new(id, format, current_context()) + return new(id, format, current_context()) end end @@ -102,17 +98,17 @@ function resize!(rb::RenderBuffer, newsize::AbstractArray) error("RenderBuffer needs to be 2 dimensional. Dimension found: ", newsize) end glBindRenderbuffer(GL_RENDERBUFFER, rb.id) - glRenderbufferStorage(GL_RENDERBUFFER, rb.format, newsize...) + return glRenderbufferStorage(GL_RENDERBUFFER, rb.format, newsize...) end struct FrameBuffer{T} id::GLuint attachments::Vector{Any} context::GLContext - function FrameBuffer{T}(dimensions::Observable) where T + function FrameBuffer{T}(dimensions::Observable) where {T} fb = glGenFramebuffers() glBindFramebuffer(GL_FRAMEBUFFER, fb) - new(id, attachments, current_context()) + return new(id, attachments, current_context()) end end @@ -132,29 +128,27 @@ const GLArrayEltypes = Union{StaticVector,Real,Colorant} """ Transform julia datatypes to opengl enum type """ -julia2glenum(x::Type{T}) where {T <: FixedPoint} = julia2glenum(FixedPointNumbers.rawtype(x)) -julia2glenum(x::Union{Type{T},T}) where {T <: Union{StaticVector,Colorant}} = julia2glenum(eltype(x)) +julia2glenum(x::Type{T}) where {T<:FixedPoint} = julia2glenum(FixedPointNumbers.rawtype(x)) +julia2glenum(x::Union{Type{T},T}) where {T<:Union{StaticVector,Colorant}} = julia2glenum(eltype(x)) julia2glenum(::Type{OffsetInteger{O,T}}) where {O,T} = julia2glenum(T) -julia2glenum(::Type{GLubyte}) = GL_UNSIGNED_BYTE -julia2glenum(::Type{GLbyte}) = GL_BYTE -julia2glenum(::Type{GLuint}) = GL_UNSIGNED_INT +julia2glenum(::Type{GLubyte}) = GL_UNSIGNED_BYTE +julia2glenum(::Type{GLbyte}) = GL_BYTE +julia2glenum(::Type{GLuint}) = GL_UNSIGNED_INT julia2glenum(::Type{GLushort}) = GL_UNSIGNED_SHORT -julia2glenum(::Type{GLshort}) = GL_SHORT -julia2glenum(::Type{GLint}) = GL_INT -julia2glenum(::Type{GLfloat}) = GL_FLOAT +julia2glenum(::Type{GLshort}) = GL_SHORT +julia2glenum(::Type{GLint}) = GL_INT +julia2glenum(::Type{GLfloat}) = GL_FLOAT julia2glenum(::Type{GLdouble}) = GL_DOUBLE -julia2glenum(::Type{Float16}) = GL_HALF_FLOAT +julia2glenum(::Type{Float16}) = GL_HALF_FLOAT struct DepthStencil_24_8 <: Real data::NTuple{4,UInt8} end -Base.eltype(::Type{<: DepthStencil_24_8}) = DepthStencil_24_8 +Base.eltype(::Type{<:DepthStencil_24_8}) = DepthStencil_24_8 julia2glenum(x::Type{DepthStencil_24_8}) = GL_UNSIGNED_INT_24_8 -function julia2glenum(::Type{T}) where T - error("Type: $T not supported as opengl number datatype") -end +julia2glenum(::Type{T}) where {T} = error("Type: $T not supported as opengl number datatype") include("GLBuffer.jl") include("GLTexture.jl") @@ -176,11 +170,11 @@ mutable struct GLVertexArray{T} context::GLContext requires_update::Observable{Bool} - function GLVertexArray{T}(program, id, bufferlength, buffers, indices) where T + function GLVertexArray{T}(program, id, bufferlength, buffers, indices) where {T} va = new(program, id, bufferlength, buffers, indices, current_context(), true) for (name, buffer) in buffers on(buffer.requires_update) do _ # only triggers true anyway - va.requires_update[] = true + return va.requires_update[] = true end end @@ -225,10 +219,7 @@ function GLVertexArray(bufferdict::Dict, program::GLProgram) bufferlengths *= "\n\t$name has length $(length(buffer))" end end - error( - "Buffer $attribute does not have the same length as the other buffers." * - bufferlengths - ) + error("Buffer $attribute does not have the same length as the other buffers." * bufferlengths) end bind(buffer) attribLocation = get_attribute_location(program.id, attribute) @@ -240,7 +231,14 @@ function GLVertexArray(bufferdict::Dict, program::GLProgram) buffers[attribute] = buffer continue end - glVertexAttribPointer(attribLocation, cardinality(buffer), julia2glenum(eltype(buffer)), GL_FALSE, 0, C_NULL) + glVertexAttribPointer( + attribLocation, + cardinality(buffer), + julia2glenum(eltype(buffer)), + GL_FALSE, + 0, + C_NULL, + ) glEnableVertexAttribArray(attribLocation) buffers[attribute] = buffer lenbuffer = buffer @@ -255,7 +253,7 @@ function GLVertexArray(bufferdict::Dict, program::GLProgram) return obj end using ShaderAbstractions: Buffer -function GLVertexArray(program::GLProgram, buffers::Buffer, triangles::AbstractVector{<: GLTriangleFace}) +function GLVertexArray(program::GLProgram, buffers::Buffer, triangles::AbstractVector{<:GLTriangleFace}) # get the size of the first array, to assert later, that all have the same size id = glGenVertexArrays() glBindVertexArray(id) @@ -269,7 +267,14 @@ function GLVertexArray(program::GLProgram, buffers::Buffer, triangles::AbstractV if attribLocation == -1 error("could not bind attribute $(attribute)") end - glVertexAttribPointer(attribLocation, cardinality(buffer), julia2glenum(eltype(buffer)), GL_FALSE, 0, C_NULL) + glVertexAttribPointer( + attribLocation, + cardinality(buffer), + julia2glenum(eltype(buffer)), + GL_FALSE, + 0, + C_NULL, + ) glEnableVertexAttribArray(attribLocation) buffers[attribute] = buffer end @@ -284,16 +289,15 @@ function bind(va::GLVertexArray) if va.id == 0 error("Binding freed VertexArray") end - glBindVertexArray(va.id) + return glBindVertexArray(va.id) end - function Base.show(io::IO, vao::GLVertexArray) show(io, vao.program) println(io, "GLVertexArray $(vao.id):") print(io, "GLVertexArray $(vao.id) buffers: ") writemime(io, MIME("text/plain"), vao.buffers) - println(io, "\nGLVertexArray $(vao.id) indices: ", vao.indices) + return println(io, "\nGLVertexArray $(vao.id) indices: ", vao.indices) end ################################################################################## @@ -306,23 +310,26 @@ function pack_bool(id, bool) end mutable struct RenderObject{Pre} - context # OpenGL context + context::Any # OpenGL context uniforms::Dict{Symbol,Any} observables::Vector{Observable} # for clean up vertexarray::GLVertexArray prerenderfunction::Pre - postrenderfunction + postrenderfunction::Any id::UInt32 requires_update::Bool visible::Bool function RenderObject{Pre}( - context, - uniforms::Dict{Symbol,Any}, observables::Vector{Observable}, - vertexarray::GLVertexArray, - prerenderfunctions, postrenderfunctions, - visible, track_updates = true - ) where Pre + context, + uniforms::Dict{Symbol,Any}, + observables::Vector{Observable}, + vertexarray::GLVertexArray, + prerenderfunctions, + postrenderfunctions, + visible, + track_updates=true, + ) where {Pre} fxaa = Bool(to_value(get!(uniforms, :fxaa, true))) RENDER_OBJECT_ID_COUNTER[] += one(UInt32) # Store fxaa in ID, so we can access it in the shader to create a mask @@ -333,9 +340,14 @@ mutable struct RenderObject{Pre} id = pack_bool(RENDER_OBJECT_ID_COUNTER[], fxaa) robj = new( context, - uniforms, observables, vertexarray, - prerenderfunctions, postrenderfunctions, - id, true, visible[] + uniforms, + observables, + vertexarray, + prerenderfunctions, + postrenderfunctions, + id, + true, + visible[], ) if track_updates @@ -345,7 +357,7 @@ mutable struct RenderObject{Pre} # visible = false on(visible) do visible robj.visible = visible - robj.requires_update = true + return robj.requires_update = true end function request_update(_::Any) @@ -366,7 +378,7 @@ mutable struct RenderObject{Pre} on(request_update, vertexarray.requires_update) else on(visible) do visible - robj.visible = visible + return robj.visible = visible end # remove tracking from GPUArrays @@ -390,12 +402,7 @@ mutable struct RenderObject{Pre} end end -function RenderObject( - data::Dict{Symbol,Any}, program, - pre::Pre, post, - context=current_context() - ) where Pre - +function RenderObject(data::Dict{Symbol,Any}, program, pre::Pre, post, context=current_context()) where {Pre} switch_context!(context) # This is a lazy workaround for disabling updates of `requires_update` when @@ -448,16 +455,7 @@ function RenderObject( end end - robj = RenderObject{Pre}( - context, - data, - observables, - vertexarray, - pre, - post, - visible, - track_updates - ) + robj = RenderObject{Pre}(context, data, observables, vertexarray, pre, post, visible, track_updates) # automatically integrate object ID, will be discarded if shader doesn't use it robj[:objectid] = robj.id return robj @@ -467,21 +465,20 @@ include("GLRenderObject.jl") #################################################################################### # freeing -function free(x) +free(x) = try unsafe_free(x) catch e isa(e, ContextNotAvailable) && return # if context got destroyed no need to worry! rethrow(e) end -end -function clean_up_observables(x::T) where T +function clean_up_observables(x::T) where {T} if hasfield(T, :observers) foreach(off, x.observers) empty!(x.observers) end - Observables.clear(x.requires_update) + return Observables.clear(x.requires_update) end # OpenGL has the annoying habit of reusing id's when creating a new context diff --git a/GLMakie/src/GLAbstraction/GLUniforms.jl b/GLMakie/src/GLAbstraction/GLUniforms.jl index 17f83cc7ec8..1601a3943a4 100644 --- a/GLMakie/src/GLAbstraction/GLUniforms.jl +++ b/GLMakie/src/GLAbstraction/GLUniforms.jl @@ -5,48 +5,50 @@ const GLSL_COMPATIBLE_NUMBER_TYPES = (GLfloat, GLint, GLuint, GLdouble) const NATIVE_TYPES = Union{ - StaticVector, Mat, GLSL_COMPATIBLE_NUMBER_TYPES..., - ZeroIndex{GLint}, ZeroIndex{GLuint}, - GLBuffer, GPUArray, Shader, GLProgram + StaticVector, + Mat, + GLSL_COMPATIBLE_NUMBER_TYPES..., + ZeroIndex{GLint}, + ZeroIndex{GLuint}, + GLBuffer, + GPUArray, + Shader, + GLProgram, } -opengl_prefix(T) = error("Object $T is not a supported uniform element type") +opengl_prefix(T) = error("Object $T is not a supported uniform element type") opengl_postfix(T) = error("Object $T is not a supported uniform element type") - -opengl_prefix(x::Type{T}) where {T <: Union{FixedPoint, Float32, Float16}} = "" -opengl_prefix(x::Type{T}) where {T <: Float64} = "d" +opengl_prefix(x::Type{T}) where {T<:Union{FixedPoint,Float32,Float16}} = "" +opengl_prefix(x::Type{T}) where {T<:Float64} = "d" opengl_prefix(x::Type{Cint}) = "i" -opengl_prefix(x::Type{T}) where {T <: Union{Cuint, UInt8, UInt16}} = "u" +opengl_prefix(x::Type{T}) where {T<:Union{Cuint,UInt8,UInt16}} = "u" opengl_postfix(x::Type{Float64}) = "dv" opengl_postfix(x::Type{Float32}) = "fv" -opengl_postfix(x::Type{Cint}) = "iv" -opengl_postfix(x::Type{Cuint}) = "uiv" - +opengl_postfix(x::Type{Cint}) = "iv" +opengl_postfix(x::Type{Cuint}) = "uiv" -function uniformfunc(typ::DataType, dims::Tuple{Int}) - Symbol(string("glUniform", first(dims), opengl_postfix(typ))) -end -function uniformfunc(typ::DataType, dims::Tuple{Int, Int}) +uniformfunc(typ::DataType, dims::Tuple{Int}) = Symbol(string("glUniform", first(dims), opengl_postfix(typ))) +function uniformfunc(typ::DataType, dims::Tuple{Int,Int}) M, N = dims - Symbol(string("glUniformMatrix", M == N ? "$M" : "$(M)x$(N)", opengl_postfix(typ))) + return Symbol(string("glUniformMatrix", M == N ? "$M" : "$(M)x$(N)", opengl_postfix(typ))) end gluniform(location::Integer, x::Nothing) = nothing -function gluniform(location::Integer, x::Union{StaticVector, Mat, Colorant}) +function gluniform(location::Integer, x::Union{StaticVector,Mat,Colorant}) xref = [x] - gluniform(location, xref) + return gluniform(location, xref) end _size(p) = size(p) _size(p::Colorant) = (length(p),) -_size(p::Type{T}) where {T <: Colorant} = (length(p),) +_size(p::Type{T}) where {T<:Colorant} = (length(p),) _ndims(p) = ndims(p) -_ndims(p::Type{T}) where {T <: Colorant} = 1 +_ndims(p::Type{T}) where {T<:Colorant} = 1 -@generated function gluniform(location::Integer, x::Vector{FSA}) where FSA <: Union{Mat, Colorant, StaticVector} +@generated function gluniform(location::Integer, x::Vector{FSA}) where {FSA<:Union{Mat,Colorant,StaticVector}} func = uniformfunc(eltype(FSA), _size(FSA)) callexpr = if _ndims(FSA) == 2 :($func(location, length(x), GL_FALSE, x)) @@ -58,33 +60,36 @@ _ndims(p::Type{T}) where {T <: Colorant} = 1 end end - #Some additional uniform functions, not related to Imutable Arrays gluniform(location::Integer, target::Integer, t::Texture) = gluniform(GLint(location), GLint(target), t) -gluniform(location::Integer, target::Integer, t::GPUVector) = gluniform(GLint(location), GLint(target), t.buffer) -gluniform(location::Integer, target::Integer, t::Observable) = gluniform(GLint(location), GLint(target), to_value(t)) -gluniform(location::Integer, target::Integer, t::TextureBuffer) = gluniform(GLint(location), GLint(target), t.texture) +function gluniform(location::Integer, target::Integer, t::GPUVector) + return gluniform(GLint(location), GLint(target), t.buffer) +end +function gluniform(location::Integer, target::Integer, t::Observable) + return gluniform(GLint(location), GLint(target), to_value(t)) +end +function gluniform(location::Integer, target::Integer, t::TextureBuffer) + return gluniform(GLint(location), GLint(target), t.texture) +end function gluniform(location::GLint, target::GLint, t::Texture) activeTarget = GL_TEXTURE0 + UInt32(target) glActiveTexture(activeTarget) glBindTexture(t.texturetype, t.id) - gluniform(location, target) + return gluniform(location, target) end gluniform(location::Integer, x::Enum) = gluniform(GLint(location), GLint(x)) -function gluniform(loc::Integer, x::Observable{T}) where T - gluniform(GLint(loc), to_value(x)) -end +gluniform(loc::Integer, x::Observable{T}) where {T} = gluniform(GLint(loc), to_value(x)) -gluniform(location::Integer, x::Union{GLubyte, GLushort, GLuint}) = glUniform1ui(GLint(location), x) -gluniform(location::Integer, x::Union{GLbyte, GLshort, GLint, Bool}) = glUniform1i(GLint(location), x) -gluniform(location::Integer, x::GLfloat) = glUniform1f(GLint(location), x) -gluniform(location::Integer, x::GLdouble) = glUniform1d(GLint(location), x) +gluniform(location::Integer, x::Union{GLubyte,GLushort,GLuint}) = glUniform1ui(GLint(location), x) +gluniform(location::Integer, x::Union{GLbyte,GLshort,GLint,Bool}) = glUniform1i(GLint(location), x) +gluniform(location::Integer, x::GLfloat) = glUniform1f(GLint(location), x) +gluniform(location::Integer, x::GLdouble) = glUniform1d(GLint(location), x) #Uniform upload functions for julia arrays... -gluniform(location::GLint, x::Vector{Float32}) = glUniform1fv(location, length(x), x) -gluniform(location::GLint, x::Vector{GLdouble}) = glUniform1dv(location, length(x), x) -gluniform(location::GLint, x::Vector{GLint}) = glUniform1iv(location, length(x), x) +gluniform(location::GLint, x::Vector{Float32}) = glUniform1fv(location, length(x), x) +gluniform(location::GLint, x::Vector{GLdouble}) = glUniform1dv(location, length(x), x) +gluniform(location::GLint, x::Vector{GLint}) = glUniform1iv(location, length(x), x) gluniform(location::GLint, x::Vector{GLuint}) = glUniform1uiv(location, length(x), x) glsl_typename(x::T) where {T} = glsl_typename(T) @@ -94,172 +99,187 @@ glsl_typename(t::Type{GLfloat}) = "float" glsl_typename(t::Type{GLdouble}) = "double" glsl_typename(t::Type{GLuint}) = "uint" glsl_typename(t::Type{GLint}) = "int" -glsl_typename(t::Type{T}) where {T <: Union{StaticVector, Colorant}} = string(opengl_prefix(eltype(T)), "vec", length(T)) +function glsl_typename(t::Type{T}) where {T<:Union{StaticVector,Colorant}} + return string(opengl_prefix(eltype(T)), "vec", length(T)) +end glsl_typename(t::Type{TextureBuffer{T}}) where {T} = string(opengl_prefix(eltype(T)), "samplerBuffer") -function glsl_typename(t::Texture{T, D}) where {T, D} +function glsl_typename(t::Texture{T,D}) where {T,D} str = string(opengl_prefix(eltype(T)), "sampler", D, "D") t.texturetype == GL_TEXTURE_2D_ARRAY && (str *= "Array") - str + return str end -function glsl_typename(t::Type{T}) where T <: Mat +function glsl_typename(t::Type{T}) where {T<:Mat} M, N = size(t) - string(opengl_prefix(eltype(t)), "mat", M==N ? M : string(M, "x", N)) + return string(opengl_prefix(eltype(t)), "mat", M == N ? M : string(M, "x", N)) end toglsltype_string(t::Observable) = toglsltype_string(to_value(t)) -toglsltype_string(x::T) where {T<:Union{Real, Mat, StaticVector, Texture, Colorant, TextureBuffer, Nothing}} = "uniform $(glsl_typename(x))" +function toglsltype_string( + x::T, +) where {T<:Union{Real,Mat,StaticVector,Texture,Colorant,TextureBuffer,Nothing}} + return "uniform $(glsl_typename(x))" +end #Handle GLSL structs, which need to be addressed via single fields -function toglsltype_string(x::T) where T +function toglsltype_string(x::T) where {T} if isa_gl_struct(x) string("uniform ", T.name.name) else - error("can't splice $T into an OpenGL shader. Make sure all fields are of a concrete type and isbits(FieldType)-->true") + error( + "can't splice $T into an OpenGL shader. Make sure all fields are of a concrete type and isbits(FieldType)-->true", + ) end end -toglsltype_string(t::Union{GLBuffer{T}, GPUVector{T}}) where {T} = string("in ", glsl_typename(T)) +toglsltype_string(t::Union{GLBuffer{T},GPUVector{T}}) where {T} = string("in ", glsl_typename(T)) # Gets used to access a -function glsl_variable_access(keystring, t::Texture{T, D}) where {T,D} +function glsl_variable_access(keystring, t::Texture{T,D}) where {T,D} fields = SubString("rgba", 1, length(T)) if t.texturetype == GL_TEXTURE_BUFFER return string("texelFetch(", keystring, "index).", fields, ";") end return string("getindex(", keystring, "index).", fields, ";") end -function glsl_variable_access(keystring, ::Union{Real, GLBuffer, GPUVector, Mat, Colorant}) - string(keystring, ";") -end -function glsl_variable_access(keystring, s::Observable) - glsl_variable_access(keystring, to_value(s)) -end +glsl_variable_access(keystring, ::Union{Real,GLBuffer,GPUVector,Mat,Colorant}) = string(keystring, ";") +glsl_variable_access(keystring, s::Observable) = glsl_variable_access(keystring, to_value(s)) function glsl_variable_access(keystring, t::Any) - error("no glsl variable calculation available for : ", keystring, " of type ", typeof(t)) + return error("no glsl variable calculation available for : ", keystring, " of type ", typeof(t)) end function uniform_name_type(program::GLuint) uniformLength = glGetProgramiv(program, GL_ACTIVE_UNIFORMS) - Dict{Symbol, GLenum}(ntuple(uniformLength) do i # take size and name - name, typ = glGetActiveUniform(program, i-1) + Dict{Symbol,GLenum}(ntuple(uniformLength) do i # take size and name + return name, typ = glGetActiveUniform(program, i - 1) end) end function attribute_name_type(program::GLuint) uniformLength = glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES) - Dict{Symbol, GLenum}(ntuple(uniformLength) do i - name, typ = glGetActiveAttrib(program, i-1) + Dict{Symbol,GLenum}(ntuple(uniformLength) do i + return name, typ = glGetActiveAttrib(program, i - 1) end) end function istexturesampler(typ::GLenum) return ( - typ == GL_SAMPLER_BUFFER || typ == GL_INT_SAMPLER_BUFFER || typ == GL_UNSIGNED_INT_SAMPLER_BUFFER || - typ == GL_IMAGE_2D || - typ == GL_SAMPLER_1D || typ == GL_SAMPLER_2D || typ == GL_SAMPLER_3D || - typ == GL_UNSIGNED_INT_SAMPLER_1D || typ == GL_UNSIGNED_INT_SAMPLER_2D || typ == GL_UNSIGNED_INT_SAMPLER_3D || - typ == GL_INT_SAMPLER_1D || typ == GL_INT_SAMPLER_2D || typ == GL_INT_SAMPLER_3D || - typ == GL_SAMPLER_1D_ARRAY || typ == GL_SAMPLER_2D_ARRAY || - typ == GL_UNSIGNED_INT_SAMPLER_1D_ARRAY || typ == GL_UNSIGNED_INT_SAMPLER_2D_ARRAY || - typ == GL_INT_SAMPLER_1D_ARRAY || typ == GL_INT_SAMPLER_2D_ARRAY + typ == GL_SAMPLER_BUFFER || + typ == GL_INT_SAMPLER_BUFFER || + typ == GL_UNSIGNED_INT_SAMPLER_BUFFER || + typ == GL_IMAGE_2D || + typ == GL_SAMPLER_1D || + typ == GL_SAMPLER_2D || + typ == GL_SAMPLER_3D || + typ == GL_UNSIGNED_INT_SAMPLER_1D || + typ == GL_UNSIGNED_INT_SAMPLER_2D || + typ == GL_UNSIGNED_INT_SAMPLER_3D || + typ == GL_INT_SAMPLER_1D || + typ == GL_INT_SAMPLER_2D || + typ == GL_INT_SAMPLER_3D || + typ == GL_SAMPLER_1D_ARRAY || + typ == GL_SAMPLER_2D_ARRAY || + typ == GL_UNSIGNED_INT_SAMPLER_1D_ARRAY || + typ == GL_UNSIGNED_INT_SAMPLER_2D_ARRAY || + typ == GL_INT_SAMPLER_1D_ARRAY || + typ == GL_INT_SAMPLER_2D_ARRAY ) end +gl_promote(x::Type{T}) where {T<:Integer} = Cint +gl_promote(x::Type{Union{Int16,Int8}}) = x -gl_promote(x::Type{T}) where {T <: Integer} = Cint -gl_promote(x::Type{Union{Int16, Int8}}) = x +gl_promote(x::Type{T}) where {T<:Unsigned} = Cuint +gl_promote(x::Type{Union{UInt16,UInt8}}) = x -gl_promote(x::Type{T}) where {T <: Unsigned} = Cuint -gl_promote(x::Type{Union{UInt16, UInt8}}) = x - -gl_promote(x::Type{T}) where {T <: AbstractFloat} = Float32 +gl_promote(x::Type{T}) where {T<:AbstractFloat} = Float32 gl_promote(x::Type{Float16}) = x -gl_promote(x::Type{T}) where {T <: Normed} = N0f32 +gl_promote(x::Type{T}) where {T<:Normed} = N0f32 gl_promote(x::Type{N0f16}) = x gl_promote(x::Type{N0f8}) = x -const Color3{T} = Colorant{T, 3} -const Color4{T} = Colorant{T, 4} +const Color3{T} = Colorant{T,3} +const Color4{T} = Colorant{T,4} -gl_promote(x::Type{Bool}) = GLboolean -gl_promote(x::Type{T}) where {T <: Gray} = Gray{gl_promote(eltype(T))} -gl_promote(x::Type{T}) where {T <: Color3} = RGB{gl_promote(eltype(T))} -gl_promote(x::Type{T}) where {T <: Color4} = RGBA{gl_promote(eltype(T))} -gl_promote(x::Type{T}) where {T <: BGRA} = BGRA{gl_promote(eltype(T))} -gl_promote(x::Type{T}) where {T <: BGR} = BGR{gl_promote(eltype(T))} +gl_promote(x::Type{Bool}) = GLboolean +gl_promote(x::Type{T}) where {T<:Gray} = Gray{gl_promote(eltype(T))} +gl_promote(x::Type{T}) where {T<:Color3} = RGB{gl_promote(eltype(T))} +gl_promote(x::Type{T}) where {T<:Color4} = RGBA{gl_promote(eltype(T))} +gl_promote(x::Type{T}) where {T<:BGRA} = BGRA{gl_promote(eltype(T))} +gl_promote(x::Type{T}) where {T<:BGR} = BGR{gl_promote(eltype(T))} -gl_promote(x::Type{Vec{N, T}}) where {N, T} = Vec{N, gl_promote(T)} -gl_promote(x::Type{Point{N, T}}) where {N, T} = Point{N, gl_promote(T)} +gl_promote(x::Type{Vec{N,T}}) where {N,T} = Vec{N,gl_promote(T)} +gl_promote(x::Type{Point{N,T}}) where {N,T} = Point{N,gl_promote(T)} gl_convert(x::AbstractVector{Vec3f}) = x -gl_convert(x::T) where {T <: Number} = gl_promote(T)(x) -gl_convert(x::T) where {T <: Colorant} = gl_promote(T)(x) -gl_convert(x::T) where {T <: AbstractMesh} = gl_convert(x) -gl_convert(x::T) where {T <: GeometryBasics.Mesh} = gl_promote(T)(x) -gl_convert(x::Observable{T}) where {T <: GeometryBasics.Mesh} = gl_promote(T)(x) +gl_convert(x::T) where {T<:Number} = gl_promote(T)(x) +gl_convert(x::T) where {T<:Colorant} = gl_promote(T)(x) +gl_convert(x::T) where {T<:AbstractMesh} = gl_convert(x) +gl_convert(x::T) where {T<:GeometryBasics.Mesh} = gl_promote(T)(x) +gl_convert(x::Observable{T}) where {T<:GeometryBasics.Mesh} = gl_promote(T)(x) gl_convert(s::Vector{Matrix{T}}) where {T<:Colorant} = Texture(s) gl_convert(s::Nothing) = s - isa_gl_struct(x::AbstractArray) = false isa_gl_struct(x::NATIVE_TYPES) = false isa_gl_struct(x::Colorant) = false -function isa_gl_struct(x::T) where T +function isa_gl_struct(x::T) where {T} !isconcretetype(T) && return false if T <: Tuple return false end fnames = fieldnames(T) - !isempty(fnames) && all(name -> isconcretetype(fieldtype(T, name)) && isbits(getfield(x, name)), fnames) + return !isempty(fnames) && + all(name -> isconcretetype(fieldtype(T, name)) && isbits(getfield(x, name)), fnames) end -function gl_convert_struct(x::T, uniform_name::Symbol) where T +function gl_convert_struct(x::T, uniform_name::Symbol) where {T} if isa_gl_struct(x) - return Dict{Symbol, Any}(map(fieldnames(x)) do name - (Symbol("$uniform_name.$name") => gl_convert(getfield(x, name))) + return Dict{Symbol,Any}(map(fieldnames(x)) do name + return (Symbol("$uniform_name.$name") => gl_convert(getfield(x, name))) end) else - error("can't convert $x to a OpenGL type. Make sure all fields are of a concrete type and isbits(FieldType)-->true") + error( + "can't convert $x to a OpenGL type. Make sure all fields are of a concrete type and isbits(FieldType)-->true", + ) end end - # native types don't need convert! -gl_convert(a::T) where {T <: NATIVE_TYPES} = a -gl_convert(s::Observable{T}) where {T <: NATIVE_TYPES} = s -gl_convert(s::Observable{T}) where T = const_lift(gl_convert, s) -gl_convert(x::StaticVector{N, T}) where {N, T} = map(gl_promote(T), x) -gl_convert(x::Mat{N, M, T}) where {N, M, T} = map(gl_promote(T), x) -gl_convert(a::AbstractVector{<: AbstractFace}) = indexbuffer(s) -gl_convert(t::Type{T}, a::T; kw_args...) where T <: NATIVE_TYPES = a -gl_convert(::Type{<: GPUArray}, a::StaticVector) = gl_convert(a) - -function gl_convert(T::Type{<: GPUArray}, a::AbstractArray{X, N}; kw_args...) where {X, N} - T(convert(AbstractArray{gl_promote(X), N}, a); kw_args...) +gl_convert(a::T) where {T<:NATIVE_TYPES} = a +gl_convert(s::Observable{T}) where {T<:NATIVE_TYPES} = s +gl_convert(s::Observable{T}) where {T} = const_lift(gl_convert, s) +gl_convert(x::StaticVector{N,T}) where {N,T} = map(gl_promote(T), x) +gl_convert(x::Mat{N,M,T}) where {N,M,T} = map(gl_promote(T), x) +gl_convert(a::AbstractVector{<:AbstractFace}) = indexbuffer(s) +gl_convert(t::Type{T}, a::T; kw_args...) where {T<:NATIVE_TYPES} = a +gl_convert(::Type{<:GPUArray}, a::StaticVector) = gl_convert(a) + +function gl_convert(T::Type{<:GPUArray}, a::AbstractArray{X,N}; kw_args...) where {X,N} + return T(convert(AbstractArray{gl_promote(X),N}, a); kw_args...) end -gl_convert(::Type{<: GLBuffer}, x::GLBuffer; kw_args...) = x +gl_convert(::Type{<:GLBuffer}, x::GLBuffer; kw_args...) = x gl_convert(::Type{Texture}, x::Texture) = x -gl_convert(::Type{<: GPUArray}, x::GPUArray) = x +gl_convert(::Type{<:GPUArray}, x::GPUArray) = x -function gl_convert(::Type{T}, a::Vector{Array{X, 2}}; kw_args...) where {T <: Texture, X} - T(a; kw_args...) -end -gl_convert(::Type{<: GPUArray}, a::Observable{<: StaticVector}) = gl_convert(a) +gl_convert(::Type{T}, a::Vector{Array{X,2}}; kw_args...) where {T<:Texture,X} = T(a; kw_args...) +gl_convert(::Type{<:GPUArray}, a::Observable{<:StaticVector}) = gl_convert(a) -function gl_convert(::Type{T}, a::Observable{<: AbstractArray{X, N}}; kw_args...) where {T <: GPUArray, X, N} +function gl_convert(::Type{T}, a::Observable{<:AbstractArray{X,N}}; kw_args...) where {T<:GPUArray,X,N} TGL = gl_promote(X) - s = (X == TGL) ? a : lift(x-> convert(Array{TGL, N}, x), a) - T(s; kw_args...) + s = (X == TGL) ? a : lift(x -> convert(Array{TGL,N}, x), a) + return T(s; kw_args...) end -lift_convert(a::AbstractArray, T, N) = lift(x -> convert(Array{T, N}, x), a) +lift_convert(a::AbstractArray, T, N) = lift(x -> convert(Array{T,N}, x), a) function lift_convert(a::ShaderAbstractions.Sampler, T, N) - ShaderAbstractions.Sampler( - lift(x -> convert(Array{T, N}, x.data), a), - minfilter = a[].minfilter, magfilter = a[].magfilter, - x_repeat = a[].repeat[1], - y_repeat = a[].repeat[min(2, N)], - z_repeat = a[].repeat[min(3, N)], - anisotropic = a[].anisotropic, swizzle_mask = a[].swizzle_mask + return ShaderAbstractions.Sampler( + lift(x -> convert(Array{T,N}, x.data), a), + minfilter=a[].minfilter, + magfilter=a[].magfilter, + x_repeat=a[].repeat[1], + y_repeat=a[].repeat[min(2, N)], + z_repeat=a[].repeat[min(3, N)], + anisotropic=a[].anisotropic, + swizzle_mask=a[].swizzle_mask, ) end diff --git a/GLMakie/src/GLAbstraction/GLUtils.jl b/GLMakie/src/GLAbstraction/GLUtils.jl index ff6f2ade728..bd32b64b954 100644 --- a/GLMakie/src/GLAbstraction/GLUtils.jl +++ b/GLMakie/src/GLAbstraction/GLUtils.jl @@ -1,26 +1,26 @@ function print_with_lines(out::IO, text::AbstractString) io = IOBuffer() - for (i,line) in enumerate(split(text, "\n")) + for (i, line) in enumerate(split(text, "\n")) println(io, @sprintf("%-4d: %s", i, line)) end - write(out, take!(io)) + return write(out, take!(io)) end print_with_lines(text::AbstractString) = print_with_lines(stdout, text) - """ Needed to match the lazy gl_convert exceptions. `Target`: targeted OpenGL type `x`: the variable that gets matched """ -matches_target(::Type{Target}, x::T) where {Target, T} = applicable(gl_convert, Target, x) || T <: Target # it can be either converted to Target, or it's already the target -matches_target(::Type{Target}, x::Observable{T}) where {Target, T} = applicable(gl_convert, Target, x) || T <: Target +matches_target(::Type{Target}, x::T) where {Target,T} = applicable(gl_convert, Target, x) || T <: Target # it can be either converted to Target, or it's already the target +function matches_target(::Type{Target}, x::Observable{T}) where {Target,T} + return applicable(gl_convert, Target, x) || T <: Target +end matches_target(::Function, x) = true matches_target(::Function, x::Nothing) = false signal_convert(T1, y::T2) where {T2<:Observable} = lift(convert, Observable(T1), y) - """ Takes a dict and inserts defaults, if not already available. The variables are made accessible in local scope, so things like this are possible: @@ -34,24 +34,29 @@ gen_defaults! dict begin end """ macro gen_defaults!(dict, args) - args.head == :block || error("second argument needs to be a block of form - begin - a = 55 - b = a * 2 # variables, like a, will get made visible in local scope - c::JuliaType = X # c needs to be of type JuliaType. c will be made available with it's original type and then converted to JuliaType when inserted into data - d = x => GLType # OpenGL convert target. Get's only applied if x is convertible to GLType. Will only be converted when passed to RenderObject - end") + args.head == :block || error( + "second argument needs to be a block of form +begin + a = 55 + b = a * 2 # variables, like a, will get made visible in local scope + c::JuliaType = X # c needs to be of type JuliaType. c will be made available with it's original type and then converted to JuliaType when inserted into data + d = x => GLType # OpenGL convert target. Get's only applied if x is convertible to GLType. Will only be converted when passed to RenderObject +end", + ) tuple_list = args.args dictsym = gensym() return_expression = Expr(:block) push!(return_expression.args, :($dictsym = $dict)) # dict could also be an expression, so we need to asign it to a variable at the beginning - push!(return_expression.args, :(gl_convert_targets = get!($dictsym, :gl_convert_targets, Dict{Symbol, Any}()))) # exceptions for glconvert. - push!(return_expression.args, :(doc_strings = get!($dictsym, :doc_string, Dict{Symbol, Any}()))) # exceptions for glconvert. + push!( + return_expression.args, + :(gl_convert_targets = get!($dictsym, :gl_convert_targets, Dict{Symbol,Any}())), + ) # exceptions for glconvert. + push!(return_expression.args, :(doc_strings = get!($dictsym, :doc_string, Dict{Symbol,Any}()))) # exceptions for glconvert. # @gen_defaults can be used multiple times, so we need to reuse gl_convert_targets if already in here for (i, elem) in enumerate(tuple_list) opengl_convert_target = :() # is optional, so first is an empty expression - convert_target = :() # is optional, so first is an empty expression - doc_strings = :() + convert_target = :() # is optional, so first is an empty expression + doc_strings = :() if Meta.isexpr(elem, :(=)) key_name, value_expr = elem.args if isa(key_name, Expr) && key_name.head == :(::) # we need to convert to a julia type @@ -97,11 +102,11 @@ macro gen_defaults!(dict, args) end #push!(return_expression.args, :($dictsym[:gl_convert_targets] = gl_convert_targets)) #just pass the targets via the dict push!(return_expression.args, :($dictsym)) #return dict - esc(return_expression) + return esc(return_expression) end export @gen_defaults! makesignal(@nospecialize(v)) = convert(Observable, v) -@inline const_lift(f::Union{DataType, Type, Function}, inputs...) = lift(f, map(makesignal, inputs)...) +@inline const_lift(f::Union{DataType,Type,Function}, inputs...) = lift(f, map(makesignal, inputs)...) export const_lift diff --git a/GLMakie/src/GLMakie.jl b/GLMakie/src/GLMakie.jl index 91a2b127204..61ef5b5b6d7 100644 --- a/GLMakie/src/GLMakie.jl +++ b/GLMakie/src/GLMakie.jl @@ -50,9 +50,7 @@ gl_texture_atlas() = Makie.get_texture_atlas(2048, 64) # don't put this into try catch, to not mess with normal errors include("gl_backend.jl") -function __init__() - activate!() -end +__init__() = activate!() Base.@deprecate set_window_config!(; screen_config...) GLMakie.activate!(; screen_config...) diff --git a/GLMakie/src/display.jl b/GLMakie/src/display.jl index c8d0aef1f72..ed72f2a20cc 100644 --- a/GLMakie/src/display.jl +++ b/GLMakie/src/display.jl @@ -10,4 +10,4 @@ function Base.display(screen::Screen, scene::Scene; connect=true) return screen end -Makie.backend_showable(::Type{Screen}, ::Union{MIME"image/jpeg", MIME"image/png"}) = true +Makie.backend_showable(::Type{Screen}, ::Union{MIME"image/jpeg",MIME"image/png"}) = true diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index dc438ca4796..a3b4cef2c6c 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -4,11 +4,16 @@ using Makie: convert_arguments Makie.el32convert(x::GLAbstraction.Texture) = x Makie.convert_attribute(s::ShaderAbstractions.Sampler{RGBAf}, k::key"color") = s -function Makie.convert_attribute(s::ShaderAbstractions.Sampler{T, N}, k::key"color") where {T, N} - ShaderAbstractions.Sampler( - el32convert(s.data), minfilter = s.minfilter, magfilter = s.magfilter, - x_repeat = s.repeat[1], y_repeat = s.repeat[min(2, N)], z_repeat = s.repeat[min(3, N)], - anisotropic = s.anisotropic, color_swizzel = s.color_swizzel +function Makie.convert_attribute(s::ShaderAbstractions.Sampler{T,N}, k::key"color") where {T,N} + return ShaderAbstractions.Sampler( + el32convert(s.data), + minfilter=s.minfilter, + magfilter=s.magfilter, + x_repeat=s.repeat[1], + y_repeat=s.repeat[min(2, N)], + z_repeat=s.repeat[min(3, N)], + anisotropic=s.anisotropic, + color_swizzel=s.color_swizzel, ) end @@ -44,7 +49,7 @@ function to_glvisualize_key(k) return k end -function connect_camera!(gl_attributes, cam, space = gl_attributes[:space]) +function connect_camera!(gl_attributes, cam, space=gl_attributes[:space]) for key in (:pixel_space, :resolution, :eyeposition) # Overwrite these, user defined attributes shouldn't use those! gl_attributes[key] = copy(getfield(cam, key)) @@ -69,7 +74,7 @@ function connect_camera!(gl_attributes, cam, space = gl_attributes[:space]) get!(gl_attributes, :projectionview) do return lift(cam.projectionview, cam.pixel_space, space) do _, _, space - Makie.space_to_clip(cam, space, true) + return Makie.space_to_clip(cam, space, true) end end @@ -83,18 +88,29 @@ function cached_robj!(robj_func, screen, scene, x::AbstractPlot) pollevents(screen) robj = get!(screen.cache, objectid(x)) do filtered = filter(x.attributes) do (k, v) - !in(k, ( - :transformation, :tickranges, :ticklabels, :raw, :SSAO, - :lightposition, :material, - :inspector_label, :inspector_hover, :inspector_clear, :inspectable - )) + return !in( + k, + ( + :transformation, + :tickranges, + :ticklabels, + :raw, + :SSAO, + :lightposition, + :material, + :inspector_label, + :inspector_hover, + :inspector_clear, + :inspectable, + ), + ) end - gl_attributes = Dict{Symbol, Any}(map(filtered) do key_value + gl_attributes = Dict{Symbol,Any}(map(filtered) do key_value key, value = key_value gl_key = to_glvisualize_key(key) gl_value = lift_convert(key, value, x) - gl_key => gl_value + return gl_key => gl_value end) pointlight = Makie.get_point_light(scene) @@ -112,10 +128,10 @@ function cached_robj!(robj_func, screen, scene, x::AbstractPlot) !haskey(gl_attributes, :ssao) && (robj[:ssao] = Observable(false)) screen.cache2plot[robj.id] = x - robj + return robj end push!(screen, scene, robj) - robj + return robj end function Base.insert!(screen::Screen, scene::Scene, x::Combined) @@ -128,16 +144,15 @@ function Base.insert!(screen::Screen, scene::Scene, x::Combined) foreach(x.plots) do x # poll inside functions to make wait on compile less prominent pollevents(screen) - insert!(screen, scene, x) + return insert!(screen, scene, x) end end end -function remove_automatic!(attributes) +remove_automatic!(attributes) = filter!(attributes) do (k, v) - to_value(v) != automatic + return to_value(v) != automatic end -end index1D(x::SubArray) = parentindices(x)[1] @@ -151,22 +166,19 @@ function handle_view(array::SubArray, attributes) return A end -function handle_view(array::Observable{T}, attributes) where T <: SubArray +function handle_view(array::Observable{T}, attributes) where {T<:SubArray} A = lift(parent, array) indices = lift(index1D, array) attributes[:indices] = indices return A end -function lift_convert(key, value, plot) - return lift_convert_inner(value, Key{key}(), Key{Makie.plotkey(plot)}(), plot) -end +lift_convert(key, value, plot) = lift_convert_inner(value, Key{key}(), Key{Makie.plotkey(plot)}(), plot) -function lift_convert_inner(value, key, plot_key, plot) - return lift(value) do value +lift_convert_inner(value, key, plot_key, plot) = + lift(value) do value return convert_attribute(value, key, plot_key) end -end to_vec4(val::RGB) = RGBAf(val, 1.0) to_vec4(val::RGBA) = RGBAf(val) @@ -184,9 +196,9 @@ end pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) function handle_intensities!(attributes) - if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<: Number} + if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<:Number} c = pop!(attributes, :color) - attributes[:intensity] = lift(x-> convert(Vector{Float32}, x), c) + attributes[:intensity] = lift(x -> convert(Vector{Float32}, x), c) else delete!(attributes, :intensity) delete!(attributes, :color_map) @@ -194,7 +206,7 @@ function handle_intensities!(attributes) end end -function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatter, MeshScatter})) +function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatter,MeshScatter})) return cached_robj!(screen, scene, x) do gl_attributes # signals not supported for shading yet gl_attributes[:shading] = to_value(get(gl_attributes, :shading, true)) @@ -207,16 +219,17 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatte if isa(x, Scatter) mspace = get(gl_attributes, :markerspace, :pixel) cam = scene.camera - gl_attributes[:preprojection] = map(space, mspace, cam.projectionview, cam.resolution) do space, mspace, _, _ - return Makie.clip_to_space(cam, mspace) * Makie.space_to_clip(cam, space) - end + gl_attributes[:preprojection] = + map(space, mspace, cam.projectionview, cam.resolution) do space, mspace, _, _ + return Makie.clip_to_space(cam, mspace) * Makie.space_to_clip(cam, space) + end # fast pixel does its own setup if !(marker[] isa FastPixel) connect_camera!(gl_attributes, cam, mspace) - gl_attributes[:billboard] = map(rot-> isa(rot, Billboard), x.rotations) + gl_attributes[:billboard] = map(rot -> isa(rot, Billboard), x.rotations) atlas = gl_texture_atlas() isnothing(gl_attributes[:distancefield][]) && delete!(gl_attributes, :distancefield) - shape = lift(m-> Cint(Makie.marker_to_sdf_shape(m)), marker) + shape = lift(m -> Cint(Makie.marker_to_sdf_shape(m)), marker) gl_attributes[:shape] = shape get!(gl_attributes, :distancefield) do if shape[] === Cint(DISTANCEFIELD) @@ -230,7 +243,13 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatte get!(gl_attributes, :uv_offset_width) do return Makie.primitive_uv_offset_width(atlas, marker, font) end - scale, quad_offset = Makie.marker_attributes(atlas, marker, gl_attributes[:scale], font, gl_attributes[:quad_offset]) + scale, quad_offset = Makie.marker_attributes( + atlas, + marker, + gl_attributes[:scale], + font, + gl_attributes[:quad_offset], + ) gl_attributes[:scale] = scale gl_attributes[:quad_offset] = quad_offset end @@ -241,10 +260,10 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatte if marker[] isa FastPixel # connect camera connect_camera!(gl_attributes, cam, get(gl_attributes, :space, :data)) - filter!(gl_attributes) do (k, v,) - k in (:color_map, :color, :color_norm, :scale, :model, :projectionview, :visible) + filter!(gl_attributes) do (k, v) + return k in (:color_map, :color, :color_norm, :scale, :model, :projectionview, :visible) end - if !(gl_attributes[:color][] isa AbstractVector{<: Number}) + if !(gl_attributes[:color][] isa AbstractVector{<:Number}) delete!(gl_attributes, :color_norm) delete!(gl_attributes, :color_map) end @@ -263,7 +282,7 @@ end function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Lines)) return cached_robj!(screen, scene, x) do gl_attributes linestyle = pop!(gl_attributes, :linestyle) - data = Dict{Symbol, Any}(gl_attributes) + data = Dict{Symbol,Any}(gl_attributes) ls = to_value(linestyle) if isnothing(ls) data[:pattern] = ls @@ -283,7 +302,7 @@ end function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::LineSegments)) return cached_robj!(screen, scene, x) do gl_attributes linestyle = pop!(gl_attributes, :linestyle) - data = Dict{Symbol, Any}(gl_attributes) + data = Dict{Symbol,Any}(gl_attributes) ls = to_value(linestyle) if isnothing(ls) data[:pattern] = ls @@ -294,7 +313,7 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::LineSegments space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call positions = handle_view(x.converted[1], data) positions = apply_transform(transform_func_obs(x), positions, space) - if haskey(data, :color) && data[:color][] isa AbstractVector{<: Number} + if haskey(data, :color) && data[:color][] isa AbstractVector{<:Number} c = pop!(data, :color) data[:color] = el32convert(c) else @@ -307,13 +326,15 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::LineSegments end end -function draw_atomic(screen::Screen, scene::Scene, - x::Text{<:Tuple{<:Union{<:Makie.GlyphCollection, <:AbstractVector{<:Makie.GlyphCollection}}}}) - +function draw_atomic( + screen::Screen, + scene::Scene, + x::Text{<:Tuple{<:Union{<:Makie.GlyphCollection,<:AbstractVector{<:Makie.GlyphCollection}}}}, +) return cached_robj!(screen, scene, x) do gl_attributes glyphcollection = x[1] - transfunc = Makie.transform_func_obs(scene) + transfunc = Makie.transform_func_obs(scene) pos = gl_attributes[:position] space = get(gl_attributes, :space, Observable(:data)) # needs to happen before connect_camera! call markerspace = gl_attributes[:markerspace] @@ -322,35 +343,29 @@ function draw_atomic(screen::Screen, scene::Scene, # calculate quad metrics glyph_data = map(pos, glyphcollection, offset, transfunc, space) do pos, gc, offset, transfunc, space - Makie.text_quads(atlas, pos, to_value(gc), offset, transfunc, space) + return Makie.text_quads(atlas, pos, to_value(gc), offset, transfunc, space) end # unpack values from the one signal: positions, char_offset, quad_offset, uv_offset_width, scale = map((1, 2, 3, 4, 5)) do i - lift(getindex, glyph_data, i) + return lift(getindex, glyph_data, i) end - filter!(gl_attributes) do (k, v) # These are liftkeys without model - !(k in ( - :position, :space, :markerspace, :font, - :fontsize, :rotation, :justification - )) # space, + return !(k in (:position, :space, :markerspace, :font, :fontsize, :rotation, :justification)) # space, end gl_attributes[:color] = lift(glyphcollection) do gc if gc isa AbstractArray - reduce(vcat, (Makie.collect_vector(g.colors, length(g.glyphs)) for g in gc), - init = RGBAf[]) + reduce(vcat, (Makie.collect_vector(g.colors, length(g.glyphs)) for g in gc), init=RGBAf[]) else Makie.collect_vector(gc.colors, length(gc.glyphs)) end end gl_attributes[:stroke_color] = lift(glyphcollection) do gc if gc isa AbstractArray - reduce(vcat, (Makie.collect_vector(g.strokecolors, length(g.glyphs)) for g in gc), - init = RGBAf[]) + reduce(vcat, (Makie.collect_vector(g.strokecolors, length(g.glyphs)) for g in gc), init=RGBAf[]) else Makie.collect_vector(gc.strokecolors, length(gc.glyphs)) end @@ -358,8 +373,11 @@ function draw_atomic(screen::Screen, scene::Scene, gl_attributes[:rotation] = lift(glyphcollection) do gc if gc isa AbstractArray - reduce(vcat, (Makie.collect_vector(g.rotations, length(g.glyphs)) for g in gc), - init = Quaternionf[]) + reduce( + vcat, + (Makie.collect_vector(g.rotations, length(g.glyphs)) for g in gc), + init=Quaternionf[], + ) else Makie.collect_vector(gc.rotations, length(gc.glyphs)) end @@ -374,9 +392,10 @@ function draw_atomic(screen::Screen, scene::Scene, gl_attributes[:visible] = x.visible cam = scene.camera # gl_attributes[:preprojection] = Observable(Mat4f(I)) - gl_attributes[:preprojection] = map(space, markerspace, cam.projectionview, cam.resolution) do s, ms, pv, res - Makie.clip_to_space(cam, ms) * Makie.space_to_clip(cam, s) - end + gl_attributes[:preprojection] = + map(space, markerspace, cam.projectionview, cam.resolution) do s, ms, pv, res + return Makie.clip_to_space(cam, ms) * Makie.space_to_clip(cam, s) + end connect_camera!(gl_attributes, cam, markerspace) return draw_scatter(screen, (DISTANCEFIELD, positions), gl_attributes) @@ -414,16 +433,16 @@ function draw_atomic(screen::Screen, scene::Scene, x::Heatmap) end xpos = map(first, xypos) ypos = map(last, xypos) - gl_attributes[:position_x] = Texture(xpos, minfilter = :nearest) - gl_attributes[:position_y] = Texture(ypos, minfilter = :nearest) + gl_attributes[:position_x] = Texture(xpos, minfilter=:nearest) + gl_attributes[:position_y] = Texture(ypos, minfilter=:nearest) # number of planes used to render the heatmap gl_attributes[:instances] = map(xpos, ypos) do x, y - (length(x)-1) * (length(y)-1) + return (length(x) - 1) * (length(y) - 1) end interp = to_value(pop!(gl_attributes, :interpolate)) interp = interp ? :linear : :nearest if !(to_value(mat) isa ShaderAbstractions.Sampler) - tex = Texture(el32convert(mat), minfilter = interp) + tex = Texture(el32convert(mat), minfilter=interp) else tex = to_value(mat) end @@ -441,11 +460,11 @@ function draw_atomic(screen::Screen, scene::Scene, x::Image) r = to_range(x, y) x, y = minimum(r[1]), minimum(r[2]) xmax, ymax = maximum(r[1]), maximum(r[2]) - rect = Rect2f(x, y, xmax - x, ymax - y) + rect = Rect2f(x, y, xmax - x, ymax - y) points = decompose(Point2f, rect) faces = decompose(GLTriangleFace, rect) uv = map(decompose_uv(rect)) do uv - return 1f0 .- Vec2f(uv[2], uv[1]) + return 1.0f0 .- Vec2f(uv[2], uv[1]) end return GeometryBasics.Mesh(meta(points; uv=uv), faces) end @@ -479,13 +498,13 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, space=:data) gl_attributes[:image] = ShaderAbstractions.Sampler(img, x_repeat=:repeat, minfilter=:nearest) get!(gl_attributes, :fetch_pixel, true) elseif to_value(color) isa AbstractMatrix{<:Colorant} - gl_attributes[:image] = Texture(const_lift(el32convert, color), minfilter = interp) + gl_attributes[:image] = Texture(const_lift(el32convert, color), minfilter=interp) delete!(gl_attributes, :color_map) delete!(gl_attributes, :color_norm) - elseif to_value(color) isa AbstractMatrix{<: Number} - gl_attributes[:image] = Texture(const_lift(el32convert, color), minfilter = interp) + elseif to_value(color) isa AbstractMatrix{<:Number} + gl_attributes[:image] = Texture(const_lift(el32convert, color), minfilter=interp) gl_attributes[:color] = nothing - elseif to_value(color) isa AbstractVector{<: Union{Number, Colorant}} + elseif to_value(color) isa AbstractVector{<:Union{Number,Colorant}} gl_attributes[:vertex_color] = lift(el32convert, color) else error("Unsupported color type: $(typeof(to_value(color)))") @@ -514,7 +533,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) img = nothing # signals not supported for shading yet # We automatically insert x[3] into the color channel, so if it's equal we don't need to do anything - if isa(to_value(color), AbstractMatrix{<: Number}) && to_value(color) !== to_value(x[3]) + if isa(to_value(color), AbstractMatrix{<:Number}) && to_value(color) !== to_value(x[3]) img = el32convert(color) elseif to_value(color) isa Makie.AbstractPattern pattern_img = lift(x -> el32convert(Makie.to_image(x)), color) @@ -523,7 +542,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) gl_attributes[:color_map] = nothing gl_attributes[:color] = nothing gl_attributes[:color_norm] = nothing - elseif isa(to_value(color), AbstractMatrix{<: Colorant}) + elseif isa(to_value(color), AbstractMatrix{<:Colorant}) img = color gl_attributes[:color_map] = nothing gl_attributes[:color] = nothing @@ -539,7 +558,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) @assert to_value(x[3]) isa AbstractMatrix types = map(v -> typeof(to_value(v)), x[1:2]) - if all(T -> T <: Union{AbstractMatrix, AbstractVector}, types) + if all(T -> T <: Union{AbstractMatrix,AbstractVector}, types) t = Makie.transform_func_obs(scene) mat = x[3] xypos = map(t, x[1], x[2], space) do t, x, y, space @@ -560,7 +579,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) xpos = map(first, xypos) ypos = map(last, xypos) args = map((xpos, ypos, mat)) do arg - Texture(map(x-> convert(Array, el32convert(x)), arg); minfilter=:linear) + return Texture(map(x -> convert(Array, el32convert(x)), arg); minfilter=:linear) end if isnothing(img) gl_attributes[:image] = args[3] @@ -586,12 +605,7 @@ function draw_atomic(screen::Screen, scene::Scene, vol::Volume) mi = minimum.(xyz) maxi = maximum.(xyz) w = maxi .- mi - m2 = Mat4f( - w[1], 0, 0, 0, - 0, w[2], 0, 0, - 0, 0, w[3], 0, - mi[1], mi[2], mi[3], 1 - ) + m2 = Mat4f(w[1], 0, 0, 0, 0, w[2], 0, 0, 0, 0, w[3], 0, mi[1], mi[2], mi[3], 1) return convert(Mat4f, m) * m2 end connect_camera!(gl_attributes, scene.camera) diff --git a/GLMakie/src/events.jl b/GLMakie/src/events.jl index fced12ae9af..cbc38d398a8 100644 --- a/GLMakie/src/events.jl +++ b/GLMakie/src/events.jl @@ -22,29 +22,25 @@ Makie.window_open(scene::Scene, screen) = window_open(scene, to_native(screen)) function Makie.window_open(scene::Scene, window::GLFW.Window) event = scene.events.window_open - function windowclose(win) - @print_error begin - event[] = false - end + windowclose(win) = @print_error begin + event[] = false end disconnect!(window, window_open) event[] = isopen(window) - GLFW.SetWindowCloseCallback(window, windowclose) + return GLFW.SetWindowCloseCallback(window, windowclose) end -function Makie.disconnect!(window::GLFW.Window, ::typeof(window_open)) - GLFW.SetWindowCloseCallback(window, nothing) -end +Makie.disconnect!(window::GLFW.Window, ::typeof(window_open)) = GLFW.SetWindowCloseCallback(window, nothing) function window_position(window::GLFW.Window) xy = GLFW.GetWindowPos(window) - (xy.x, xy.y) + return (xy.x, xy.y) end struct WindowAreaUpdater window::GLFW.Window dpi::Observable{Float64} - area::Observable{GeometryBasics.HyperRectangle{2, Int64}} + area::Observable{GeometryBasics.HyperRectangle{2,Int64}} end function (x::WindowAreaUpdater)(::Nothing) @@ -70,9 +66,7 @@ end function Makie.window_area(scene::Scene, screen::Screen) disconnect!(screen, window_area) - updater = WindowAreaUpdater( - to_native(screen), scene.events.window_dpi, scene.events.window_area - ) + updater = WindowAreaUpdater(to_native(screen), scene.events.window_dpi, scene.events.window_area) on(updater, screen.render_tick) return @@ -83,11 +77,12 @@ function Makie.disconnect!(screen::Screen, ::typeof(window_area)) return end function Makie.disconnect!(::GLFW.Window, ::typeof(window_area)) - error("disconnect!(::Screen, ::window_area) should be called instead of disconnect!(::GLFW.Window, ::window_area)!") + error( + "disconnect!(::Screen, ::window_area) should be called instead of disconnect!(::GLFW.Window, ::window_area)!", + ) return end - """ Registers a callback for the mouse buttons + modifiers returns `Observable{NTuple{4, Int}}` @@ -102,11 +97,9 @@ function Makie.mouse_buttons(scene::Scene, window::GLFW.Window) end end disconnect!(window, mouse_buttons) - GLFW.SetMouseButtonCallback(window, mousebuttons) -end -function Makie.disconnect!(window::GLFW.Window, ::typeof(mouse_buttons)) - GLFW.SetMouseButtonCallback(window, nothing) + return GLFW.SetMouseButtonCallback(window, mousebuttons) end +Makie.disconnect!(window::GLFW.Window, ::typeof(mouse_buttons)) = GLFW.SetMouseButtonCallback(window, nothing) Makie.keyboard_buttons(scene::Scene, screen) = keyboard_buttons(scene, to_native(screen)) function Makie.keyboard_buttons(scene::Scene, window::GLFW.Window) event = scene.events.keyboardbutton @@ -116,12 +109,10 @@ function Makie.keyboard_buttons(scene::Scene, window::GLFW.Window) end end disconnect!(window, keyboard_buttons) - GLFW.SetKeyCallback(window, keyoardbuttons) + return GLFW.SetKeyCallback(window, keyoardbuttons) end -function Makie.disconnect!(window::GLFW.Window, ::typeof(keyboard_buttons)) - GLFW.SetKeyCallback(window, nothing) -end +Makie.disconnect!(window::GLFW.Window, ::typeof(keyboard_buttons)) = GLFW.SetKeyCallback(window, nothing) """ Registers a callback for drag and drop of files. @@ -131,18 +122,14 @@ returns `Observable{Vector{String}}`, which are absolute file paths Makie.dropped_files(scene::Scene, screen) = dropped_files(scene, to_native(screen)) function Makie.dropped_files(scene::Scene, window::GLFW.Window) event = scene.events.dropped_files - function droppedfiles(window, files) - @print_error begin - event[] = String.(files) - end + droppedfiles(window, files) = @print_error begin + event[] = String.(files) end disconnect!(window, dropped_files) event[] = String[] - GLFW.SetDropCallback(window, droppedfiles) -end -function Makie.disconnect!(window::GLFW.Window, ::typeof(dropped_files)) - GLFW.SetDropCallback(window, nothing) + return GLFW.SetDropCallback(window, droppedfiles) end +Makie.disconnect!(window::GLFW.Window, ::typeof(dropped_files)) = GLFW.SetDropCallback(window, nothing) """ Registers a callback for keyboard unicode input. @@ -153,24 +140,20 @@ containing the pressed char. Is empty, if no key is pressed. Makie.unicode_input(scene::Scene, screen) = unicode_input(scene, to_native(screen)) function Makie.unicode_input(scene::Scene, window::GLFW.Window) event = scene.events.unicode_input - function unicodeinput(window, c::Char) - @print_error begin - event[] = c - end + unicodeinput(window, c::Char) = @print_error begin + event[] = c end disconnect!(window, unicode_input) # x = Char[]; sizehint!(x, 1) # event[] = x - GLFW.SetCharCallback(window, unicodeinput) -end -function Makie.disconnect!(window::GLFW.Window, ::typeof(unicode_input)) - GLFW.SetCharCallback(window, nothing) + return GLFW.SetCharCallback(window, unicodeinput) end +Makie.disconnect!(window::GLFW.Window, ::typeof(unicode_input)) = GLFW.SetCharCallback(window, nothing) # TODO memoise? Or to bug ridden for the small performance gain? function retina_scaling_factor(w, fb) (w[1] == 0 || w[2] == 0) && return (1.0, 1.0) - fb ./ w + return fb ./ w end # TODO both of these methods are slow! @@ -178,26 +161,26 @@ end # This is too slow for events that may happen 100x per frame function framebuffer_size(window::GLFW.Window) wh = GLFW.GetFramebufferSize(window) - (wh.width, wh.height) + return (wh.width, wh.height) end function window_size(window::GLFW.Window) wh = GLFW.GetWindowSize(window) - (wh.width, wh.height) + return (wh.width, wh.height) end function retina_scaling_factor(window::GLFW.Window) w, fb = window_size(window), framebuffer_size(window) - retina_scaling_factor(w, fb) + return retina_scaling_factor(w, fb) end function correct_mouse(window::GLFW.Window, w, h) ws, fb = window_size(window), framebuffer_size(window) s = retina_scaling_factor(ws, fb) - (w * s[1], fb[2] - (h * s[2])) + return (w * s[1], fb[2] - (h * s[2])) end struct MousePositionUpdater window::GLFW.Window - mouseposition::Observable{Tuple{Float64, Float64}} + mouseposition::Observable{Tuple{Float64,Float64}} hasfocus::Observable{Bool} end @@ -220,9 +203,7 @@ which is not in scene coordinates, with the upper left window corner being 0 """ function Makie.mouse_position(scene::Scene, screen::Screen) disconnect!(screen, mouse_position) - updater = MousePositionUpdater( - to_native(screen), scene.events.mouseposition, scene.events.hasfocus - ) + updater = MousePositionUpdater(to_native(screen), scene.events.mouseposition, scene.events.hasfocus) on(updater, screen.render_tick) return end @@ -231,8 +212,10 @@ function Makie.disconnect!(screen::Screen, ::typeof(mouse_position)) return end function Makie.disconnect!(window::GLFW.Window, ::typeof(mouse_position)) - error("disconnect!(::Screen, ::mouse_position) should be called instead of disconnect!(::GLFW.Window, ::mouseposition)!") - nothing + error( + "disconnect!(::Screen, ::mouse_position) should be called instead of disconnect!(::GLFW.Window, ::mouseposition)!", + ) + return nothing end """ @@ -244,17 +227,13 @@ which is an x and y offset. Makie.scroll(scene::Scene, screen) = scroll(scene, to_native(screen)) function Makie.scroll(scene::Scene, window::GLFW.Window) event = scene.events.scroll - function scrollcb(window, w::Cdouble, h::Cdouble) - @print_error begin - event[] = (w, h) - end + scrollcb(window, w::Cdouble, h::Cdouble) = @print_error begin + event[] = (w, h) end disconnect!(window, scroll) - GLFW.SetScrollCallback(window, scrollcb) -end -function Makie.disconnect!(window::GLFW.Window, ::typeof(scroll)) - GLFW.SetScrollCallback(window, nothing) + return GLFW.SetScrollCallback(window, scrollcb) end +Makie.disconnect!(window::GLFW.Window, ::typeof(scroll)) = GLFW.SetScrollCallback(window, nothing) """ Registers a callback for the focus of a window. @@ -265,19 +244,15 @@ which is true whenever the window has focus. Makie.hasfocus(scene::Scene, screen) = hasfocus(scene, to_native(screen)) function Makie.hasfocus(scene::Scene, window::GLFW.Window) event = scene.events.hasfocus - function hasfocuscb(window, focus::Bool) - @print_error begin - event[] = focus - end + hasfocuscb(window, focus::Bool) = @print_error begin + event[] = focus end disconnect!(window, hasfocus) GLFW.SetWindowFocusCallback(window, hasfocuscb) event[] = GLFW.GetWindowAttrib(window, GLFW.FOCUSED) - nothing -end -function Makie.disconnect!(window::GLFW.Window, ::typeof(hasfocus)) - GLFW.SetWindowFocusCallback(window, nothing) + return nothing end +Makie.disconnect!(window::GLFW.Window, ::typeof(hasfocus)) = GLFW.SetWindowFocusCallback(window, nothing) """ Registers a callback for if the mouse has entered the window. @@ -288,15 +263,13 @@ which is true whenever the cursor enters the window. Makie.entered_window(scene::Scene, screen) = entered_window(scene, to_native(screen)) function Makie.entered_window(scene::Scene, window::GLFW.Window) event = scene.events.entered_window - function enteredwindowcb(window, entered::Bool) - @print_error begin - event[] = entered - end + enteredwindowcb(window, entered::Bool) = @print_error begin + event[] = entered end disconnect!(window, entered_window) - GLFW.SetCursorEnterCallback(window, enteredwindowcb) + return GLFW.SetCursorEnterCallback(window, enteredwindowcb) end function Makie.disconnect!(window::GLFW.Window, ::typeof(entered_window)) - GLFW.SetCursorEnterCallback(window, nothing) + return GLFW.SetCursorEnterCallback(window, nothing) end diff --git a/GLMakie/src/gl_backend.jl b/GLMakie/src/gl_backend.jl index 1fb7a003f02..434496d58c6 100644 --- a/GLMakie/src/gl_backend.jl +++ b/GLMakie/src/gl_backend.jl @@ -14,7 +14,7 @@ include("GLAbstraction/GLAbstraction.jl") using .GLAbstraction -const atlas_texture_cache = Dict{Any, Tuple{Texture{Float16, 2}, Function}}() +const atlas_texture_cache = Dict{Any,Tuple{Texture{Float16,2},Function}}() function get_texture!(atlas::Makie.TextureAtlas) current_ctx = GLAbstraction.current_context() @@ -34,15 +34,15 @@ function get_texture!(atlas::Makie.TextureAtlas) tex, func = get!(atlas_texture_cache, (pointer(atlas.data), current_ctx)) do tex = Texture( - atlas.data, - minfilter = :linear, - magfilter = :linear, - # TODO: Consider alternatives to using the builtin anisotropic - # samplers for signed distance fields; the anisotropic - # filtering should happen *after* the SDF thresholding, but - # with the builtin sampler it happens before. - anisotropic = 16f0, - mipmap = true + atlas.data, + minfilter=:linear, + magfilter=:linear, + # TODO: Consider alternatives to using the builtin anisotropic + # samplers for signed distance fields; the anisotropic + # filtering should happen *after* the SDF thresholding, but + # with the builtin sampler it happens before. + anisotropic=16.0f0, + mipmap=true, ) # update the texture, whenever a new font is added to the atlas function callback(distance_field, rectangle) diff --git a/GLMakie/src/glshaders/image_like.jl b/GLMakie/src/glshaders/image_like.jl index ec21243a53f..1dda7026136 100644 --- a/GLMakie/src/glshaders/image_like.jl +++ b/GLMakie/src/glshaders/image_like.jl @@ -8,31 +8,33 @@ VolumePrerender(a, b) = VolumePrerender(StandardPrerender(a, b)) function (x::VolumePrerender)() x.sp() glEnable(GL_CULL_FACE) - glCullFace(GL_FRONT) + return glCullFace(GL_FRONT) end vol_depth_init(enable) = enable ? "float depth = 100000.0;" : "" vol_depth_default(enable) = enable ? "gl_FragDepth = gl_FragCoord.z;" : "" -function vol_depth_main(enable) +vol_depth_main(enable) = if enable """ vec4 frag_coord = projectionview * model * vec4(pos, 1); depth = min(depth, frag_coord.z / frag_coord.w); """ - else "" end -end -function vol_depth_write(enable) + else + "" + end +vol_depth_write(enable) = if enable "gl_FragDepth = depth == 100000.0 ? gl_FragDepth : 0.5 * depth + 0.5;" - else "" end -end + else + "" + end @nospecialize """ A matrix of Intensities will result in a contourf kind of plot """ function draw_heatmap(screen, main, data::Dict) - primitive = triangle_mesh(Rect2(0f0,0f0,1f0,1f0)) + primitive = triangle_mesh(Rect2(0.0f0, 0.0f0, 1.0f0, 1.0f0)) to_opengl_mesh!(data, primitive) @gen_defaults! data begin intensity = main => Texture @@ -42,16 +44,18 @@ function draw_heatmap(screen, main, data::Dict) color_map = nothing => Texture color_norm = nothing stroke_width::Float32 = 0.0f0 - levels::Float32 = 0f0 - stroke_color = RGBA{Float32}(0,0,0,0) + levels::Float32 = 0.0f0 + stroke_color = RGBA{Float32}(0, 0, 0, 0) transparency = false shader = GLVisualizeShader( screen, - "fragment_output.frag", "heatmap.vert", "heatmap.frag", - view = Dict( + "fragment_output.frag", + "heatmap.vert", + "heatmap.frag", + view=Dict( "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) fxaa = false end @@ -70,22 +74,25 @@ function draw_volume(screen, main::VolumeTypes, data::Dict) color = color_map === nothing ? default(RGBA, s) : nothing algorithm = MaximumIntensityProjection - absorption = 1f0 + absorption = 1.0f0 isovalue = 0.5f0 isorange = 0.01f0 enable_depth = true transparency = false shader = GLVisualizeShader( screen, - "fragment_output.frag", "util.vert", "volume.vert", "volume.frag", - view = Dict( - "depth_init" => vol_depth_init(to_value(enable_depth)), - "depth_default" => vol_depth_default(to_value(enable_depth)), - "depth_main" => vol_depth_main(to_value(enable_depth)), + "fragment_output.frag", + "util.vert", + "volume.vert", + "volume.frag", + view=Dict( + "depth_init" => vol_depth_init(to_value(enable_depth)), + "depth_default" => vol_depth_default(to_value(enable_depth)), + "depth_main" => vol_depth_main(to_value(enable_depth)), "depth_write" => vol_depth_write(to_value(enable_depth)), "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) prerender = VolumePrerender(data[:transparency], data[:overdraw]) postrender = () -> glDisable(GL_CULL_FACE) diff --git a/GLMakie/src/glshaders/lines.jl b/GLMakie/src/glshaders/lines.jl index 323d21e3d01..7cd073cc041 100644 --- a/GLMakie/src/glshaders/lines.jl +++ b/GLMakie/src/glshaders/lines.jl @@ -1,27 +1,27 @@ function sumlengths(points) T = eltype(points[1]) result = zeros(T, length(points)) - for i=1:length(points) - i0 = max(i-1,1) + for i in 1:length(points) + i0 = max(i - 1, 1) p1, p2 = points[i0], points[i] if !(any(map(isnan, p1)) || any(map(isnan, p2))) - result[i] = result[i0] + norm(p1-p2) + result[i] = result[i0] + norm(p1 - p2) else result[i] = result[i0] end end - result + return result end intensity_convert(intensity, verts) = intensity -function intensity_convert(intensity::VecOrSignal{T}, verts) where T +function intensity_convert(intensity::VecOrSignal{T}, verts) where {T} if length(to_value(intensity)) == length(to_value(verts)) GLBuffer(intensity) else Texture(intensity) end end -function intensity_convert_tex(intensity::VecOrSignal{T}, verts) where T +function intensity_convert_tex(intensity::VecOrSignal{T}, verts) where {T} if length(to_value(intensity)) == length(to_value(verts)) TextureBuffer(intensity) else @@ -29,14 +29,14 @@ function intensity_convert_tex(intensity::VecOrSignal{T}, verts) where T end end #TODO NaNMath.min/max? -dist(a, b) = abs(a-b) +dist(a, b) = abs(a - b) mindist(x, a, b) = min(dist(a, x), dist(b, x)) function gappy(x, ps) n = length(ps) x <= first(ps) && return first(ps) - x - for j=1:(n-1) + for j in 1:(n - 1) p0 = ps[j] - p1 = ps[min(j+1, n)] + p1 = ps[min(j + 1, n)] if p0 <= x && p1 >= x return mindist(x, p0, p1) * (isodd(j) ? 1 : -1) end @@ -44,11 +44,11 @@ function gappy(x, ps) return last(ps) - x end function ticks(points, resolution) - Float16[gappy(x, points) for x = range(first(points), stop=last(points), length=resolution)] + return Float16[gappy(x, points) for x in range(first(points), stop=last(points), length=resolution)] end @nospecialize -function draw_lines(screen, position::Union{VectorTypes{T}, MatTypes{T}}, data::Dict) where T<:Point +function draw_lines(screen, position::Union{VectorTypes{T},MatTypes{T}}, data::Dict) where {T<:Point} p_vec = if isa(position, GPUArray) position else @@ -56,34 +56,38 @@ function draw_lines(screen, position::Union{VectorTypes{T}, MatTypes{T}}, data:: end @gen_defaults! data begin - total_length::Int32 = const_lift(x-> Int32(length(x)), position) - vertex = p_vec => GLBuffer - intensity = nothing - color_map = nothing => Texture - color_norm = nothing - color = (color_map == nothing ? default(RGBA, s) : nothing) => GLBuffer - thickness::Float32 = 2f0 - pattern = nothing - fxaa = false + total_length::Int32 = const_lift(x -> Int32(length(x)), position) + vertex = p_vec => GLBuffer + intensity = nothing + color_map = nothing => Texture + color_norm = nothing + color = (color_map == nothing ? default(RGBA, s) : nothing) => GLBuffer + thickness::Float32 = 2.0f0 + pattern = nothing + fxaa = false # Duplicate the vertex indices on the ends of the line, as our geometry # shader in `layout(lines_adjacency)` mode requires each rendered # segment to have neighbouring vertices. - indices = const_lift(p_vec) do p + indices = const_lift(p_vec) do p len0 = length(p) - 1 return isempty(p) ? Cuint[] : Cuint[0; 0:len0; len0] end => to_index_buffer transparency = false - shader = GLVisualizeShader( + shader = GLVisualizeShader( screen, - "fragment_output.frag", "util.vert", "lines.vert", "lines.geom", "lines.frag", - view = Dict( + "fragment_output.frag", + "util.vert", + "lines.vert", + "lines.geom", + "lines.frag", + view=Dict( "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) - gl_primitive = GL_LINE_STRIP_ADJACENCY - valid_vertex = const_lift(p_vec) do points - map(p-> Float32(all(isfinite, p)), points) + gl_primitive = GL_LINE_STRIP_ADJACENCY + valid_vertex = const_lift(p_vec) do points + return map(p -> Float32(all(isfinite, p)), points) end => GLBuffer end if pattern !== nothing @@ -91,12 +95,12 @@ function draw_lines(screen, position::Union{VectorTypes{T}, MatTypes{T}}, data:: if !isa(pattern, Vector) error("Pattern needs to be a Vector of floats. Found: $(typeof(pattern))") end - tex = GLAbstraction.Texture(ticks(pattern, 100), x_repeat = :repeat) + tex = GLAbstraction.Texture(ticks(pattern, 100), x_repeat=:repeat) data[:pattern] = tex end @gen_defaults! data begin pattern_length = Float32(last(pattern)) - lastlen = const_lift(sumlengths, p_vec) => GLBuffer + lastlen = const_lift(sumlengths, p_vec) => GLBuffer maxlength = const_lift(last, lastlen) end end @@ -104,26 +108,30 @@ function draw_lines(screen, position::Union{VectorTypes{T}, MatTypes{T}}, data:: return assemble_shader(data) end -function draw_linesegments(screen, positions::VectorTypes{T}, data::Dict) where T <: Point +function draw_linesegments(screen, positions::VectorTypes{T}, data::Dict) where {T<:Point} @gen_defaults! data begin - vertex = positions => GLBuffer - color = default(RGBA, s, 1) => GLBuffer - color_map = nothing => Texture - color_norm = nothing - thickness = 2f0 => GLBuffer - shape = RECTANGLE - pattern = nothing - fxaa = false - indices = const_lift(length, positions) => to_index_buffer + vertex = positions => GLBuffer + color = default(RGBA, s, 1) => GLBuffer + color_map = nothing => Texture + color_norm = nothing + thickness = 2.0f0 => GLBuffer + shape = RECTANGLE + pattern = nothing + fxaa = false + indices = const_lift(length, positions) => to_index_buffer # TODO update boundingbox transparency = false - shader = GLVisualizeShader( + shader = GLVisualizeShader( screen, - "fragment_output.frag", "util.vert", "line_segment.vert", "line_segment.geom", "lines.frag", - view = Dict( + "fragment_output.frag", + "util.vert", + "line_segment.vert", + "line_segment.geom", + "lines.frag", + view=Dict( "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) gl_primitive = GL_LINES end @@ -131,7 +139,7 @@ function draw_linesegments(screen, positions::VectorTypes{T}, data::Dict) where if !isa(pattern, Vector) error("Pattern needs to be a Vector of floats") end - tex = GLAbstraction.Texture(ticks(pattern, 100), x_repeat = :repeat) + tex = GLAbstraction.Texture(ticks(pattern, 100), x_repeat=:repeat) data[:pattern] = tex data[:pattern_length] = Float32(last(pattern)) end diff --git a/GLMakie/src/glshaders/mesh.jl b/GLMakie/src/glshaders/mesh.jl index 1cacd125aea..8f1a3ead025 100644 --- a/GLMakie/src/glshaders/mesh.jl +++ b/GLMakie/src/glshaders/mesh.jl @@ -1,18 +1,18 @@ -function to_opengl_mesh!(result, mesh_obs::TOrSignal{<: GeometryBasics.Mesh}) +function to_opengl_mesh!(result, mesh_obs::TOrSignal{<:GeometryBasics.Mesh}) m_attr = map(convert(Observable, mesh_obs)) do m return (m, GeometryBasics.attributes(m)) end - result[:faces] = indexbuffer(map(((m,_),)-> faces(m), m_attr)) - result[:vertices] = GLBuffer(map(((m,_),)-> decompose(Point, m), m_attr)) + result[:faces] = indexbuffer(map(((m, _),) -> faces(m), m_attr)) + result[:vertices] = GLBuffer(map(((m, _),) -> decompose(Point, m), m_attr)) attribs = m_attr[][2] - function to_buffer(name, target) + to_buffer(name, target) = if haskey(attribs, name) val = attribs[name] if mesh_obs isa Observable - val = map(((m, a),)-> a[name], m_attr) + val = map(((m, a),) -> a[name], m_attr) end if val[] isa AbstractVector result[target] = GLBuffer(map(metafree, val)) @@ -22,7 +22,6 @@ function to_opengl_mesh!(result, mesh_obs::TOrSignal{<: GeometryBasics.Mesh}) error("unsupported attribute: $(name)") end end - end to_buffer(:color, :vertex_color) to_buffer(:uv, :texturecoordinates) to_buffer(:uvw, :texturecoordinates) @@ -38,7 +37,7 @@ function draw_mesh(screen, @nospecialize(mesh), data::Dict) to_opengl_mesh!(data, mesh) @gen_defaults! data begin shading = true - backlight = 0f0 + backlight = 0.0f0 vertex_color = nothing => GLBuffer texturecoordinates = Vec2f(0) image = nothing => Texture @@ -51,12 +50,15 @@ function draw_mesh(screen, @nospecialize(mesh), data::Dict) interpolate_in_fragment_shader = true shader = GLVisualizeShader( screen, - "util.vert", "mesh.vert", "mesh.frag", "fragment_output.frag", - view = Dict( + "util.vert", + "mesh.vert", + "mesh.frag", + "fragment_output.frag", + view=Dict( "light_calc" => light_calc(shading), "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) end return assemble_shader(data) diff --git a/GLMakie/src/glshaders/particles.jl b/GLMakie/src/glshaders/particles.jl index 3ab7d85661f..226a4339caa 100644 --- a/GLMakie/src/glshaders/particles.jl +++ b/GLMakie/src/glshaders/particles.jl @@ -1,31 +1,21 @@ using Makie: RectanglePacker -function to_meshcolor(color::TOrSignal{Vector{T}}) where T <: Colorant - TextureBuffer(color) -end +to_meshcolor(color::TOrSignal{Vector{T}}) where {T<:Colorant} = TextureBuffer(color) -function to_meshcolor(color::TOrSignal{Matrix{T}}) where T <: Colorant - Texture(color) -end -function to_meshcolor(color) - color -end +to_meshcolor(color::TOrSignal{Matrix{T}}) where {T<:Colorant} = Texture(color) +to_meshcolor(color) = color vec2quaternion(rotation::StaticVector{4}) = rotation -function vec2quaternion(r::StaticVector{2}) - vec2quaternion(Vec3f(r[1], r[2], 0)) -end -function vec2quaternion(rotation::StaticVector{3}) - Makie.rotation_between(Vec3f(0, 0, 1), Vec3f(rotation)) -end +vec2quaternion(r::StaticVector{2}) = vec2quaternion(Vec3f(r[1], r[2], 0)) +vec2quaternion(rotation::StaticVector{3}) = Makie.rotation_between(Vec3f(0, 0, 1), Vec3f(rotation)) vec2quaternion(rotation::Vec4f) = rotation -vec2quaternion(rotation::VectorTypes) = const_lift(x-> vec2quaternion.(x), rotation) +vec2quaternion(rotation::VectorTypes) = const_lift(x -> vec2quaternion.(x), rotation) vec2quaternion(rotation::Observable) = lift(vec2quaternion, rotation) -vec2quaternion(rotation::Makie.Quaternion)= Vec4f(rotation.data) -vec2quaternion(rotation)= vec2quaternion(to_rotation(rotation)) -GLAbstraction.gl_convert(rotation::Makie.Quaternion)= Vec4f(rotation.data) +vec2quaternion(rotation::Makie.Quaternion) = Vec4f(rotation.data) +vec2quaternion(rotation) = vec2quaternion(to_rotation(rotation)) +GLAbstraction.gl_convert(rotation::Makie.Quaternion) = Vec4f(rotation.data) to_pointsize(x::Number) = Float32(x) to_pointsize(x) = Float32(x[1]) struct PointSizeRender @@ -33,8 +23,6 @@ struct PointSizeRender end (x::PointSizeRender)() = glPointSize(to_pointsize(x.size[])) - - @nospecialize """ This is the main function to assemble particles with a GLNormalMesh as a primitive @@ -69,13 +57,16 @@ function draw_mesh_particle(screen, p, data) transparency = false shader = GLVisualizeShader( screen, - "util.vert", "particles.vert", "mesh.frag", "fragment_output.frag", - view = Dict( + "util.vert", + "particles.vert", + "mesh.frag", + "fragment_output.frag", + view=Dict( "position_calc" => position_calc(position, nothing, nothing, nothing, TextureBuffer), "light_calc" => light_calc(shading), "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) end if !isnothing(Makie.to_value(intensity)) @@ -85,26 +76,27 @@ function draw_mesh_particle(screen, p, data) return assemble_shader(data) end - """ This is the most primitive particle system, which uses simple points as primitives. This is supposed to be the fastest way of displaying particles! """ function draw_pixel_scatter(screen, position::VectorTypes, data::Dict) @gen_defaults! data begin - vertex = position => GLBuffer - color_map = nothing => Texture - color = (color_map === nothing ? default(RGBA{Float32}, s) : nothing) => GLBuffer - color_norm = nothing - scale = 2f0 + vertex = position => GLBuffer + color_map = nothing => Texture + color = (color_map === nothing ? default(RGBA{Float32}, s) : nothing) => GLBuffer + color_norm = nothing + scale = 2.0f0 transparency = false - shader = GLVisualizeShader( + shader = GLVisualizeShader( screen, - "fragment_output.frag", "dots.vert", "dots.frag", - view = Dict( + "fragment_output.frag", + "dots.vert", + "dots.frag", + view=Dict( "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) gl_primitive = GL_POINTS end @@ -113,29 +105,33 @@ function draw_pixel_scatter(screen, position::VectorTypes, data::Dict) end function draw_scatter( - screen, p::Tuple{TOrSignal{Matrix{C}}, VectorTypes{P}}, data::Dict - ) where {C <: Colorant, P <: Point} + screen, + p::Tuple{TOrSignal{Matrix{C}},VectorTypes{P}}, + data::Dict, +) where {C<:Colorant,P<:Point} data[:image] = p[1] # we don't want this to be overwritten by user @gen_defaults! data begin - scale = lift(x-> Vec2f(size(x)), p[1]) + scale = lift(x -> Vec2f(size(x)), p[1]) offset = Vec2f(0) end - draw_scatter(screen, (RECTANGLE, p[2]), data) + return draw_scatter(screen, (RECTANGLE, p[2]), data) end function draw_scatter( - screen, p::Tuple{VectorTypes{Matrix{C}}, VectorTypes{P}}, data::Dict - ) where {C <: Colorant, P <: Point} + screen, + p::Tuple{VectorTypes{Matrix{C}},VectorTypes{P}}, + data::Dict, +) where {C<:Colorant,P<:Point} images = map(el32convert, to_value(p[1])) isempty(images) && error("Can not display empty vector of images as primitive") sizes = map(size, images) - if !all(x-> x == sizes[1], sizes) # if differently sized + if !all(x -> x == sizes[1], sizes) # if differently sized # create texture atlas - maxdims = sum(map(Vec{2, Int}, sizes)) - rectangles = map(x->Rect2(0, 0, x...), sizes) + maxdims = sum(map(Vec{2,Int}, sizes)) + rectangles = map(x -> Rect2(0, 0, x...), sizes) rpack = RectanglePacker(Rect2(0, 0, maxdims...)) uv_coordinates = [push!(rpack, rect).area for rect in rectangles] - max_xy = mapreduce(maximum, (a,b)-> max.(a, b), uv_coordinates) + max_xy = mapreduce(maximum, (a, b) -> max.(a, b), uv_coordinates) texture_atlas = Texture(eltype(images[1]), (max_xy...,)) for (area, img) in zip(uv_coordinates, images) texture_atlas[area] = img #transfer to texture atlas @@ -166,42 +162,46 @@ function draw_scatter(screen, (marker, position), data) delete!(data, :rotation) @gen_defaults! data begin - shape = Cint(0) - position = position => GLBuffer - marker_offset = Vec3f(0) => GLBuffer; - scale = Vec2f(0) => GLBuffer - rotation = rot => GLBuffer - image = nothing => Texture + shape = Cint(0) + position = position => GLBuffer + marker_offset = Vec3f(0) => GLBuffer + scale = Vec2f(0) => GLBuffer + rotation = rot => GLBuffer + image = nothing => Texture end @gen_defaults! data begin - quad_offset = Vec2f(0) => GLBuffer - intensity = nothing => GLBuffer - color_map = nothing => Texture - color_norm = nothing - color = nothing => GLBuffer - - glow_color = RGBA{Float32}(0,0,0,0) => GLBuffer - stroke_color = RGBA{Float32}(0,0,0,0) => GLBuffer - stroke_width = 0f0 - glow_width = 0f0 + quad_offset = Vec2f(0) => GLBuffer + intensity = nothing => GLBuffer + color_map = nothing => Texture + color_norm = nothing + color = nothing => GLBuffer + + glow_color = RGBA{Float32}(0, 0, 0, 0) => GLBuffer + stroke_color = RGBA{Float32}(0, 0, 0, 0) => GLBuffer + stroke_width = 0.0f0 + glow_width = 0.0f0 uv_offset_width = Vec4f(0) => GLBuffer - distancefield = nothing => Texture - indices = const_lift(length, position) => to_index_buffer + distancefield = nothing => Texture + indices = const_lift(length, position) => to_index_buffer # rotation and billboard don't go along - billboard = rotation == Vec4f(0,0,0,1) => "if `billboard` == true, particles will always face camera" - fxaa = false - transparency = false - shader = GLVisualizeShader( + billboard = + rotation == Vec4f(0, 0, 0, 1) => "if `billboard` == true, particles will always face camera" + fxaa = false + transparency = false + shader = GLVisualizeShader( screen, - "fragment_output.frag", "util.vert", "sprites.geom", - "sprites.vert", "distance_shape.frag", - view = Dict( + "fragment_output.frag", + "util.vert", + "sprites.geom", + "sprites.vert", + "distance_shape.frag", + view=Dict( "position_calc" => position_calc(position, nothing, nothing, nothing, GLBuffer), "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) scale_primitive = true gl_primitive = GL_POINTS diff --git a/GLMakie/src/glshaders/surface.jl b/GLMakie/src/glshaders/surface.jl index c4d5961fc1a..9595b834a3d 100644 --- a/GLMakie/src/glshaders/surface.jl +++ b/GLMakie/src/glshaders/surface.jl @@ -1,9 +1,7 @@ -function position_calc(x...) - _position_calc(Iterators.filter(x->!isa(x, Nothing), x)...) -end +position_calc(x...) = _position_calc(Iterators.filter(x -> !isa(x, Nothing), x)...) -function normal_calc(x::Bool, invert_normals::Bool = false) +function normal_calc(x::Bool, invert_normals::Bool=false) i = invert_normals ? "-" : "" if x return "$(i)getnormal(position, position_x, position_y, position_z, o_uv);" @@ -12,7 +10,7 @@ function normal_calc(x::Bool, invert_normals::Bool = false) end end -function light_calc(x::Bool) +light_calc(x::Bool) = if x """ vec3 L = normalize(o_lightdir); @@ -24,69 +22,75 @@ function light_calc(x::Bool) else "" end -end function _position_calc( - position_x::MatTypes{T}, position_y::MatTypes{T}, position_z::MatTypes{T}, target::Type{Texture} - ) where T<:AbstractFloat - """ - int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); - ivec2 index2D = ind2sub(dims, index1D); - vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); - pos = vec3( - texelFetch(position_x, index2D, 0).x, - texelFetch(position_y, index2D, 0).x, - texelFetch(position_z, index2D, 0).x - ); - """ + position_x::MatTypes{T}, + position_y::MatTypes{T}, + position_z::MatTypes{T}, + target::Type{Texture}, +) where {T<:AbstractFloat} + return """ + int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); + ivec2 index2D = ind2sub(dims, index1D); + vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); + pos = vec3( + texelFetch(position_x, index2D, 0).x, + texelFetch(position_y, index2D, 0).x, + texelFetch(position_z, index2D, 0).x + ); + """ end function _position_calc( - position_x::VectorTypes{T}, position_y::VectorTypes{T}, position_z::MatTypes{T}, - target::Type{Texture} - ) where T<:AbstractFloat - """ - int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); - ivec2 index2D = ind2sub(dims, index1D); - vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); - pos = vec3( - texelFetch(position_x, index2D.x, 0).x, - texelFetch(position_y, index2D.y, 0).x, - texelFetch(position_z, index2D, 0).x - ); - """ + position_x::VectorTypes{T}, + position_y::VectorTypes{T}, + position_z::MatTypes{T}, + target::Type{Texture}, +) where {T<:AbstractFloat} + return """ + int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); + ivec2 index2D = ind2sub(dims, index1D); + vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); + pos = vec3( + texelFetch(position_x, index2D.x, 0).x, + texelFetch(position_y, index2D.y, 0).x, + texelFetch(position_z, index2D, 0).x + ); + """ end -function _position_calc( - position_xyz::VectorTypes{T}, target::Type{TextureBuffer} - ) where T <: StaticVector - "pos = texelFetch(position, index).xyz;" +function _position_calc(position_xyz::VectorTypes{T}, target::Type{TextureBuffer}) where {T<:StaticVector} + return "pos = texelFetch(position, index).xyz;" end -function _position_calc( - position_xyz::VectorTypes{T}, target::Type{GLBuffer} - ) where T <: StaticVector +function _position_calc(position_xyz::VectorTypes{T}, target::Type{GLBuffer}) where {T<:StaticVector} len = length(T) - filler = join(ntuple(x->0, 3-len), ", ") + filler = join(ntuple(x -> 0, 3 - len), ", ") needs_comma = len != 3 ? ", " : "" - "pos = vec3(position $needs_comma $filler);" + return "pos = vec3(position $needs_comma $filler);" end function _position_calc( - grid::Grid{2}, position_z::MatTypes{T}, target::Type{Texture} - ) where T<:AbstractFloat - """ - int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); - ivec2 index2D = ind2sub(dims, index1D); - vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); - float height = texture(position_z, index01).x; - pos = vec3(grid_pos(position, index01), height); - """ + grid::Grid{2}, + position_z::MatTypes{T}, + target::Type{Texture}, +) where {T<:AbstractFloat} + return """ + int index1D = index + offseti.x + offseti.y * dims.x + (index/(dims.x-1)); + ivec2 index2D = ind2sub(dims, index1D); + vec2 index01 = vec2(index2D) / (vec2(dims)-1.0); + float height = texture(position_z, index01).x; + pos = vec3(grid_pos(position, index01), height); + """ end @nospecialize # surface(::Matrix, ::Matrix, ::Matrix) -function draw_surface(screen, main::Tuple{MatTypes{T}, MatTypes{T}, MatTypes{T}}, data::Dict) where T <: AbstractFloat +function draw_surface( + screen, + main::Tuple{MatTypes{T},MatTypes{T},MatTypes{T}}, + data::Dict, +) where {T<:AbstractFloat} @gen_defaults! data begin position_x = main[1] => (Texture, "x position, must be a `Matrix{Float}`") position_y = main[2] => (Texture, "y position, must be a `Matrix{Float}`") @@ -97,7 +101,11 @@ function draw_surface(screen, main::Tuple{MatTypes{T}, MatTypes{T}, MatTypes{T}} end # surface(Vector or Range, Vector or Range, ::Matrix) -function draw_surface(screen, main::Tuple{VectorTypes{T}, VectorTypes{T}, MatTypes{T}}, data::Dict) where T <: AbstractFloat +function draw_surface( + screen, + main::Tuple{VectorTypes{T},VectorTypes{T},MatTypes{T}}, + data::Dict, +) where {T<:AbstractFloat} @gen_defaults! data begin position_x = main[1] => (Texture, "x position, must be a `Vector{Float}`") position_y = main[2] => (Texture, "y position, must be a `Vector{Float}`") @@ -108,7 +116,7 @@ function draw_surface(screen, main::Tuple{VectorTypes{T}, VectorTypes{T}, MatTyp end function draw_surface(screen, main, data::Dict) - primitive = triangle_mesh(Rect2(0f0,0f0,1f0,1f0)) + primitive = triangle_mesh(Rect2(0.0f0, 0.0f0, 1.0f0, 1.0f0)) to_opengl_mesh!(data, primitive) @gen_defaults! data begin scale = nothing @@ -120,7 +128,7 @@ function draw_surface(screen, main, data::Dict) shading = true normal = shading invert_normals = false - backlight = 0f0 + backlight = 0.0f0 end @gen_defaults! data begin color = nothing => Texture @@ -134,19 +142,25 @@ function draw_surface(screen, main, data::Dict) lowclip = RGBAf(0, 0, 0, 0) uv_scale = Vec2f(1) - instances = const_lift(x->(size(x,1)-1) * (size(x,2)-1), main) => "number of planes used to render the surface" + instances = + const_lift( + x -> (size(x, 1) - 1) * (size(x, 2) - 1), + main, + ) => "number of planes used to render the surface" transparency = false shader = GLVisualizeShader( screen, - "fragment_output.frag", "util.vert", "surface.vert", + "fragment_output.frag", + "util.vert", + "surface.vert", "mesh.frag", - view = Dict( + view=Dict( "position_calc" => position_calc(position, position_x, position_y, position_z, Texture), "normal_calc" => normal_calc(normal, to_value(invert_normals)), "light_calc" => light_calc(shading), "buffers" => output_buffers(screen, to_value(transparency)), - "buffer_writes" => output_buffer_writes(screen, to_value(transparency)) - ) + "buffer_writes" => output_buffer_writes(screen, to_value(transparency)), + ), ) end return assemble_shader(data) diff --git a/GLMakie/src/glshaders/visualize_interface.jl b/GLMakie/src/glshaders/visualize_interface.jl index 1633084e6b6..b07d86bbf37 100644 --- a/GLMakie/src/glshaders/visualize_interface.jl +++ b/GLMakie/src/glshaders/visualize_interface.jl @@ -1,6 +1,6 @@ @enum CubeSides TOP BOTTOM FRONT BACK RIGHT LEFT -struct Grid{N,T <: AbstractRange} +struct Grid{N,T<:AbstractRange} dims::NTuple{N,T} end Base.ndims(::Grid{N,T}) where {N,T} = N @@ -11,7 +11,7 @@ function Grid(a::Array{T,N}) where {N,T} smax = maximum(s) s = s ./ smax Grid(ntuple(Val{N}) do i - range(0, stop=s[i], length=size(a, i)) + return range(0, stop=s[i], length=size(a, i)) end) end @@ -24,12 +24,14 @@ and all kind of range types. The constructor will make sure that all ranges matc the size of the dimension of the array `a`. """ function Grid(a::AbstractArray{T,N}, ranges::Tuple) where {T,N} - length(ranges) = ! N && throw(ArgumentError( - "You need to supply a range for every dimension of the array. Given: $ranges - given Array: $(typeof(a))" - )) + function length(ranges) + return !N && throw( + ArgumentError("You need to supply a range for every dimension of the array. Given: $ranges + given Array: $(typeof(a))"), + ) + end Grid(ntuple(Val(N)) do i - range(first(ranges[i]), stop=last(ranges[i]), length=size(a, i)) + return range(first(ranges[i]), stop=last(ranges[i]), length=size(a, i)) end) end @@ -38,7 +40,7 @@ Base.size(p::Grid) = map(length, p.dims) function Base.getindex(p::Grid{N,T}, i) where {N,T} inds = ind2sub(size(p), i) return Point{N,eltype(T)}(ntuple(Val(N)) do i - p.dims[i][inds[i]] + return p.dims[i][inds[i]] end) end @@ -51,16 +53,16 @@ function GLAbstraction.gl_convert_struct(g::Grid{N,T}, uniform_name::Symbol) whe Symbol("$uniform_name.start") => Vec{N,Float32}(minimum.(g.dims)), Symbol("$uniform_name.stop") => Vec{N,Float32}(maximum.(g.dims)), Symbol("$uniform_name.lendiv") => Vec{N,Cint}(length.(g.dims) .- 1), - Symbol("$uniform_name.dims") => Vec{N,Cint}(map(length, g.dims)) + Symbol("$uniform_name.dims") => Vec{N,Cint}(map(length, g.dims)), ) end -function GLAbstraction.gl_convert_struct(g::Grid{1,T}, uniform_name::Symbol) where T +function GLAbstraction.gl_convert_struct(g::Grid{1,T}, uniform_name::Symbol) where {T} x = g.dims[1] return Dict{Symbol,Any}( Symbol("$uniform_name.start") => Float32(minimum(x)), Symbol("$uniform_name.stop") => Float32(maximum(x)), Symbol("$uniform_name.lendiv") => Cint(length(x) - 1), - Symbol("$uniform_name.dims") => Cint(length(x)) + Symbol("$uniform_name.dims") => Cint(length(x)), ) end @@ -68,24 +70,21 @@ struct GLVisualizeShader <: AbstractLazyShader screen::Screen paths::Tuple kw_args::Dict{Symbol,Any} - function GLVisualizeShader( - screen::Screen, paths::String...; - view = Dict{String,String}(), kw_args... - ) + function GLVisualizeShader(screen::Screen, paths::String...; view=Dict{String,String}(), kw_args...) # TODO properly check what extensions are available @static if !Sys.isapple() view["GLSL_EXTENSIONS"] = "#extension GL_ARB_conservative_depth: enable" view["SUPPORTED_EXTENSIONS"] = "#define DEPTH_LAYOUT" end - args = Dict{Symbol, Any}(kw_args) + args = Dict{Symbol,Any}(kw_args) args[:view] = view args[:fragdatalocation] = [(0, "fragment_color"), (1, "fragment_groupid")] - new(screen, map(x -> loadshader(x), paths), args) + return new(screen, map(x -> loadshader(x), paths), args) end end function GLAbstraction.gl_convert(shader::GLVisualizeShader, data) - GLAbstraction.gl_convert(shader.screen.shader_cache, shader, data) + return GLAbstraction.gl_convert(shader.screen.shader_cache, shader, data) end function assemble_shader(data) @@ -100,7 +99,7 @@ function assemble_shader(data) pre = if !isnothing(pre_fun) _pre_fun = GLAbstraction.StandardPrerender(transp, overdraw) - ()->(_pre_fun(); pre_fun()) + () -> (_pre_fun(); pre_fun()) else GLAbstraction.StandardPrerender(transp, overdraw) end @@ -131,24 +130,22 @@ to_index_buffer(x::TOrSignal{UnitRange{Int}}) = x """ For integers, we transform it to 0 based indices """ -to_index_buffer(x::AbstractVector{I}) where {I <: Integer} = indexbuffer(Cuint.(x .- 1)) -function to_index_buffer(x::Observable{<: AbstractVector{I}}) where I <: Integer - indexbuffer(lift(x -> Cuint.(x .- 1), x)) +to_index_buffer(x::AbstractVector{I}) where {I<:Integer} = indexbuffer(Cuint.(x .- 1)) +function to_index_buffer(x::Observable{<:AbstractVector{I}}) where {I<:Integer} + return indexbuffer(lift(x -> Cuint.(x .- 1), x)) end """ If already GLuint, we assume its 0 based (bad heuristic, should better be solved with some Index type) """ -function to_index_buffer(x::VectorTypes{I}) where I <: Union{GLuint,LineFace{GLIndex}} - indexbuffer(x) -end +to_index_buffer(x::VectorTypes{I}) where {I<:Union{GLuint,LineFace{GLIndex}}} = indexbuffer(x) -to_index_buffer(x) = error( - "Not a valid index type: $(typeof(x)). - Please choose from Int, Vector{UnitRange{Int}}, Vector{Int} or a signal of either of them" -) +function to_index_buffer(x) + return error("Not a valid index type: $(typeof(x)). + Please choose from Int, Vector{UnitRange{Int}}, Vector{Int} or a signal of either of them") +end -function output_buffers(screen::Screen, transparency = false) +function output_buffers(screen::Screen, transparency=false) if transparency """ layout(location=2) out float coverage; @@ -163,7 +160,7 @@ function output_buffers(screen::Screen, transparency = false) end end -function output_buffer_writes(screen::Screen, transparency = false) +function output_buffer_writes(screen::Screen, transparency=false) if transparency scale = screen.config.transparency_weight_scale """ diff --git a/GLMakie/src/glwindow.jl b/GLMakie/src/glwindow.jl index d643f609c5b..3e9c425f07e 100644 --- a/GLMakie/src/glwindow.jl +++ b/GLMakie/src/glwindow.jl @@ -3,19 +3,19 @@ Selection of random objects on the screen is realized by rendering an object id + plus an arbitrary index into the framebuffer. The index can be used for e.g. instanced geometries. """ -struct SelectionID{T <: Integer} +struct SelectionID{T<:Integer} id::T index::T end -Base.convert(::Type{SelectionID{T}}, s::SelectionID) where T = SelectionID{T}(T(s.id), T(s.index)) -Base.zero(::Type{GLMakie.SelectionID{T}}) where T = SelectionID{T}(T(0), T(0)) +Base.convert(::Type{SelectionID{T}}, s::SelectionID) where {T} = SelectionID{T}(T(s.id), T(s.index)) +Base.zero(::Type{GLMakie.SelectionID{T}}) where {T} = SelectionID{T}(T(0), T(0)) mutable struct GLFramebuffer - resolution::Observable{NTuple{2, Int}} + resolution::Observable{NTuple{2,Int}} id::GLuint - buffer_ids::Dict{Symbol, GLuint} - buffers::Dict{Symbol, Texture} + buffer_ids::Dict{Symbol,GLuint} + buffers::Dict{Symbol,Texture} render_buffer_ids::Vector{GLuint} end @@ -25,16 +25,15 @@ Base.haskey(fb::GLFramebuffer, key::Symbol) = haskey(fb.buffers, key) Base.getindex(fb::GLFramebuffer, key::Symbol) = fb.buffer_ids[key] => fb.buffers[key] function getfallback(fb::GLFramebuffer, key::Symbol, fallback_key::Symbol) - haskey(fb, key) ? fb[key] : fb[fallback_key] + return haskey(fb, key) ? fb[key] : fb[fallback_key] end - -function attach_framebuffer(t::Texture{T, 2}, attachment) where T - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, t.id, 0) +function attach_framebuffer(t::Texture{T,2}, attachment) where {T} + return glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, t.id, 0) end # attach texture as color attachment with automatic id picking -function attach_colorbuffer!(fb::GLFramebuffer, key::Symbol, t::Texture{T, 2}) where T +function attach_colorbuffer!(fb::GLFramebuffer, key::Symbol, t::Texture{T,2}) where {T} if haskey(fb.buffer_ids, key) || haskey(fb.buffers, key) error("Key $key already exists.") end @@ -56,34 +55,28 @@ function attach_colorbuffer!(fb::GLFramebuffer, key::Symbol, t::Texture{T, 2}) w return next_color_id end -function GLFramebuffer(fb_size::NTuple{2, Int}) +function GLFramebuffer(fb_size::NTuple{2,Int}) # Create framebuffer frambuffer_id = glGenFramebuffers() glBindFramebuffer(GL_FRAMEBUFFER, frambuffer_id) # Buffers we always need # Holds the image that eventually gets displayed - color_buffer = Texture( - RGBA{N0f8}, fb_size, minfilter = :nearest, x_repeat = :clamp_to_edge - ) + color_buffer = Texture(RGBA{N0f8}, fb_size, minfilter=:nearest, x_repeat=:clamp_to_edge) # Holds a (plot id, element id) for point picking - objectid_buffer = Texture( - Vec{2, GLuint}, fb_size, minfilter = :nearest, x_repeat = :clamp_to_edge - ) + objectid_buffer = Texture(Vec{2,GLuint}, fb_size, minfilter=:nearest, x_repeat=:clamp_to_edge) # holds depth and stencil values depth_buffer = Texture( - Ptr{GLAbstraction.DepthStencil_24_8}(C_NULL), fb_size, - minfilter = :nearest, x_repeat = :clamp_to_edge, - internalformat = GL_DEPTH24_STENCIL8, - format = GL_DEPTH_STENCIL + Ptr{GLAbstraction.DepthStencil_24_8}(C_NULL), + fb_size, + minfilter=:nearest, + x_repeat=:clamp_to_edge, + internalformat=GL_DEPTH24_STENCIL8, + format=GL_DEPTH_STENCIL, ) # Order Independent Transparency - HDR_color_buffer = Texture( - RGBA{Float16}, fb_size, minfilter = :linear, x_repeat = :clamp_to_edge - ) - OIT_weight_buffer = Texture( - N0f8, fb_size, minfilter = :nearest, x_repeat = :clamp_to_edge - ) + HDR_color_buffer = Texture(RGBA{Float16}, fb_size, minfilter=:linear, x_repeat=:clamp_to_edge) + OIT_weight_buffer = Texture(N0f8, fb_size, minfilter=:nearest, x_repeat=:clamp_to_edge) attach_framebuffer(color_buffer, GL_COLOR_ATTACHMENT0) attach_framebuffer(objectid_buffer, GL_COLOR_ATTACHMENT1) @@ -101,63 +94,73 @@ function GLFramebuffer(fb_size::NTuple{2, Int}) # track of the buffer ids that are already in use. We may also want to reuse # buffers so we give them names for easy fetching. buffer_ids = Dict( - :color => GL_COLOR_ATTACHMENT0, + :color => GL_COLOR_ATTACHMENT0, :objectid => GL_COLOR_ATTACHMENT1, :HDR_color => GL_COLOR_ATTACHMENT2, :OIT_weight => GL_COLOR_ATTACHMENT3, - :depth => GL_DEPTH_ATTACHMENT, - :stencil => GL_STENCIL_ATTACHMENT, + :depth => GL_DEPTH_ATTACHMENT, + :stencil => GL_STENCIL_ATTACHMENT, ) buffers = Dict( - :color => color_buffer, + :color => color_buffer, :objectid => objectid_buffer, :HDR_color => HDR_color_buffer, :OIT_weight => OIT_weight_buffer, - :depth => depth_buffer, - :stencil => depth_buffer + :depth => depth_buffer, + :stencil => depth_buffer, ) return GLFramebuffer( - fb_size_node, frambuffer_id, - buffer_ids, buffers, - [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1] + fb_size_node, + frambuffer_id, + buffer_ids, + buffers, + [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1], ) end function Base.resize!(fb::GLFramebuffer, window_size) ws = Int.((window_size[1], window_size[2])) - if ws != size(fb) && all(x-> x > 0, window_size) + if ws != size(fb) && all(x -> x > 0, window_size) for (name, buffer) in fb.buffers resize_nocopy!(buffer, ws) end fb.resolution[] = ws end - nothing + return nothing end - struct MonitorProperties name::String isprimary::Bool - position::Vec{2, Int} - physicalsize::Vec{2, Int} + position::Vec{2,Int} + physicalsize::Vec{2,Int} videomode::GLFW.VidMode videomode_supported::Vector{GLFW.VidMode} - dpi::Vec{2, Float64} + dpi::Vec{2,Float64} monitor::GLFW.Monitor end function MonitorProperties(monitor::GLFW.Monitor) name = GLFW.GetMonitorName(monitor) isprimary = GLFW.GetPrimaryMonitor() == monitor - position = Vec{2, Int}(GLFW.GetMonitorPos(monitor)...) - physicalsize = Vec{2, Int}(GLFW.GetMonitorPhysicalSize(monitor)...) + position = Vec{2,Int}(GLFW.GetMonitorPos(monitor)...) + physicalsize = Vec{2,Int}(GLFW.GetMonitorPhysicalSize(monitor)...) videomode = GLFW.GetVideoMode(monitor) sfactor = Sys.isapple() ? 2.0 : 1.0 - dpi = Vec(videomode.width * 25.4, videomode.height * 25.4) * sfactor ./ Vec{2, Float64}(physicalsize) + dpi = Vec(videomode.width * 25.4, videomode.height * 25.4) * sfactor ./ Vec{2,Float64}(physicalsize) videomode_supported = GLFW.GetVideoModes(monitor) - MonitorProperties(name, isprimary, position, physicalsize, videomode, videomode_supported, dpi, monitor) + return MonitorProperties( + name, + isprimary, + position, + physicalsize, + videomode, + videomode_supported, + dpi, + monitor, + ) end was_destroyed(nw::GLFW.Window) = nw.handle == C_NULL @@ -169,13 +172,9 @@ function GLContext() return GLContext(context, version, glsl_version, unique_context_counter()) end -function ShaderAbstractions.native_switch_context!(x::GLFW.Window) - GLFW.MakeContextCurrent(x) -end +ShaderAbstractions.native_switch_context!(x::GLFW.Window) = GLFW.MakeContextCurrent(x) -function ShaderAbstractions.native_context_alive(x::GLFW.Window) - GLFW.is_initialized() && !was_destroyed(x) -end +ShaderAbstractions.native_context_alive(x::GLFW.Window) = GLFW.is_initialized() && !was_destroyed(x) function destroy!(nw::GLFW.Window) was_current = ShaderAbstractions.is_current_context(nw) @@ -185,7 +184,7 @@ function destroy!(nw::GLFW.Window) GLFW.DestroyWindow(nw) nw.handle = C_NULL end - was_current && ShaderAbstractions.switch_context!() + return was_current && ShaderAbstractions.switch_context!() end function windowsize(nw::GLFW.Window) diff --git a/GLMakie/src/picking.jl b/GLMakie/src/picking.jl index a444e8c7998..e93f79829c7 100644 --- a/GLMakie/src/picking.jl +++ b/GLMakie/src/picking.jl @@ -23,7 +23,7 @@ function pick_native(screen::Screen, rect::Rect2i) end end -function pick_native(screen::Screen, xy::Vec{2, Float64}) +function pick_native(screen::Screen, xy::Vec{2,Float64}) isopen(screen) || return SelectionID{Int}(0, 0) ShaderAbstractions.switch_context!(screen.glscreen) sid = Base.RefValue{SelectionID{UInt32}}() @@ -41,7 +41,7 @@ function pick_native(screen::Screen, xy::Vec{2, Float64}) return SelectionID{Int}(0, 0) end -function Makie.pick(scene::Scene, screen::Screen, xy::Vec{2, Float64}) +function Makie.pick(scene::Scene, screen::Screen, xy::Vec{2,Float64}) sid = pick_native(screen, xy) if haskey(screen.cache2plot, sid.id) plot = screen.cache2plot[sid.id] @@ -51,7 +51,7 @@ function Makie.pick(scene::Scene, screen::Screen, xy::Vec{2, Float64}) end end -function Makie.pick(scene::Scene, screen::Screen, rect::Rect2i) +Makie.pick(scene::Scene, screen::Screen, rect::Rect2i) = map(pick_native(screen, rect)) do sid if haskey(screen.cache2plot, sid.id) (screen.cache2plot[sid.id], sid.index) @@ -59,8 +59,6 @@ function Makie.pick(scene::Scene, screen::Screen, rect::Rect2i) (nothing, sid.index) end end -end - # Skips one set of allocations function Makie.pick_closest(scene::Scene, screen::Screen, xy, range) @@ -70,14 +68,15 @@ function Makie.pick_closest(scene::Scene, screen::Screen, xy, range) x0, y0 = max.(1, floor.(Int, xy .- range)) x1, y1 = min.((w, h), floor.(Int, xy .+ range)) - dx = x1 - x0; dy = y1 - y0 + dx = x1 - x0 + dy = y1 - y0 sids = pick_native(screen, Rect2i(x0, y0, dx, dy)) min_dist = range^2 id = SelectionID{Int}(0, 0) - x, y = xy .+ 1 .- Vec2f(x0, y0) + x, y = xy .+ 1 .- Vec2f(x0, y0) for i in 1:dx, j in 1:dy - d = (x-i)^2 + (y-j)^2 + d = (x - i)^2 + (y - j)^2 sid = sids[i, j] if (d < min_dist) && (sid.id > 0) && haskey(screen.cache2plot, sid.id) min_dist = d @@ -97,20 +96,21 @@ function Makie.pick_sorted(scene::Scene, screen::Screen, xy, range) isopen(screen) || return (nothing, 0) w, h = size(screen) if !((1.0 <= xy[1] <= w) && (1.0 <= xy[2] <= h)) - return Tuple{AbstractPlot, Int}[] + return Tuple{AbstractPlot,Int}[] end x0, y0 = max.(1, floor.(Int, xy .- range)) x1, y1 = min.([w, h], ceil.(Int, xy .+ range)) - dx = x1 - x0; dy = y1 - y0 + dx = x1 - x0 + dy = y1 - y0 picks = pick_native(screen, Rect2i(x0, y0, dx, dy)) selected = filter(x -> x.id > 0 && haskey(screen.cache2plot, x.id), unique(vec(picks))) distances = Float32[range^2 for _ in selected] - x, y = xy .+ 1 .- Vec2f(x0, y0) + x, y = xy .+ 1 .- Vec2f(x0, y0) for i in 1:dx, j in 1:dy if picks[i, j].id > 0 - d = (x-i)^2 + (y-j)^2 + d = (x - i)^2 + (y - j)^2 i = findfirst(isequal(picks[i, j]), selected) if i === nothing @warn "This shouldn't happen..." diff --git a/GLMakie/src/postprocessing.jl b/GLMakie/src/postprocessing.jl index 3c295d158a6..c352e3c072b 100644 --- a/GLMakie/src/postprocessing.jl +++ b/GLMakie/src/postprocessing.jl @@ -16,7 +16,7 @@ function (sp::PostprocessPrerender)() return end -rcpframe(x) = 1f0 ./ Vec2f(x[1], x[2]) +rcpframe(x) = 1.0f0 ./ Vec2f(x[1], x[2]) struct PostProcessor{F} robjs::Vector{RenderObject} @@ -25,25 +25,25 @@ struct PostProcessor{F} end function empty_postprocessor(args...; kwargs...) - PostProcessor(RenderObject[], screen -> nothing, empty_postprocessor) + return PostProcessor(RenderObject[], screen -> nothing, empty_postprocessor) end - function OIT_postprocessor(framebuffer, shader_cache) # Based on https://jcgt.org/published/0002/02/09/, see #1390 # OIT setup shader = LazyShader( shader_cache, loadshader("postprocessing/fullscreen.vert"), - loadshader("postprocessing/OIT_blend.frag") + loadshader("postprocessing/OIT_blend.frag"), ) - data = Dict{Symbol, Any}( + data = Dict{Symbol,Any}( # :opaque_color => framebuffer[:color][2], :sum_color => framebuffer[:HDR_color][2], :prod_alpha => framebuffer[:OIT_weight][2], ) pass = RenderObject( - data, shader, + data, + shader, () -> begin glDepthMask(GL_TRUE) glDisable(GL_DEPTH_TEST) @@ -57,7 +57,7 @@ function OIT_postprocessor(framebuffer, shader_cache) # opaque.a = 0 * src.a + 1 * opaque.a glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA, GL_ZERO, GL_ONE) end, - nothing + nothing, ) pass.postrenderfunction = () -> draw_fullscreen(pass.vertexarray.id) @@ -72,28 +72,22 @@ function OIT_postprocessor(framebuffer, shader_cache) GLAbstraction.render(pass) end - PostProcessor(RenderObject[pass], full_render, OIT_postprocessor) + return PostProcessor(RenderObject[pass], full_render, OIT_postprocessor) end - - - function ssao_postprocessor(framebuffer, shader_cache) # Add missing buffers if !haskey(framebuffer, :position) glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.id[1]) - position_buffer = Texture( - Vec3f, size(framebuffer), minfilter = :nearest, x_repeat = :clamp_to_edge - ) + position_buffer = Texture(Vec3f, size(framebuffer), minfilter=:nearest, x_repeat=:clamp_to_edge) pos_id = attach_colorbuffer!(framebuffer, :position, position_buffer) push!(framebuffer.render_buffer_ids, pos_id) end if !haskey(framebuffer, :normal) if !haskey(framebuffer, :HDR_color) glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.id[1]) - normal_occlusion_buffer = Texture( - Vec4{Float16}, size(framebuffer), minfilter = :nearest, x_repeat = :clamp_to_edge - ) + normal_occlusion_buffer = + Texture(Vec4{Float16}, size(framebuffer), minfilter=:nearest, x_repeat=:clamp_to_edge) normal_occ_id = attach_colorbuffer!(framebuffer, :normal_occlusion, normal_occlusion_buffer) else normal_occ_id = framebuffer[:HDR_color][1] @@ -108,7 +102,7 @@ function ssao_postprocessor(framebuffer, shader_cache) kernel = map(1:N_samples) do i n = normalize([2.0rand() .- 1.0, 2.0rand() .- 1.0, rand()]) scale = lerp_min + (lerp_max - lerp_min) * (i / N_samples)^2 - v = Vec3f(scale * rand() * n) + return v = Vec3f(scale * rand() * n) end # compute occlusion @@ -116,39 +110,37 @@ function ssao_postprocessor(framebuffer, shader_cache) shader_cache, loadshader("postprocessing/fullscreen.vert"), loadshader("postprocessing/SSAO.frag"), - view = Dict( - "N_samples" => "$N_samples" - ) + view=Dict("N_samples" => "$N_samples"), ) - data1 = Dict{Symbol, Any}( + data1 = Dict{Symbol,Any}( :position_buffer => framebuffer[:position][2], :normal_occlusion_buffer => getfallback(framebuffer, :normal_occlusion, :HDR_color)[2], :kernel => kernel, :noise => Texture( [normalize(Vec2f(2.0rand(2) .- 1.0)) for _ in 1:4, __ in 1:4], - minfilter = :nearest, x_repeat = :repeat + minfilter=:nearest, + x_repeat=:repeat, ), :noise_scale => map(s -> Vec2f(s ./ 4.0), framebuffer.resolution), :projection => Observable(Mat4f(I)), :bias => 0.025f0, - :radius => 0.5f0 + :radius => 0.5f0, ) pass1 = RenderObject(data1, shader1, PostprocessPrerender(), nothing) pass1.postrenderfunction = () -> draw_fullscreen(pass1.vertexarray.id) - # blur occlusion and combine with color shader2 = LazyShader( shader_cache, loadshader("postprocessing/fullscreen.vert"), - loadshader("postprocessing/SSAO_blur.frag") + loadshader("postprocessing/SSAO_blur.frag"), ) - data2 = Dict{Symbol, Any}( + data2 = Dict{Symbol,Any}( :normal_occlusion => getfallback(framebuffer, :normal_occlusion, :HDR_color)[2], :color_texture => framebuffer[:color][2], :ids => framebuffer[:objectid][2], :inv_texel_size => lift(rcpframe, framebuffer.resolution), - :blur_range => Int32(2) + :blur_range => Int32(2), ) pass2 = RenderObject(data2, shader2, PostprocessPrerender(), nothing) pass2.postrenderfunction = () -> draw_fullscreen(pass2.vertexarray.id) @@ -193,7 +185,7 @@ function ssao_postprocessor(framebuffer, shader_cache) glDisable(GL_SCISSOR_TEST) end - PostProcessor(RenderObject[pass1, pass2], full_render, ssao_postprocessor) + return PostProcessor(RenderObject[pass1, pass2], full_render, ssao_postprocessor) end """ @@ -206,9 +198,8 @@ function fxaa_postprocessor(framebuffer, shader_cache) if !haskey(framebuffer, :color_luma) if !haskey(framebuffer, :HDR_color) glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.id[1]) - color_luma_buffer = Texture( - RGBA{N0f8}, size(framebuffer), minfilter=:linear, x_repeat=:clamp_to_edge - ) + color_luma_buffer = + Texture(RGBA{N0f8}, size(framebuffer), minfilter=:linear, x_repeat=:clamp_to_edge) luma_id = attach_colorbuffer!(framebuffer, :color_luma, color_luma_buffer) else luma_id = framebuffer[:HDR_color][1] @@ -219,12 +210,10 @@ function fxaa_postprocessor(framebuffer, shader_cache) shader1 = LazyShader( shader_cache, loadshader("postprocessing/fullscreen.vert"), - loadshader("postprocessing/postprocess.frag") - ) - data1 = Dict{Symbol, Any}( - :color_texture => framebuffer[:color][2], - :object_ids => framebuffer[:objectid][2] + loadshader("postprocessing/postprocess.frag"), ) + data1 = + Dict{Symbol,Any}(:color_texture => framebuffer[:color][2], :object_ids => framebuffer[:objectid][2]) pass1 = RenderObject(data1, shader1, PostprocessPrerender(), nothing) pass1.postrenderfunction = () -> draw_fullscreen(pass1.vertexarray.id) @@ -232,9 +221,9 @@ function fxaa_postprocessor(framebuffer, shader_cache) shader2 = LazyShader( shader_cache, loadshader("postprocessing/fullscreen.vert"), - loadshader("postprocessing/fxaa.frag") + loadshader("postprocessing/fxaa.frag"), ) - data2 = Dict{Symbol, Any}( + data2 = Dict{Symbol,Any}( :color_texture => getfallback(framebuffer, :color_luma, :HDR_color)[2], :RCPFrame => lift(rcpframe, framebuffer.resolution), ) @@ -259,10 +248,9 @@ function fxaa_postprocessor(framebuffer, shader_cache) GLAbstraction.render(pass2) end - PostProcessor(RenderObject[pass1, pass2], full_render, fxaa_postprocessor) + return PostProcessor(RenderObject[pass1, pass2], full_render, fxaa_postprocessor) end - """ to_screen_postprocessor(framebuffer, shader_cache, default_id = nothing) @@ -271,16 +259,14 @@ final step for displaying the screen. The argument `screen_fb_id` can be used to pass in a reference to the framebuffer ID of the screen. If `nothing` is used (the default), 0 is used. """ -function to_screen_postprocessor(framebuffer, shader_cache, screen_fb_id = nothing) +function to_screen_postprocessor(framebuffer, shader_cache, screen_fb_id=nothing) # draw color buffer shader = LazyShader( shader_cache, loadshader("postprocessing/fullscreen.vert"), - loadshader("postprocessing/copy.frag") - ) - data = Dict{Symbol, Any}( - :color_texture => framebuffer[:color][2] + loadshader("postprocessing/copy.frag"), ) + data = Dict{Symbol,Any}(:color_texture => framebuffer[:color][2]) pass = RenderObject(data, shader, PostprocessPrerender(), nothing) pass.postrenderfunction = () -> draw_fullscreen(pass.vertexarray.id) @@ -297,7 +283,7 @@ function to_screen_postprocessor(framebuffer, shader_cache, screen_fb_id = nothi GLAbstraction.render(pass) # copy postprocess end - PostProcessor(RenderObject[pass], full_render, to_screen_postprocessor) + return PostProcessor(RenderObject[pass], full_render, to_screen_postprocessor) end function destroy!(pp::PostProcessor) diff --git a/GLMakie/src/screen.jl b/GLMakie/src/screen.jl index 9f732df3b22..b72af661e94 100644 --- a/GLMakie/src/screen.jl +++ b/GLMakie/src/screen.jl @@ -1,7 +1,7 @@ const ScreenID = UInt16 const ZIndex = Int # ID, Area, clear, is visible, background color -const ScreenArea = Tuple{ScreenID, Scene} +const ScreenArea = Tuple{ScreenID,Scene} function renderloop end @@ -51,7 +51,7 @@ mutable struct ScreenConfig title::String fullscreen::Bool debugging::Bool - monitor::Union{Nothing, GLFW.Monitor} + monitor::Union{Nothing,GLFW.Monitor} # Postprocessor oit::Bool @@ -60,26 +60,26 @@ mutable struct ScreenConfig transparency_weight_scale::Float32 function ScreenConfig( - # Renderloop - renderloop::Union{Makie.Automatic, Function}, - pause_renderloop::Bool, - vsync::Bool, - render_on_demand::Bool, - framerate::Number, - # GLFW window attributes - float::Bool, - focus_on_show::Bool, - decorated::Bool, - title::AbstractString, - fullscreen::Bool, - debugging::Bool, - monitor::Union{Nothing, GLFW.Monitor}, - # Preproccessor - oit::Bool, - fxaa::Bool, - ssao::Bool, - transparency_weight_scale::Number) - + # Renderloop + renderloop::Union{Makie.Automatic,Function}, + pause_renderloop::Bool, + vsync::Bool, + render_on_demand::Bool, + framerate::Number, + # GLFW window attributes + float::Bool, + focus_on_show::Bool, + decorated::Bool, + title::AbstractString, + fullscreen::Bool, + debugging::Bool, + monitor::Union{Nothing,GLFW.Monitor}, + # Preproccessor + oit::Bool, + fxaa::Bool, + ssao::Bool, + transparency_weight_scale::Number, + ) return new( # Renderloop renderloop isa Makie.Automatic ? GLMakie.renderloop : renderloop, @@ -99,7 +99,8 @@ mutable struct ScreenConfig oit, fxaa, ssao, - transparency_weight_scale) + transparency_weight_scale, + ) end end @@ -141,51 +142,62 @@ mutable struct Screen{GLWindow} <: MakieScreen glscreen::GLWindow shader_cache::GLAbstraction.ShaderCache framebuffer::GLFramebuffer - config::Union{Nothing, ScreenConfig} + config::Union{Nothing,ScreenConfig} stop_renderloop::Bool - rendertask::Union{Task, Nothing} + rendertask::Union{Task,Nothing} - screen2scene::Dict{WeakRef, ScreenID} + screen2scene::Dict{WeakRef,ScreenID} screens::Vector{ScreenArea} - renderlist::Vector{Tuple{ZIndex, ScreenID, RenderObject}} + renderlist::Vector{Tuple{ZIndex,ScreenID,RenderObject}} postprocessors::Vector{PostProcessor} - cache::Dict{UInt64, RenderObject} - cache2plot::Dict{UInt32, AbstractPlot} + cache::Dict{UInt64,RenderObject} + cache2plot::Dict{UInt32,AbstractPlot} framecache::Matrix{RGB{N0f8}} render_tick::Observable{Nothing} window_open::Observable{Bool} - root_scene::Union{Scene, Nothing} + root_scene::Union{Scene,Nothing} reuse::Bool close_after_renderloop::Bool # To trigger rerenders that aren't related to an existing renderobject. requires_update::Bool function Screen( - glscreen::GLWindow, - shader_cache::GLAbstraction.ShaderCache, - framebuffer::GLFramebuffer, - config::Union{Nothing, ScreenConfig}, - stop_renderloop::Bool, - rendertask::Union{Nothing, Task}, - - screen2scene::Dict{WeakRef, ScreenID}, - screens::Vector{ScreenArea}, - renderlist::Vector{Tuple{ZIndex, ScreenID, RenderObject}}, - postprocessors::Vector{PostProcessor}, - cache::Dict{UInt64, RenderObject}, - cache2plot::Dict{UInt32, AbstractPlot}, - reuse::Bool - ) where {GLWindow} - + glscreen::GLWindow, + shader_cache::GLAbstraction.ShaderCache, + framebuffer::GLFramebuffer, + config::Union{Nothing,ScreenConfig}, + stop_renderloop::Bool, + rendertask::Union{Nothing,Task}, + screen2scene::Dict{WeakRef,ScreenID}, + screens::Vector{ScreenArea}, + renderlist::Vector{Tuple{ZIndex,ScreenID,RenderObject}}, + postprocessors::Vector{PostProcessor}, + cache::Dict{UInt64,RenderObject}, + cache2plot::Dict{UInt32,AbstractPlot}, + reuse::Bool, + ) where {GLWindow} s = size(framebuffer) screen = new{GLWindow}( - glscreen, shader_cache, framebuffer, - config, stop_renderloop, rendertask, + glscreen, + shader_cache, + framebuffer, + config, + stop_renderloop, + rendertask, screen2scene, - screens, renderlist, postprocessors, cache, cache2plot, - Matrix{RGB{N0f8}}(undef, s), Observable(nothing), - Observable(true), nothing, reuse, true, false + screens, + renderlist, + postprocessors, + cache, + cache2plot, + Matrix{RGB{N0f8}}(undef, s), + Observable(nothing), + Observable(true), + nothing, + reuse, + true, + false, ) push!(ALL_SCREENS, screen) # track all created screens return screen @@ -198,28 +210,27 @@ const ALL_SCREENS = Set{Screen}() function empty_screen(debugging::Bool; reuse=true) windowhints = [ - (GLFW.SAMPLES, 0), - (GLFW.DEPTH_BITS, 0), + (GLFW.SAMPLES, 0), + (GLFW.DEPTH_BITS, 0), # SETTING THE ALPHA BIT IS REALLY IMPORTANT ON OSX, SINCE IT WILL JUST KEEP SHOWING A BLACK SCREEN # WITHOUT ANY ERROR -.- - (GLFW.ALPHA_BITS, 8), - (GLFW.RED_BITS, 8), - (GLFW.GREEN_BITS, 8), - (GLFW.BLUE_BITS, 8), - + (GLFW.ALPHA_BITS, 8), + (GLFW.RED_BITS, 8), + (GLFW.GREEN_BITS, 8), + (GLFW.BLUE_BITS, 8), (GLFW.STENCIL_BITS, 0), - (GLFW.AUX_BUFFERS, 0), + (GLFW.AUX_BUFFERS, 0), ] resolution = (10, 10) window = try GLFW.Window( - resolution = resolution, - windowhints = windowhints, - visible = false, - focus = false, - fullscreen = false, - debugging = debugging, + resolution=resolution, + windowhints=windowhints, + visible=false, + focus=false, + fullscreen=false, + debugging=debugging, ) catch e @warn(""" @@ -243,19 +254,22 @@ function empty_screen(debugging::Bool; reuse=true) empty_postprocessor(), empty_postprocessor(), empty_postprocessor(), - to_screen_postprocessor(fb, shader_cache) + to_screen_postprocessor(fb, shader_cache), ] screen = Screen( - window, shader_cache, fb, - nothing, false, + window, + shader_cache, + fb, nothing, - Dict{WeakRef, ScreenID}(), + false, + nothing, + Dict{WeakRef,ScreenID}(), ScreenArea[], - Tuple{ZIndex, ScreenID, RenderObject}[], + Tuple{ZIndex,ScreenID,RenderObject}[], postprocessors, - Dict{UInt64, RenderObject}(), - Dict{UInt32, AbstractPlot}(), + Dict{UInt64,RenderObject}(), + Dict{UInt32,AbstractPlot}(), reuse, ) GLFW.SetWindowRefreshCallback(window, window -> refreshwindowcb(window, screen)) @@ -301,7 +315,7 @@ end const GLFW_FOCUS_ON_SHOW = 0x0002000C function Makie.apply_screen_config!(screen::Screen, config::ScreenConfig, scene::Scene, args...) - apply_config!(screen, config) + return apply_config!(screen, config) end function apply_config!(screen::Screen, config::ScreenConfig; visible::Bool=true, start_renderloop::Bool=true) @@ -345,11 +359,11 @@ function apply_config!(screen::Screen, config::ScreenConfig; visible::Bool=true, end function Screen(; - resolution::Union{Nothing, Tuple{Int, Int}} = nothing, - visible = true, - start_renderloop = true, - screen_config... - ) + resolution::Union{Nothing,Tuple{Int,Int}}=nothing, + visible=true, + start_renderloop=true, + screen_config..., +) # Screen config is managed by the current active theme, so managed by Makie config = Makie.merge_screen_config(ScreenConfig, screen_config) screen = screen_from_pool(config.debugging) @@ -387,7 +401,14 @@ function Screen(scene::Scene, config::ScreenConfig; visible=true, start_renderlo end # Screen to save a png/jpeg to file or io -function Screen(scene::Scene, config::ScreenConfig, io::Union{Nothing, String, IO}, typ::MIME; visible=false, start_renderloop=false) +function Screen( + scene::Scene, + config::ScreenConfig, + io::Union{Nothing,String,IO}, + typ::MIME; + visible=false, + start_renderloop=false, +) screen = singleton_screen(config.debugging) apply_config!(screen, config; visible=visible, start_renderloop=start_renderloop) display_scene!(screen, scene) @@ -395,7 +416,13 @@ function Screen(scene::Scene, config::ScreenConfig, io::Union{Nothing, String, I end # Screen that is efficient for `colorbuffer(screen)` -function Screen(scene::Scene, config::ScreenConfig, ::Makie.ImageStorageFormat; visible=false, start_renderloop=false) +function Screen( + scene::Scene, + config::ScreenConfig, + ::Makie.ImageStorageFormat; + visible=false, + start_renderloop=false, +) screen = singleton_screen(config.debugging) apply_config!(screen, config; visible=visible, start_renderloop=start_renderloop) display_scene!(screen, scene) @@ -405,7 +432,7 @@ end function pollevents(screen::Screen) ShaderAbstractions.switch_context!(screen.glscreen) notify(screen.render_tick) - GLFW.PollEvents() + return GLFW.PollEvents() end Base.wait(x::Screen) = !isnothing(x.rendertask) && wait(x.rendertask) @@ -448,7 +475,7 @@ function Base.delete!(screen::Screen, scene::Scene) # Remap scene IDs to a continuous range by replacing the largest ID # with the one that got removed - if deleted_id-1 != length(screen.screens) + if deleted_id - 1 != length(screen.screens) key, max_id = first(screen.screen2scene) for p in screen.screen2scene if p[2] > max_id @@ -492,7 +519,7 @@ function destroy!(rob::RenderObject) for obs in rob.observables Observables.clear(obs) end - GLAbstraction.free(rob.vertexarray) + return GLAbstraction.free(rob.vertexarray) end function Base.delete!(screen::Screen, scene::Scene, plot::AbstractPlot) @@ -507,7 +534,7 @@ function Base.delete!(screen::Screen, scene::Scene, plot::AbstractPlot) renderobject = get(screen.cache, objectid(plot), nothing) if !isnothing(renderobject) destroy!(renderobject) - filter!(x-> x[3] !== renderobject, screen.renderlist) + filter!(x -> x[3] !== renderobject, screen.renderlist) delete!(screen.cache2plot, renderobject.id) end delete!(screen.cache, objectid(plot)) @@ -536,7 +563,7 @@ function Base.empty!(screen::Screen) empty!(screen.screen2scene) empty!(screen.screens) Observables.clear(screen.render_tick) - Observables.clear(screen.window_open) + return Observables.clear(screen.window_open) end function destroy!(screen::Screen) @@ -607,10 +634,10 @@ function Base.resize!(screen::Screen, w, h) nw = to_native(screen) resize_native!(nw, w, h) fb = screen.framebuffer - resize!(fb, (w, h)) + return resize!(fb, (w, h)) end -function fast_color_data!(dest::Array{RGB{N0f8}, 2}, source::Texture{T, 2}) where T +function fast_color_data!(dest::Array{RGB{N0f8},2}, source::Texture{T,2}) where {T} GLAbstraction.bind(source) glPixelStorei(GL_PACK_ALIGNMENT, 1) glGetTexImage(source.texturetype, 0, GL_RGB, GL_UNSIGNED_BYTE, dest) @@ -643,7 +670,7 @@ function depthbuffer(screen::Screen) return depth end -function Makie.colorbuffer(screen::Screen, format::Makie.ImageStorageFormat = Makie.JuliaNative) +function Makie.colorbuffer(screen::Screen, format::Makie.ImageStorageFormat=Makie.JuliaNative) if !isopen(screen) error("Screen not open!") end @@ -670,7 +697,7 @@ end function Base.push!(screen::Screen, scene::Scene, robj) # filter out gc'ed elements filter!(screen.screen2scene) do (k, v) - k.value !== nothing + return k.value !== nothing end screenid = get!(screen.screen2scene, WeakRef(scene)) do id = length(screen.screens) + 1 @@ -689,7 +716,7 @@ Loads the makie loading icon and embedds it in an image the size of resolution function get_loading_image(resolution) icon = Matrix{N0f8}(undef, 192, 192) open(joinpath(GL_ASSET_DIR, "loading.bin")) do io - read!(io, icon) + return read!(io, icon) end img = zeros(RGBA{N0f8}, resolution...) center = resolution .÷ 2 @@ -730,7 +757,7 @@ function renderloop_running(screen::Screen) return !screen.stop_renderloop && !isnothing(screen.rendertask) && !istaskdone(screen.rendertask) end -function start_renderloop!(screen::Screen) +start_renderloop!(screen::Screen) = if renderloop_running(screen) screen.config.pause_renderloop = false return @@ -746,11 +773,8 @@ function start_renderloop!(screen::Screen) error("What's up with task $(task)") end end -end -function pause_renderloop!(screen::Screen) - screen.config.pause_renderloop = true -end +pause_renderloop!(screen::Screen) = screen.config.pause_renderloop = true function stop_renderloop!(screen::Screen; close_after_renderloop=screen.close_after_renderloop) # don't double close when stopping renderloop @@ -770,9 +794,7 @@ function stop_renderloop!(screen::Screen; close_after_renderloop=screen.close_af return end -function set_framerate!(screen::Screen, fps=30) - screen.config.framerate = fps -end +set_framerate!(screen::Screen, fps=30) = screen.config.framerate = fps function refreshwindowcb(window, screen) screen.render_tick[] = nothing @@ -782,10 +804,11 @@ function refreshwindowcb(window, screen) end # TODO add render_tick event to scene events -function vsynced_renderloop(screen) +vsynced_renderloop(screen) = while isopen(screen) && !screen.stop_renderloop if screen.config.pause_renderloop - pollevents(screen); sleep(0.1) + pollevents(screen) + sleep(0.1) continue end pollevents(screen) # GLFW poll @@ -793,12 +816,12 @@ function vsynced_renderloop(screen) GLFW.SwapBuffers(to_native(screen)) yield() end -end -function fps_renderloop(screen::Screen) +fps_renderloop(screen::Screen) = while isopen(screen) && !screen.stop_renderloop if screen.config.pause_renderloop - pollevents(screen); sleep(0.1) + pollevents(screen) + sleep(0.1) continue end time_per_frame = 1.0 / screen.config.framerate @@ -814,7 +837,6 @@ function fps_renderloop(screen::Screen) yield() end end -end function requires_update(screen::Screen) if screen.requires_update @@ -827,7 +849,7 @@ function requires_update(screen::Screen) return false end -function on_demand_renderloop(screen::Screen) +on_demand_renderloop(screen::Screen) = while isopen(screen) && !screen.stop_renderloop t = time_ns() time_per_frame = 1.0 / screen.config.framerate @@ -846,7 +868,6 @@ function on_demand_renderloop(screen::Screen) yield() end end -end function renderloop(screen) isopen(screen) || error("Screen most be open to run renderloop!") @@ -864,14 +885,14 @@ function renderloop(screen) fps_renderloop(screen) end catch e - @warn "error in renderloop" exception=(e, Base.catch_backtrace()) + @warn "error in renderloop" exception = (e, Base.catch_backtrace()) rethrow(e) end if screen.close_after_renderloop try close(screen) catch e - @warn "error closing screen" exception=(e, Base.catch_backtrace()) + @warn "error closing screen" exception = (e, Base.catch_backtrace()) end end screen.rendertask = nothing @@ -880,7 +901,7 @@ end function plot2robjs(screen::Screen, plot) plots = Makie.flatten_plots(plot) - return map(x-> screen.cache[objectid(x)], plots) + return map(x -> screen.cache[objectid(x)], plots) end export plot2robjs diff --git a/GLMakie/test/glmakie_refimages.jl b/GLMakie/test/glmakie_refimages.jl index 5a386d5d0e8..91821e9d24d 100644 --- a/GLMakie/test/glmakie_refimages.jl +++ b/GLMakie/test/glmakie_refimages.jl @@ -11,18 +11,18 @@ using ReferenceTests.RNG scene = Scene() cam2d!(scene) r = 4 - sep = 4*r - scatter!(scene, (sep+2*r)*[-1,-1,1,1], (sep+2*r)*[-1,1,-1,1]) + sep = 4 * r + scatter!(scene, (sep + 2 * r) * [-1, -1, 1, 1], (sep + 2 * r) * [-1, 1, -1, 1]) - for i=-1:1 - for j=-1:1 - angle = pi/2 + pi/4*i - x = r*[-cos(angle/2),0,-cos(angle/2)] - y = r*[-sin(angle/2),0,sin(angle/2)] + for i in -1:1 + for j in -1:1 + angle = pi / 2 + pi / 4 * i + x = r * [-cos(angle / 2), 0, -cos(angle / 2)] + y = r * [-sin(angle / 2), 0, sin(angle / 2)] linewidth = 40 * 2.0^j - lines!(scene, x .+ sep*i, y .+ sep*j, color=RGBAf(0,0,0,0.5), linewidth=linewidth) - lines!(scene, x .+ sep*i, y .+ sep*j, color=:red) + lines!(scene, x .+ sep * i, y .+ sep * j, color=RGBAf(0, 0, 0, 0.5), linewidth=linewidth) + lines!(scene, x .+ sep * i, y .+ sep * j, color=:red) end end center!(scene) @@ -49,41 +49,41 @@ end pos = Observable(RNG.rand(Point3f, 2)) rot = Observable(RNG.rand(Vec3f, 2)) color = Observable(RNG.rand(RGBf, 2)) - size = Observable(0.1*RNG.rand(2)) + size = Observable(0.1 * RNG.rand(2)) makenew = Observable(1) on(makenew) do i pos[] = RNG.rand(Point3f, i) rot[] = RNG.rand(Vec3f, i) color[] = RNG.rand(RGBf, i) - size[] = 0.1*RNG.rand(i) + return size[] = 0.1 * RNG.rand(i) end - fig, ax, p = meshscatter(pos, + fig, ax, p = meshscatter( + pos, rotations=rot, color=color, markersize=size, - axis = (; scenekw = (;limits=Rect3f(Point3(0), Point3(1)))) + axis=(; scenekw=(; limits=Rect3f(Point3(0), Point3(1)))), ) Record(fig, [10, 5, 100, 60, 177]) do i - makenew[] = i + return makenew[] = i end end @reference_test "Explicit frame rendering" begin - function update_loop(m, buff, screen) - for i = 1:20 + update_loop(m, buff, screen) = + for i in 1:20 GLFW.PollEvents() - buff .= RNG.rand.(Point3f) .* 20f0 + buff .= RNG.rand.(Point3f) .* 20.0f0 m[1] = buff GLMakie.render_frame(screen) GLFW.SwapBuffers(GLMakie.to_native(screen)) glFinish() end - end - fig, ax, meshplot = meshscatter(RNG.rand(Point3f, 10^4) .* 20f0) - screen = display(GLMakie.Screen(;renderloop=(screen) -> nothing, start_renderloop=false), fig.scene) - buff = RNG.rand(Point3f, 10^4) .* 20f0; + fig, ax, meshplot = meshscatter(RNG.rand(Point3f, 10^4) .* 20.0f0) + screen = display(GLMakie.Screen(; renderloop=(screen) -> nothing, start_renderloop=false), fig.scene) + buff = RNG.rand(Point3f, 10^4) .* 20.0f0 update_loop(meshplot, buff, screen) @test isnothing(screen.rendertask) GLMakie.destroy!(screen) @@ -96,10 +96,19 @@ end fig = Figure() left = LScene(fig[1, 1]) - contour!(left, [sin(i+j) * sin(j+k) * sin(i+k) for i in 1:10, j in 1:10, k in 1:10], enable_depth = true) - mesh!(left, Sphere(Point3f(5), 6f0)) + contour!( + left, + [sin(i + j) * sin(j + k) * sin(i + k) for i in 1:10, j in 1:10, k in 1:10], + enable_depth=true, + ) + mesh!(left, Sphere(Point3f(5), 6.0f0)) right = LScene(fig[1, 2]) - volume!(right, [sin(2i) * sin(2j) * sin(2k) for i in 1:10, j in 1:10, k in 1:10], algorithm = :iso, enable_depth = true) - mesh!(right, Sphere(Point3f(5), 6f0)) + volume!( + right, + [sin(2i) * sin(2j) * sin(2k) for i in 1:10, j in 1:10, k in 1:10], + algorithm=:iso, + enable_depth=true, + ) + mesh!(right, Sphere(Point3f(5), 6.0f0)) fig end diff --git a/GLMakie/test/runtests.jl b/GLMakie/test/runtests.jl index d73329c6825..67d277888f9 100644 --- a/GLMakie/test/runtests.jl +++ b/GLMakie/test/runtests.jl @@ -13,7 +13,7 @@ if !GLMakie.ModernGL.enable_opengl_debugging end reference_tests_dir = normpath(joinpath(dirname(pathof(Makie)), "..", "ReferenceTests")) -Pkg.develop(PackageSpec(path = reference_tests_dir)) +Pkg.develop(PackageSpec(path=reference_tests_dir)) using ReferenceTests GLMakie.activate!(framerate=1.0) @@ -36,15 +36,15 @@ include("unit_tests.jl") recorded_files, recording_dir = @include_reference_tests "refimages.jl" missing_images, scores = ReferenceTests.record_comparison(recording_dir) n_missing_images += length(missing_images) - ReferenceTests.test_comparison(scores; threshold = 0.032) + ReferenceTests.test_comparison(scores; threshold=0.032) end @testset "glmakie_refimages" begin recorded_files, recording_dir = @include_reference_tests joinpath(@__DIR__, "glmakie_refimages.jl") missing_images, scores = ReferenceTests.record_comparison(recording_dir) n_missing_images += length(missing_images) - ReferenceTests.test_comparison(scores; threshold = 0.01) - ReferenceTests.test_comparison(scores; threshold = 0.01) + ReferenceTests.test_comparison(scores; threshold=0.01) + ReferenceTests.test_comparison(scores; threshold=0.01) end GLMakie.closeall() GC.gc(true) # make sure no finalizers act up! diff --git a/GLMakie/test/unit_tests.jl b/GLMakie/test/unit_tests.jl index ea16da8f284..e30b38d481e 100644 --- a/GLMakie/test/unit_tests.jl +++ b/GLMakie/test/unit_tests.jl @@ -15,7 +15,7 @@ end @test isempty(GLMakie.SINGLETON_SCREEN) # A raw screen should be tracked in GLFW_WINDOWS - screen = GLMakie.Screen(resolution = (100, 100), visible = false) + screen = GLMakie.Screen(resolution=(100, 100), visible=false) @test isopen(screen) @test GLMakie.ALL_SCREENS == Set([screen]) @test isempty(GLMakie.SCREEN_REUSE_POOL) @@ -23,7 +23,7 @@ end # A displayed figure should create a singleton screen and leave other # screens untouched - fig, ax, splot = scatter(1:4); + fig, ax, splot = scatter(1:4) screen2 = display(fig) @test screen !== screen2 @test GLMakie.ALL_SCREENS == Set([screen, screen2]) @@ -52,11 +52,11 @@ end @test isempty(events(ax.scene).window_open.listeners) # Test singleton screen replacement - fig, ax, p = scatter(1:4); + fig, ax, p = scatter(1:4) screen = display(fig) ptr = deepcopy(screen.glscreen.handle) @test isopen(screen) && (screen === GLMakie.SINGLETON_SCREEN[1]) - fig2, ax2, p2 = scatter(4:-1:1); + fig2, ax2, p2 = scatter(4:-1:1) screen2 = display(fig2) @test isopen(screen2) && (screen2 === GLMakie.SINGLETON_SCREEN[]) @test screen === screen2 @@ -67,25 +67,25 @@ end @testset "Pick a plot element or plot elements inside a rectangle" begin N = 100000 fig, ax, splot = scatter(1:N, 1:N) - limits!(ax, 99990,100000, 99990,100000) - screen = display(GLMakie.Screen(visible = false), fig) + limits!(ax, 99990, 100000, 99990, 100000) + screen = display(GLMakie.Screen(visible=false), fig) # we don't really need the color buffer here, but this should be the best way right now to really # force a full render to happen GLMakie.Makie.colorbuffer(screen) # test for pick a single data point (with idx > 65535) - point_px = project_sp(ax.scene, Point2f(N-1,N-1)) - plot,idx = pick(ax.scene, point_px) - @test idx == N-1 + point_px = project_sp(ax.scene, Point2f(N - 1, N - 1)) + plot, idx = pick(ax.scene, point_px) + @test idx == N - 1 # test for pick a rectangle of data points (also with some indices > 65535) - rect = Rect2f(99990.5,99990.5,8,8) + rect = Rect2f(99990.5, 99990.5, 8, 8) origin_px = project_sp(ax.scene, Point(origin(rect))) tip_px = project_sp(ax.scene, Point(origin(rect) .+ widths(rect))) rect_px = Rect2i(round.(origin_px), round.(tip_px .- origin_px)) picks = unique(pick(ax.scene, rect_px)) # objects returned in plot_idx should be either grid lines (i.e. LineSegments) or Scatter points - @test all(pi-> pi[1] isa Union{LineSegments,Scatter, Makie.Mesh}, picks) + @test all(pi -> pi[1] isa Union{LineSegments,Scatter,Makie.Mesh}, picks) # scatter points should have indices equal to those in 99991:99998 scatter_plot_idx = filter(pi -> pi[1] isa Scatter, picks) @test Set(last.(scatter_plot_idx)) == Set(99991:99998) @@ -96,7 +96,7 @@ end @testset "emtpy!(fig)" begin GLMakie.closeall() fig = Figure() - ax = Axis(fig[1,1]) + ax = Axis(fig[1, 1]) heatmap!(ax, rand(4, 4)) lines!(ax, 1:5, rand(5); linewidth=3) text!(ax, [Point2f(2)], text=["hi"]) @@ -112,7 +112,7 @@ end @test robj.vertexarray.id == 0 end end - ax = Axis(fig[1,1]) + ax = Axis(fig[1, 1]) heatmap!(ax, rand(4, 4)) lines!(ax, 1:5, rand(5); linewidth=3) text!(ax, [Point2f(2)], text=["hi"]) @@ -133,7 +133,7 @@ end @testset "empty!(ax)" begin GLMakie.closeall() fig = Figure() - ax = Axis(fig[1,1]) + ax = Axis(fig[1, 1]) hmp = heatmap!(ax, rand(4, 4)) lp = lines!(ax, 1:5, rand(5); linewidth=3) tp = text!(ax, [Point2f(2)], text=["hi"]) @@ -141,7 +141,7 @@ end @test ax.scene.plots == [hmp, lp, tp] - robjs = map(x-> screen.cache[objectid(x)], [hmp, lp, tp.plots...]) + robjs = map(x -> screen.cache[objectid(x)], [hmp, lp, tp.plots...]) empty!(ax) @@ -178,7 +178,7 @@ end @testset "closing and redisplaying" begin GLMakie.closeall() fig = Figure() - ax = Axis(fig[1,1]) # only happens with axis + ax = Axis(fig[1, 1]) # only happens with axis # lines!(ax, 1:5, rand(5); linewidth=5) # but doesn't need a plot screen = display(fig) GLMakie.closeall() @@ -189,11 +189,11 @@ end @testset "closing and redisplaying + resizing" begin GLMakie.closeall() fig = Figure() - ax = Axis(fig[1,1]) # only happens with axis + ax = Axis(fig[1, 1]) # only happens with axis screen = display(fig) close(screen) screen = display(fig) - resize!(fig, 800,601) + resize!(fig, 800, 601) @test true # test for no errors for now # GLMakie.destroy!(screen) end @@ -211,8 +211,8 @@ end GLMakie.closeall() screens = map(1:10) do i fig = Figure(resolution=(500, 500)) - rng = Random.MersenneTwister(0) - ax, pl = image(fig[1, 1], 0..1, 0..1, rand(rng, 1000, 1000)) + rng = Random.MersenneTwister(0) + ax, pl = image(fig[1, 1], 0 .. 1, 0 .. 1, rand(rng, 1000, 1000)) scatter!(ax, rand(rng, Point2f, 1000), color=:red) lines!(ax, rand(rng, Point2f, 1000), transparency=true) @@ -220,13 +220,13 @@ end meshscatter!(ax3d, rand(rng, Point3f, 100), color=:red) heatmap(fig[2, 1], rand(rng, 100, 100)) - surface(fig[2, 2], 0..1, 0..1, rand(rng, 1000, 1000) ./ 2) + surface(fig[2, 2], 0 .. 1, 0 .. 1, rand(rng, 1000, 1000) ./ 2) - display(GLMakie.Screen(visible=false), fig) + return display(GLMakie.Screen(visible=false), fig) end images = map(Makie.colorbuffer, screens) - @test all(x-> x ≈ first(images), images) + @test all(x -> x ≈ first(images), images) @test Base.summarysize(screens) / 10^6 > 300 foreach(close, screens) @@ -248,7 +248,7 @@ end @test (Base.summarysize(screen) / 10^6) < 1.2 end # All should go to pool after close - @test all(x-> x in GLMakie.SCREEN_REUSE_POOL, screens) + @test all(x -> x in GLMakie.SCREEN_REUSE_POOL, screens) GLMakie.closeall() # now every screen should be gone diff --git a/MakieCore/src/MakieCore.jl b/MakieCore/src/MakieCore.jl index 30940b26b11..5bdca40da10 100644 --- a/MakieCore/src/MakieCore.jl +++ b/MakieCore/src/MakieCore.jl @@ -9,7 +9,6 @@ using Observables using Observables: to_value using Base: RefValue - include("types.jl") include("attributes.jl") include("recipes.jl") diff --git a/MakieCore/src/attributes.jl b/MakieCore/src/attributes.jl index 84eddc36f94..cd02ac89a96 100644 --- a/MakieCore/src/attributes.jl +++ b/MakieCore/src/attributes.jl @@ -10,24 +10,26 @@ value_convert(x::Observables.AbstractObservable) = Observables.observe(x) value_convert(@nospecialize(x)) = x # We transform a tuple of observables into a Observable(tuple(values...)) -function value_convert(x::NTuple{N, Union{Any, Observables.AbstractObservable}}) where N +function value_convert(x::NTuple{N,Union{Any,Observables.AbstractObservable}}) where {N} result = Observable(to_value.(x)) - onany((args...)-> args, x...) + onany((args...) -> args, x...) return result end value_convert(x::NamedTuple) = Attributes(x) # Version of `convert(Observable{Any}, obj)` that doesn't require runtime dispatch -node_any(@nospecialize(obj)) = isa(obj, Observable{Any}) ? obj : - isa(obj, Observable) ? convert(Observable{Any}, obj) : Observable{Any}(obj) +function node_any(@nospecialize(obj)) + return isa(obj, Observable{Any}) ? obj : + isa(obj, Observable) ? convert(Observable{Any}, obj) : Observable{Any}(obj) +end -node_pairs(pair::Union{Pair, Tuple{Any, Any}}) = (pair[1] => node_any(value_convert(pair[2]))) +node_pairs(pair::Union{Pair,Tuple{Any,Any}}) = (pair[1] => node_any(value_convert(pair[2]))) node_pairs(pairs) = (node_pairs(pair) for pair in pairs) -Attributes(; kw_args...) = Attributes(Dict{Symbol, Observable}(node_pairs(kw_args))) -Attributes(pairs::Pair...) = Attributes(Dict{Symbol, Observable}(node_pairs(pairs))) -Attributes(pairs::AbstractVector) = Attributes(Dict{Symbol, Observable}(node_pairs.(pairs))) +Attributes(; kw_args...) = Attributes(Dict{Symbol,Observable}(node_pairs(kw_args))) +Attributes(pairs::Pair...) = Attributes(Dict{Symbol,Observable}(node_pairs(pairs))) +Attributes(pairs::AbstractVector) = Attributes(Dict{Symbol,Observable}(node_pairs.(pairs))) Attributes(pairs::Iterators.Pairs) = Attributes(collect(pairs)) Attributes(nt::NamedTuple) = Attributes(; nt...) attributes(x::Attributes) = getfield(x, :attributes) @@ -39,13 +41,9 @@ function Base.iterate(x::Attributes, state...) return (s[1] => x[s[1]], s[2]) end -function Base.copy(attr::Attributes) - return Attributes(copy(attributes(attr))) -end +Base.copy(attr::Attributes) = Attributes(copy(attributes(attr))) -function Base.deepcopy(obs::Observable) - return Observable{Any}(to_value(obs)) -end +Base.deepcopy(obs::Observable) = Observable{Any}(to_value(obs)) function Base.deepcopy(attributes::Attributes) result = Attributes() @@ -69,17 +67,16 @@ end Base.merge(target::Attributes, args::Attributes...) = merge!(copy(target), args...) -@generated hasfield(x::T, ::Val{key}) where {T, key} = :($(key in fieldnames(T))) +@generated hasfield(x::T, ::Val{key}) where {T,key} = :($(key in fieldnames(T))) -@inline function Base.getproperty(x::Union{Attributes, AbstractPlot}, key::Symbol) +@inline Base.getproperty(x::Union{Attributes,AbstractPlot}, key::Symbol) = if hasfield(x, Val(key)) getfield(x, key) else getindex(x, key) end -end -@inline function Base.setproperty!(x::Union{Attributes, AbstractPlot}, key::Symbol, value) +@inline function Base.setproperty!(x::Union{Attributes,AbstractPlot}, key::Symbol, value) if hasfield(x, Val(key)) setfield!(x, key, value) else @@ -94,13 +91,12 @@ function Base.getindex(x::Attributes, key::Symbol) return x[] isa Attributes ? x[] : x end -function Base.setindex!(x::Attributes, value, key::Symbol) +Base.setindex!(x::Attributes, value, key::Symbol) = if haskey(x, key) x.attributes[key][] = value else x.attributes[key] = node_any(value) end -end function Base.setindex!(x::Attributes, value::Observable, key::Symbol) if haskey(x, key) @@ -118,8 +114,7 @@ end _indent_attrs(s, n) = join(split(s, '\n'), "\n" * " "^n) -function Base.show(io::IO,::MIME"text/plain", attr::Attributes) - +function Base.show(io::IO, ::MIME"text/plain", attr::Attributes) io = IOContext(io, :compact => true) d = Dict() @@ -131,7 +126,7 @@ function Base.show(io::IO,::MIME"text/plain", attr::Attributes) print(io, ":") - ks = sort(collect(keys(attr)), by = lowercase ∘ String) + ks = sort(collect(keys(attr)), by=lowercase ∘ String) maxlength = maximum(length ∘ String, ks) for k in ks @@ -152,11 +147,11 @@ theme(x::AbstractPlot) = x.attributes isvisible(x) = haskey(x, :visible) && to_value(x[:visible]) #dict interface -const AttributeOrPlot = Union{AbstractPlot, Attributes} +const AttributeOrPlot = Union{AbstractPlot,Attributes} Base.pop!(x::AttributeOrPlot, args...) = pop!(x.attributes, args...) Base.haskey(x::AttributeOrPlot, key) = haskey(x.attributes, key) Base.delete!(x::AttributeOrPlot, key) = delete!(x.attributes, key) -function Base.get!(f::Function, x::AttributeOrPlot, key::Symbol) +Base.get!(f::Function, x::AttributeOrPlot, key::Symbol) = if haskey(x, key) return x[key] else @@ -164,10 +159,9 @@ function Base.get!(f::Function, x::AttributeOrPlot, key::Symbol) x[key] = val return x[key] end -end -Base.get!(x::AttributeOrPlot, key::Symbol, default) = get!(()-> default, x, key) +Base.get!(x::AttributeOrPlot, key::Symbol, default) = get!(() -> default, x, key) Base.get(f::Function, x::AttributeOrPlot, key::Symbol) = haskey(x, key) ? x[key] : f() -Base.get(x::AttributeOrPlot, key::Symbol, default) = get(()-> default, x, key) +Base.get(x::AttributeOrPlot, key::Symbol, default) = get(() -> default, x, key) # This is a bit confusing, since for a plot it returns the attribute from the arguments # and not a plot for integer indexing. But, we want to treat plots as "atomic" @@ -193,13 +187,13 @@ end function Base.getindex(x::AttributeOrPlot, key::Symbol, key2::Symbol, rest::Symbol...) dict = to_value(x[key]) dict isa Attributes || error("Trying to access $(typeof(dict)) with multiple keys: $key, $key2, $(rest)") - dict[key2, rest...] + return dict[key2, rest...] end function Base.setindex!(x::AttributeOrPlot, value, key::Symbol, key2::Symbol, rest::Symbol...) dict = to_value(x[key]) dict isa Attributes || error("Trying to access $(typeof(dict)) with multiple keys: $key, $key2, $(rest)") - dict[key2, rest...] = value + return dict[key2, rest...] = value end function Base.setindex!(x::AbstractPlot, value, key::Symbol) @@ -233,7 +227,7 @@ function Base.setindex!(x::AbstractPlot, value::Observable, key::Symbol) end # a few shortcut functions to make attribute conversion easier -function get_attribute(dict, key, default=nothing) +get_attribute(dict, key, default=nothing) = if haskey(dict, key) value = to_value(dict[key]) value isa Automatic && return default @@ -241,7 +235,6 @@ function get_attribute(dict, key, default=nothing) else return default end -end function merge_attributes!(input::Attributes, theme::Attributes) for (key, value) in theme @@ -259,6 +252,4 @@ function merge_attributes!(input::Attributes, theme::Attributes) return input end -function Base.propertynames(x::Union{Attributes, AbstractPlot}) - return (keys(x.attributes)...,) -end +Base.propertynames(x::Union{Attributes,AbstractPlot}) = (keys(x.attributes)...,) diff --git a/MakieCore/src/basic_plots.jl b/MakieCore/src/basic_plots.jl index 325d59d6806..7511c79d56e 100644 --- a/MakieCore/src/basic_plots.jl +++ b/MakieCore/src/basic_plots.jl @@ -9,7 +9,7 @@ calculated_attributes!(trait, plot) = nothing `calculated_attributes!(plot::AbstractPlot)` Fill in values that can only be calculated when we have all other attributes filled """ -calculated_attributes!(plot::T) where T = calculated_attributes!(T, plot) +calculated_attributes!(plot::T) where {T} = calculated_attributes!(T, plot) """ image(x, y, image) @@ -41,17 +41,17 @@ Plots an image on range `x, y` (defaults to dimensions). - `space::Symbol = :data` sets the transformation space for the position of the image. See `Makie.spaces()` for possible inputs. """ @recipe(Image, x, y, image) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - colormap = [:black, :white], - colorrange = automatic, - lowclip = automatic, - highclip = automatic, - nan_color = :transparent, - interpolate = true, - fxaa = false, - inspectable = theme(scene, :inspectable), - space = :data + colormap=[:black, :white], + colorrange=automatic, + lowclip=automatic, + highclip=automatic, + nan_color=:transparent, + interpolate=true, + fxaa=false, + inspectable=theme(scene, :inspectable), + space=:data, ) end @@ -85,19 +85,19 @@ Plots a heatmap as an image on `x, y` (defaults to interpretation as dimensions) - `space::Symbol = :data` sets the transformation space for the position of the heatmap. See `Makie.spaces()` for possible inputs. """ @recipe(Heatmap, x, y, values) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - colormap = theme(scene, :colormap), - colorrange = automatic, - lowclip = automatic, - highclip = automatic, - nan_color = :transparent, - linewidth = 0.0, - interpolate = false, - levels = 1, - fxaa = true, - inspectable = theme(scene, :inspectable), - space = :data + colormap=theme(scene, :colormap), + colorrange=automatic, + lowclip=automatic, + highclip=automatic, + nan_color=:transparent, + linewidth=0.0, + interpolate=false, + levels=1, + fxaa=true, + inspectable=theme(scene, :inspectable), + space=:data, ) end @@ -144,17 +144,17 @@ Available algorithms are: - `ssao::Bool = false` adjusts whether the plot is rendered with ssao (screen space ambient occlusion). Note that this only makes sense in 3D plots and is only applicable with `fxaa = true`. """ @recipe(Volume, x, y, z, volume) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - algorithm = :mip, - isovalue = 0.5, - isorange = 0.05, - color = nothing, - colormap = theme(scene, :colormap), - colorrange = (0, 1), - fxaa = true, - inspectable = theme(scene, :inspectable), - space = :data + algorithm=:mip, + isovalue=0.5, + isorange=0.05, + color=nothing, + colormap=theme(scene, :colormap), + colorrange=(0, 1), + fxaa=true, + inspectable=theme(scene, :inspectable), + space=:data, ) end @@ -197,20 +197,20 @@ Plots a surface, where `(x, y)` define a grid whose heights are the entries in - `ssao::Bool = false` adjusts whether the plot is rendered with ssao (screen space ambient occlusion). Note that this only makes sense in 3D plots and is only applicable with `fxaa = true`. """ @recipe(Surface, x, y, z) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - backlight = 0f0, - color = nothing, - colormap = theme(scene, :colormap), - colorrange = automatic, - lowclip = automatic, - highclip = automatic, - nan_color = :transparent, - shading = true, - fxaa = true, - invert_normals = false, - inspectable = theme(scene, :inspectable), - space = :data + backlight=0.0f0, + color=nothing, + colormap=theme(scene, :colormap), + colorrange=automatic, + lowclip=automatic, + highclip=automatic, + nan_color=:transparent, + shading=true, + fxaa=true, + invert_normals=false, + inspectable=theme(scene, :inspectable), + space=:data, ) end @@ -247,17 +247,17 @@ Creates a connected line plot for each element in `(x, y, z)`, `(x, y)` or `posi - `space::Symbol = :data` sets the transformation space for line position. See `Makie.spaces()` for possible inputs. """ @recipe(Lines, positions) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - linewidth = theme(scene, :linewidth), - color = theme(scene, :linecolor), - colormap = theme(scene, :colormap), - colorrange = automatic, - linestyle = nothing, - fxaa = false, - cycle = [:color], - inspectable = theme(scene, :inspectable), - space = :data + linewidth=theme(scene, :linewidth), + color=theme(scene, :linecolor), + colormap=theme(scene, :colormap), + colorrange=automatic, + linestyle=nothing, + fxaa=false, + cycle=[:color], + inspectable=theme(scene, :inspectable), + space=:data, ) end @@ -293,7 +293,7 @@ Plots a line for each pair of points in `(x, y, z)`, `(x, y)`, or `positions`. - `space::Symbol = :data` sets the transformation space for line position. See `Makie.spaces()` for possible inputs. """ @recipe(LineSegments, positions) do scene - default_theme(scene, Lines) + return default_theme(scene, Lines) end # alternatively, mesh3d? Or having only mesh instead of poly + mesh and figure out 2d/3d via dispatch @@ -334,21 +334,21 @@ Plots a 3D or 2D mesh. Supported `mesh_object`s include `Mesh` types from [Geome - `ssao::Bool = false` adjusts whether the plot is rendered with ssao (screen space ambient occlusion). Note that this only makes sense in 3D plots and is only applicable with `fxaa = true`. """ @recipe(Mesh, mesh) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - color = :black, - backlight = 0f0, - colormap = theme(scene, :colormap), - colorrange = automatic, - lowclip = automatic, - highclip = automatic, - nan_color = :transparent, - interpolate = true, - shading = true, - fxaa = true, - inspectable = theme(scene, :inspectable), - cycle = [:color => :patchcolor], - space = :data + color=:black, + backlight=0.0f0, + colormap=theme(scene, :colormap), + colorrange=automatic, + lowclip=automatic, + highclip=automatic, + nan_color=:transparent, + interpolate=true, + shading=true, + fxaa=true, + inspectable=theme(scene, :inspectable), + cycle=[:color => :patchcolor], + space=:data, ) end @@ -390,29 +390,27 @@ Plots a marker for each element in `(x, y, z)`, `(x, y)`, or `positions`. - `space::Symbol = :data` sets the transformation space for positions of markers. See `Makie.spaces()` for possible inputs. """ @recipe(Scatter, positions) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - color = theme(scene, :markercolor), - colormap = theme(scene, :colormap), - colorrange = automatic, - marker = theme(scene, :marker), - markersize = theme(scene, :markersize), - - strokecolor = theme(scene, :markerstrokecolor), - strokewidth = theme(scene, :markerstrokewidth), - glowcolor = (:black, 0.0), - glowwidth = 0.0, - - rotations = Billboard(), - marker_offset = automatic, - transform_marker = false, # Applies the plots transformation to marker - distancefield = nothing, - uv_offset_width = (0.0, 0.0, 0.0, 0.0), - space = :data, - markerspace = :pixel, - fxaa = false, - cycle = [:color], - inspectable = theme(scene, :inspectable) + color=theme(scene, :markercolor), + colormap=theme(scene, :colormap), + colorrange=automatic, + marker=theme(scene, :marker), + markersize=theme(scene, :markersize), + strokecolor=theme(scene, :markerstrokecolor), + strokewidth=theme(scene, :markerstrokewidth), + glowcolor=(:black, 0.0), + glowwidth=0.0, + rotations=Billboard(), + marker_offset=automatic, + transform_marker=false, # Applies the plots transformation to marker + distancefield=nothing, + uv_offset_width=(0.0, 0.0, 0.0, 0.0), + space=:data, + markerspace=:pixel, + fxaa=false, + cycle=[:color], + inspectable=theme(scene, :inspectable), ) end @@ -457,20 +455,20 @@ Plots a mesh for each element in `(x, y, z)`, `(x, y)`, or `positions` (similar - `ssao::Bool = false` adjusts whether the plot is rendered with ssao (screen space ambient occlusion). Note that this only makes sense in 3D plots and is only applicable with `fxaa = true`. """ @recipe(MeshScatter, positions) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - color = :black, - colormap = theme(scene, :colormap), - colorrange = automatic, - marker = :Sphere, - markersize = 0.1, - rotations = 0.0, - backlight = 0f0, - space = :data, - shading = true, - fxaa = true, - inspectable = theme(scene, :inspectable), - cycle = [:color], + color=:black, + colormap=theme(scene, :colormap), + colorrange=automatic, + marker=:Sphere, + markersize=0.1, + rotations=0.0, + backlight=0.0f0, + space=:data, + shading=true, + fxaa=true, + inspectable=theme(scene, :inspectable), + cycle=[:color], ) end @@ -513,24 +511,24 @@ Plots one or multiple texts passed via the `text` keyword. """ @recipe(Text, positions) do scene - Attributes(; + return Attributes(; default_theme(scene)..., - color = theme(scene, :textcolor), - font = theme(scene, :font), - fonts = theme(scene, :fonts), - strokecolor = (:black, 0.0), - strokewidth = 0, - align = (:left, :bottom), - rotation = 0.0, - fontsize = theme(scene, :fontsize), - position = (0.0, 0.0), - justification = automatic, - lineheight = 1.0, - space = :data, - markerspace = :pixel, - offset = (0.0, 0.0), - word_wrap_width = -1, - inspectable = theme(scene, :inspectable) + color=theme(scene, :textcolor), + font=theme(scene, :font), + fonts=theme(scene, :fonts), + strokecolor=(:black, 0.0), + strokewidth=0, + align=(:left, :bottom), + rotation=0.0, + fontsize=theme(scene, :fontsize), + position=(0.0, 0.0), + justification=automatic, + lineheight=1.0, + space=:data, + markerspace=:pixel, + offset=(0.0, 0.0), + word_wrap_width=-1, + inspectable=theme(scene, :inspectable), ) end @@ -577,57 +575,54 @@ Plots polygons, which are defined by - `shading = false` enables lighting. """ @recipe(Poly) do scene - Attributes(; - color = theme(scene, :patchcolor), - visible = theme(scene, :visible), - strokecolor = theme(scene, :patchstrokecolor), - colormap = theme(scene, :colormap), - colorrange = automatic, - lowclip = automatic, - highclip = automatic, - nan_color = :transparent, - strokewidth = theme(scene, :patchstrokewidth), - shading = false, - fxaa = true, - linestyle = nothing, - overdraw = false, - transparency = false, - cycle = [:color => :patchcolor], - inspectable = theme(scene, :inspectable), - space = :data + return Attributes(; + color=theme(scene, :patchcolor), + visible=theme(scene, :visible), + strokecolor=theme(scene, :patchstrokecolor), + colormap=theme(scene, :colormap), + colorrange=automatic, + lowclip=automatic, + highclip=automatic, + nan_color=:transparent, + strokewidth=theme(scene, :patchstrokewidth), + shading=false, + fxaa=true, + linestyle=nothing, + overdraw=false, + transparency=false, + cycle=[:color => :patchcolor], + inspectable=theme(scene, :inspectable), + space=:data, ) end @recipe(Wireframe) do scene # default_theme(scene, LineSegments) - Attributes(; - default_theme(scene, LineSegments)..., - depth_shift = -1f-5, - ) + return Attributes(; default_theme(scene, LineSegments)..., depth_shift=-1.0f-5) end @recipe(Arrows, points, directions) do scene attr = merge!( default_theme(scene), Attributes( - arrowhead = automatic, - arrowtail = automatic, - color = :black, - linecolor = automatic, - arrowsize = automatic, - linestyle = nothing, - align = :origin, - normalize = false, - lengthscale = 1f0, - colormap = theme(scene, :colormap), - quality = 32, - inspectable = theme(scene, :inspectable), - markerspace = :pixel, - ) + arrowhead=automatic, + arrowtail=automatic, + color=:black, + linecolor=automatic, + arrowsize=automatic, + linestyle=nothing, + align=:origin, + normalize=false, + lengthscale=1.0f0, + colormap=theme(scene, :colormap), + quality=32, + inspectable=theme(scene, :inspectable), + markerspace=:pixel, + ), ) attr[:fxaa] = automatic attr[:linewidth] = automatic # connect arrow + linecolor by default get!(attr, :arrowcolor, attr[:linecolor]) - attr + return attr end diff --git a/MakieCore/src/conversion.jl b/MakieCore/src/conversion.jl index 09ed90a6eb8..d93d20feb80 100644 --- a/MakieCore/src/conversion.jl +++ b/MakieCore/src/conversion.jl @@ -9,7 +9,7 @@ function used_attributes end abstract type ConversionTrait end -const XYBased = Union{MeshScatter, Scatter, Lines, LineSegments} +const XYBased = Union{MeshScatter,Scatter,Lines,LineSegments} struct NoConversion <: ConversionTrait end @@ -18,16 +18,16 @@ conversion_trait(::Type) = NoConversion() convert_arguments(::NoConversion, args...) = args struct PointBased <: ConversionTrait end -conversion_trait(::Type{<: XYBased}) = PointBased() -conversion_trait(::Type{<: Text}) = PointBased() +conversion_trait(::Type{<:XYBased}) = PointBased() +conversion_trait(::Type{<:Text}) = PointBased() abstract type SurfaceLike <: ConversionTrait end struct ContinuousSurface <: SurfaceLike end -conversion_trait(::Type{<: Union{Surface, Image}}) = ContinuousSurface() +conversion_trait(::Type{<:Union{Surface,Image}}) = ContinuousSurface() struct DiscreteSurface <: SurfaceLike end -conversion_trait(::Type{<: Heatmap}) = DiscreteSurface() +conversion_trait(::Type{<:Heatmap}) = DiscreteSurface() struct VolumeLike <: ConversionTrait end -conversion_trait(::Type{<: Volume}) = VolumeLike() +conversion_trait(::Type{<:Volume}) = VolumeLike() diff --git a/MakieCore/src/recipes.jl b/MakieCore/src/recipes.jl index 741ab37a169..79c82f413d4 100644 --- a/MakieCore/src/recipes.jl +++ b/MakieCore/src/recipes.jl @@ -1,25 +1,25 @@ -not_implemented_for(x) = error("Not implemented for $(x). You might want to put: `using Makie` into your code!") +function not_implemented_for(x) + return error("Not implemented for $(x). You might want to put: `using Makie` into your code!") +end to_func_name(x::Symbol) = Symbol(lowercase(string(x))) # Fallback for Combined ... # Will get overloaded by recipe Macro plotsym(x) = :plot -function func2string(func::F) where F <: Function - string(F.name.mt.name) -end +func2string(func::F) where {F<:Function} = string(F.name.mt.name) -plotfunc(::Combined{F}) where F = F -plotfunc(::Type{<: AbstractPlot{Func}}) where Func = Func -plotfunc(::T) where T <: AbstractPlot = plotfunc(T) +plotfunc(::Combined{F}) where {F} = F +plotfunc(::Type{<:AbstractPlot{Func}}) where {Func} = Func +plotfunc(::T) where {T<:AbstractPlot} = plotfunc(T) plotfunc(f::Function) = f -func2type(x::T) where T = func2type(T) -func2type(x::Type{<: AbstractPlot}) = x +func2type(x::T) where {T} = func2type(T) +func2type(x::Type{<:AbstractPlot}) = x func2type(f::Function) = Combined{f} -plotkey(::Type{<: AbstractPlot{Typ}}) where Typ = Symbol(lowercase(func2string(Typ))) -plotkey(::T) where T <: AbstractPlot = plotkey(T) +plotkey(::Type{<:AbstractPlot{Typ}}) where {Typ} = Symbol(lowercase(func2string(Typ))) +plotkey(::T) where {T<:AbstractPlot} = plotkey(T) plotkey(::Nothing) = :scatter """ @@ -30,26 +30,20 @@ The `Core.@__doc__` macro transfers the docstring given to the Recipe into the f """ function default_plot_signatures(funcname, funcname!, PlotType) quote - Core.@__doc__ function ($funcname)(args...; attributes...) - plot($PlotType, args...; attributes...) - end + Core.@__doc__ ($funcname)(args...; attributes...) = plot($PlotType, args...; attributes...) - Core.@__doc__ function ($funcname!)(args...; attributes...) - plot!($PlotType, args...; attributes...) - end + Core.@__doc__ ($funcname!)(args...; attributes...) = plot!($PlotType, args...; attributes...) end end """ Each argument can be named for a certain plot type `P`. Falls back to `arg1`, `arg2`, etc. """ -function argument_names(plot::P) where {P<:AbstractPlot} - argument_names(P, length(plot.converted)) -end +argument_names(plot::P) where {P<:AbstractPlot} = argument_names(P, length(plot.converted)) function argument_names(::Type{<:AbstractPlot}, num_args::Integer) # this is called in the indexing function, so let's be a bit efficient - ntuple(i -> Symbol("arg$i"), num_args) + return ntuple(i -> Symbol("arg$i"), num_args) end # Since we can use Combined like a scene in some circumstances, we define this alias @@ -178,15 +172,9 @@ macro recipe(theme_func, Tsym::Symbol, args::Symbol...) export $PlotType, $funcname, $funcname! end if !isempty(args) - push!( - expr.args, - :( - $(esc(:($(MakieCore).argument_names)))(::Type{<:$PlotType}, len::Integer) = - $args - ), - ) + push!(expr.args, :($(esc(:($(MakieCore).argument_names)))(::Type{<:$PlotType}, len::Integer) = $args)) end - expr + return expr end # Register plot / plot! using the Any type as PlotType. @@ -198,17 +186,11 @@ eval(default_plot_signatures(:plot, :plot!, :Any)) """ Returns the Combined type that represents the signature of `args`. """ -function Plot(args::Vararg{Any,N}) where {N} - Combined{Any,<:Tuple{args...}} -end +Plot(args::Vararg{Any,N}) where {N} = Combined{Any,<:Tuple{args...}} -Base.@pure function Plot(::Type{T}) where {T} - Combined{Any,<:Tuple{T}} -end +Base.@pure Plot(::Type{T}) where {T} = Combined{Any,<:Tuple{T}} -Base.@pure function Plot(::Type{T1}, ::Type{T2}) where {T1,T2} - Combined{Any,<:Tuple{T1,T2}} -end +Base.@pure Plot(::Type{T1}, ::Type{T2}) where {T1,T2} = Combined{Any,<:Tuple{T1,T2}} """ `plottype(plot_args...)` @@ -220,4 +202,4 @@ e.g.: plottype(x::Array{<: AbstractFloat, 3}) = Volume ``` """ -plottype(plot_args...) = Combined{Any, Tuple{typeof.(to_value.(plot_args))...}} # default to dispatch to type recipes! +plottype(plot_args...) = Combined{Any,Tuple{typeof.(to_value.(plot_args))...}} # default to dispatch to type recipes! diff --git a/MakieCore/src/types.jl b/MakieCore/src/types.jl index 3a633fcb09d..8a0931c2051 100644 --- a/MakieCore/src/types.jl +++ b/MakieCore/src/types.jl @@ -40,17 +40,17 @@ push_screen!(scene, screen) """ abstract type MakieScreen <: AbstractDisplay end -const SceneLike = Union{AbstractScene, ScenePlot} +const SceneLike = Union{AbstractScene,ScenePlot} """ Main structure for holding attributes, for theming plots etc! Will turn all values into observables, so that they can be updated. """ struct Attributes - attributes::Dict{Symbol, Observable} + attributes::Dict{Symbol,Observable} end -struct Combined{Typ, T} <: ScenePlot{Typ} +struct Combined{Typ,T} <: ScenePlot{Typ} parent::SceneLike transformation::Transformable attributes::Attributes @@ -59,15 +59,13 @@ struct Combined{Typ, T} <: ScenePlot{Typ} plots::Vector{AbstractPlot} end -function Base.show(io::IO, plot::Combined) - print(io, typeof(plot)) -end +Base.show(io::IO, plot::Combined) = print(io, typeof(plot)) Base.parent(x::AbstractPlot) = x.parent struct Key{K} end macro key_str(arg) - :(Key{$(QuoteNode(Symbol(arg)))}) + return :(Key{$(QuoteNode(Symbol(arg)))}) end Base.broadcastable(x::Key) = (x,) @@ -104,9 +102,9 @@ const px = Pixel(1) Billboard attribute to always have a primitive face the camera. Can be used for rotation. """ -struct Billboard{T <: Union{Float32, Vector{Float32}}} +struct Billboard{T<:Union{Float32,Vector{Float32}}} rotation::T end -Billboard() = Billboard(0f0) +Billboard() = Billboard(0.0f0) Billboard(angle::Real) = Billboard(Float32(angle)) Billboard(angles::Vector) = Billboard(Float32.(angles)) diff --git a/MakieCore/test/runtests.jl b/MakieCore/test/runtests.jl index 600ac535987..4268b7e61a4 100644 --- a/MakieCore/test/runtests.jl +++ b/MakieCore/test/runtests.jl @@ -12,7 +12,7 @@ end function plot!(plot::Plot(AbstractTimeseriesSolution)) # plot contains any keyword arguments that you pass to plot(series; kw...) var = get(plot, :var, Observable(5)) - density!(plot, map((v, r)-> v .* r.results, var, plot[1])) + return density!(plot, map((v, r) -> v .* r.results, var, plot[1])) end struct Test2 @@ -28,13 +28,13 @@ function plot!(plot::Plot(Test2)) scatter!(plot, arg1[].series) ser = AbstractTimeseriesSolution(arg1[].series) sol = Solution(arg1[].series) - plot!(plot, ser, var = 10) - scatter!(plot, sol, attribute = 3, color=:red) + plot!(plot, ser, var=10) + return scatter!(plot, sol, attribute=3, color=:red) end used_attributes(::Any, x::Solution) = (:attribute,) # Convert for all point based types (lines, scatter) -function convert_arguments(p::MakieCore.PointBased, x::Solution; attribute = 1.0) +function convert_arguments(p::MakieCore.PointBased, x::Solution; attribute=1.0) return convert_arguments(p, x.data .* attribute) end diff --git a/MakieRecipes/src/MakieRecipes.jl b/MakieRecipes/src/MakieRecipes.jl index 1f98310e675..ba1efbc2074 100644 --- a/MakieRecipes/src/MakieRecipes.jl +++ b/MakieRecipes/src/MakieRecipes.jl @@ -7,7 +7,6 @@ module MakieRecipes # using RecipesPipeline # using Colors - # # ## Palette # # The default palette is defined here. @@ -41,7 +40,6 @@ module MakieRecipes # tomakie(args...; attrs...) = tomakie!(Scene(), args...; attrs...) - # export tomakie, tomakie!, recipeplot, recipeplot! end diff --git a/MakieRecipes/src/attribute_table.jl b/MakieRecipes/src/attribute_table.jl index 5909ceeaff0..a592ddfb3d6 100644 --- a/MakieRecipes/src/attribute_table.jl +++ b/MakieRecipes/src/attribute_table.jl @@ -1,20 +1,20 @@ -const makie_linetype = Dict{Symbol, Any}( +const makie_linetype = Dict{Symbol,Any}( :auto => nothing, :solid => nothing, :dash => :dash, :dot => :dot, :dashdot => :dashdot, - :dashdotdot => [0.4, 0.2, 0.1, 0.2, 0.4] + :dashdotdot => [0.4, 0.2, 0.1, 0.2, 0.4], ) function makie_color(c) if color === :match return Colors.colorant"blue" end - convert(RGBA, c) + return convert(RGBA, c) end -makie_seriestype_map = Dict{Symbol, Type}( +makie_seriestype_map = Dict{Symbol,Type}( :path => Lines, :path3d => Lines, :scatter => Scatter, diff --git a/MakieRecipes/src/bezier.jl b/MakieRecipes/src/bezier.jl index bf222bd1b02..8385bfc9b21 100644 --- a/MakieRecipes/src/bezier.jl +++ b/MakieRecipes/src/bezier.jl @@ -1,30 +1,27 @@ @recipe(Bezier) do scene - merge( - default_theme(scene, Lines), - Attributes( - npoints = 30, - colorrange = automatic - ) - ) + return merge(default_theme(scene, Lines), Attributes(npoints=30, colorrange=automatic)) end -conversion_trait(::Type{<: Bezier}) = PointBased() +conversion_trait(::Type{<:Bezier}) = PointBased() -function calculated_attributes!(::Type{<: Bezier}, plot) +function calculated_attributes!(::Type{<:Bezier}, plot) color_and_colormap!(plot) pos = plot[1][] # extend one color per linesegment to be one (the same) color per vertex # taken from @edljk in PR #77 - if haskey(plot, :color) && isa(plot[:color][], AbstractVector) && iseven(length(pos)) && (length(pos) ÷ 2) == length(plot[:color][]) + if haskey(plot, :color) && + isa(plot[:color][], AbstractVector) && + iseven(length(pos)) && + (length(pos) ÷ 2) == length(plot[:color][]) plot[:color] = lift(plot[:color]) do cols - map(i-> cols[(i + 1) ÷ 2], 1:(length(cols) * 2)) + return map(i -> cols[(i + 1) ÷ 2], 1:(length(cols) * 2)) end end end # used in the pipeline too (for poly) -function from_nansep_vec(v::Vector{T}) where T +function from_nansep_vec(v::Vector{T}) where {T} idxs = findall(isnan, v) if isempty(idxs) @@ -34,7 +31,7 @@ function from_nansep_vec(v::Vector{T}) where T prev = 1 num = 1 for i in idxs - vs[num] = v[prev:i-1] + vs[num] = v[prev:(i - 1)] prev = i + 1 num += 1 @@ -49,10 +46,9 @@ function bezier_value(pts::AbstractVector, t::Real) for (i, p) in enumerate(pts) val += p * binomial(n, i - 1) * (1 - t)^(n - i + 1) * t^(i - 1) end - val + return val end - function to_bezier(p::Vector{Point2f}, npoints::Int) curves = Point2f[] @@ -78,13 +74,13 @@ function plot!(plot::Bezier) curves = lift(to_bezier, positions, npoints) - lines!( + return lines!( plot, curves; - linestyle = plot.linestyle, - linewidth = plot.linewidth, - color = plot.color, - colormap = plot.colormap, - colorrange = plot.colorrange + linestyle=plot.linestyle, + linewidth=plot.linewidth, + color=plot.color, + colormap=plot.colormap, + colorrange=plot.colorrange, ) end diff --git a/MakieRecipes/src/layout_integration.jl b/MakieRecipes/src/layout_integration.jl index 6cf6ad5206f..90297239382 100644 --- a/MakieRecipes/src/layout_integration.jl +++ b/MakieRecipes/src/layout_integration.jl @@ -1,4 +1,4 @@ function tomakie!(sc::AbstractScene, layout::Makie.GridLayout, args...; attrs...) # TODO create a finalizer for a Tuple{Scene, Layout, Vector{LAxis}} - RecipesPipeline.recipe_pipeline!(sc, Dict{Symbol, Any}(attrs), args) + return RecipesPipeline.recipe_pipeline!(sc, Dict{Symbol,Any}(attrs), args) end diff --git a/MakieRecipes/src/pipeline_integration.jl b/MakieRecipes/src/pipeline_integration.jl index acbb29b1996..2c9af9168ca 100644 --- a/MakieRecipes/src/pipeline_integration.jl +++ b/MakieRecipes/src/pipeline_integration.jl @@ -2,60 +2,56 @@ # ## Types and aliases -const PlotContext = Union{ - AbstractScene, - AbstractPlot, - MakieLayout.LAxis - } +const PlotContext = Union{AbstractScene,AbstractPlot,MakieLayout.LAxis} # ## API implementation # Define overrides for RecipesPipeline hooks. -RecipesBase.apply_recipe(plotattributes, ::Type{T}, ::PlotContext) where T = throw(MethodError("Unmatched plot type: $T")) +function RecipesBase.apply_recipe(plotattributes, ::Type{T}, ::PlotContext) where {T} + throw(MethodError("Unmatched plot type: $T")) +end # Preprocessing involves resetting the palette for now. # Later, it may involve setting up a layouting context, among other things. -function RecipesPipeline.preprocess_attributes!(plt::PlotContext, plotattributes) - plt.palette[].i[] = zero(UInt8) -end - +RecipesPipeline.preprocess_attributes!(plt::PlotContext, plotattributes) = plt.palette[].i[] = zero(UInt8) # Allow a series type to be plotted. RecipesPipeline.is_seriestype_supported(sc::PlotContext, st) = haskey(makie_seriestype_map, st) # Forward the argument preprocessing to Plots for now. -RecipesPipeline.series_defaults(sc::PlotContext, args...) = Dict{Symbol, Any}() +RecipesPipeline.series_defaults(sc::PlotContext, args...) = Dict{Symbol,Any}() # Pre-processing of user recipes function RecipesPipeline.process_userrecipe!(sc::PlotContext, kw_list, kw) if isa(get(kw, :marker_z, nothing), Function) # TODO: should this take y and/or z as arguments? - kw[:marker_z] = isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) : + kw[:marker_z] = + isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) : map(kw[:marker_z], kw[:x], kw[:y], kw[:z]) end # map line_z if it's a Function if isa(get(kw, :line_z, nothing), Function) - kw[:line_z] = isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) : - map(kw[:line_z], kw[:x], kw[:y], kw[:z]) + kw[:line_z] = + isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) : map(kw[:line_z], kw[:x], kw[:y], kw[:z]) end - push!(kw_list, kw) + return push!(kw_list, kw) end # Determine axis limits function RecipesPipeline.get_axis_limits(sc::PlotContext, f, letter) lims = to_value(data_limits(sc)) i = if letter === :x - 1 - elseif letter === :y - 2 - elseif letter === :z - 3 - else - throw(ArgumentError("Letter $letter does not correspond to an axis.")) - end + 1 + elseif letter === :y + 2 + elseif letter === :z + 3 + else + throw(ArgumentError("Letter $letter does not correspond to an axis.")) + end o = origin(lims) return (o[i], o[i] + widths(lims)[i]) @@ -66,9 +62,9 @@ end ######################################## function slice_arg(v::AbstractMatrix, idx::Int) - c = mod1(idx, size(v,2)) - m,n = axes(v) - size(v,1) == 1 ? v[first(m),n[c]] : v[:,n[c]] + c = mod1(idx, size(v, 2)) + m, n = axes(v) + return size(v, 1) == 1 ? v[first(m), n[c]] : v[:, n[c]] end # slice_arg(wrapper::Plots.InputWrapper, idx) = wrapper.obj slice_arg(v, idx) = v @@ -90,14 +86,13 @@ slice_arg(v, idx) = v Returns the Makie plot type which corresponds to the given seriestype. The plot type is returned as a Type (`Lines`, `Scatter`, ...). """ -function makie_plottype(st::Symbol) - return get(makie_seriestype_map, st, Lines) -end +makie_plottype(st::Symbol) = get(makie_seriestype_map, st, Lines) -makie_args(::Type{T}, plotattributes) where T <: AbstractPlot = makie_args(conversion_trait(T), plotattributes) +function makie_args(::Type{T}, plotattributes) where {T<:AbstractPlot} + return makie_args(conversion_trait(T), plotattributes) +end function makie_args(::PointBased, plotattributes) - x, y = (plotattributes[:x], plotattributes[:y]) if isempty(x) && isempty(y) @@ -115,9 +110,11 @@ end # TODO use Makie.plottype makie_args(::SurfaceLike, plotattributes) = (plotattributes[:x], plotattributes[:y], plotattributes[:z].surf) -makie_args(::Type{<: Contour}, plotattributes) = (plotattributes[:x], plotattributes[:y], plotattributes[:z].surf) +function makie_args(::Type{<:Contour}, plotattributes) + return (plotattributes[:x], plotattributes[:y], plotattributes[:z].surf) +end -function makie_args(::Type{<: Poly}, plotattributes) +function makie_args(::Type{<:Poly}, plotattributes) return (from_nansep_vec(Point2f.(plotattributes[:x], plotattributes[:y])),) end @@ -142,7 +139,6 @@ function translate_to_makie!(st, pa) # series color if st ∈ (:path, :path3d, :curves) - if !isnothing(get(pa, :line_z, nothing)) pa[:color] = pa[:line_z] elseif !isnothing(get(pa, :linecolor, nothing)) @@ -225,7 +221,6 @@ function translate_to_makie!(st, pa) else # some default transformations end - end ######################################## @@ -233,18 +228,21 @@ end ######################################## function set_series_color!(scene, st, plotattributes) - - has_color = (haskey(plotattributes, :color) && plotattributes[:color] !== automatic) || any( - if st ∈ (:path, :path3d, :curves) - haskey.(Ref(plotattributes), (:linecolor, :line_z, :seriescolor)) - elseif st == :scatter - haskey.(Ref(plotattributes), (:markercolor, :marker_z, :seriescolor)) - elseif st ∈ (:shape, :heatmap, :image, :surface, :contour, :bar) - haskey.(Ref(plotattributes), (:fillcolor, :fill_z, :seriescolor, :cgrad)) - else # what else? - haskey.(Ref(plotattributes), (:linecolor, :markercolor, :fillcolor, :line_z, :marker_z, :fill_z, :seriescolor)) - end - ) + has_color = + (haskey(plotattributes, :color) && plotattributes[:color] !== automatic) || any( + if st ∈ (:path, :path3d, :curves) + haskey.(Ref(plotattributes), (:linecolor, :line_z, :seriescolor)) + elseif st == :scatter + haskey.(Ref(plotattributes), (:markercolor, :marker_z, :seriescolor)) + elseif st ∈ (:shape, :heatmap, :image, :surface, :contour, :bar) + haskey.(Ref(plotattributes), (:fillcolor, :fill_z, :seriescolor, :cgrad)) + else # what else? + haskey.( + Ref(plotattributes), + (:linecolor, :markercolor, :fillcolor, :line_z, :marker_z, :fill_z, :seriescolor), + ) + end, + ) has_seriescolor = haskey(plotattributes, :seriescolor) @@ -269,27 +267,23 @@ function set_series_color!(scene, st, plotattributes) return nothing end - else # TODO FIXME DEBUG REMOVE # printstyled(st; color = :red) # println() end - if !(plot isa Union{Heatmap, Surface, Image, Spy, Axis2D, Axis3D}) - + if !(plot isa Union{Heatmap,Surface,Image,Spy,Axis2D,Axis3D}) get!(plotattributes, :seriescolor, to_color(plotattributes[:palette])) - end return nothing - end function set_palette!(plt, plotattributes) pt = get!(plotattributes, :palette, default_palette) if pt isa Palette # nothing - elseif pt isa Vector{<: Colorant} + elseif pt isa Vector{<:Colorant} plotattributes[:palette] = Palette(pt) else @warn "Palette was unrecognizable!" @@ -297,7 +291,6 @@ function set_palette!(plt, plotattributes) end function plot_series_annotations!(plt, args, pt, plotattributes) - sa = plotattributes[:series_annotations] positions = Point2f.(plotattributes[:x], plotattributes[:y]) @@ -310,12 +303,17 @@ function plot_series_annotations!(plt, args, pt, plotattributes) @debug("Series annotations say hi") - annotations!(plt, strs, positions; fontsize = fontsize/30, align = (:center, :center), color = get(plotattributes, :textcolor, :black)) - + return annotations!( + plt, + strs, + positions; + fontsize=fontsize / 30, + align=(:center, :center), + color=get(plotattributes, :textcolor, :black), + ) end function plot_annotations!(plt, args, pt, plotattributes) - sa = plotattributes[:annotations] positions = Point2f.(plotattributes[:x], plotattributes[:y]) @@ -326,8 +324,14 @@ function plot_annotations!(plt, args, pt, plotattributes) @debug("Annotations say hi") - annotations!(plt, strs, positions; fontsize = fontsizes ./ 80, align = (:center, :center), color = get(plotattributes, :textcolor, :black)) - + return annotations!( + plt, + strs, + positions; + fontsize=fontsizes ./ 80, + align=(:center, :center), + color=get(plotattributes, :textcolor, :black), + ) end function plot_fill!(plt, args, pt, plotattributes) @@ -340,7 +344,7 @@ function plot_fill!(plt, args, pt, plotattributes) c = to_color(color) bandcolor = RGBA(red(c), green(c), blue(c), alpha(c) * opacity) - band!(plt, x, upper, lower; color = bandcolor) + return band!(plt, x, upper, lower; color=bandcolor) end # Add the "series" to the Scene. @@ -385,7 +389,8 @@ function RecipesPipeline.add_series!(plt::PlotContext, plotattributes) haskey(plotattributes, :annotations) && plot_annotations!(plt, args, pt, plotattributes) - !isnothing(get(plotattributes, :series_annotations, nothing)) && plot_series_annotations!(plt, args, pt, plotattributes) + !isnothing(get(plotattributes, :series_annotations, nothing)) && + plot_series_annotations!(plt, args, pt, plotattributes) return plt end diff --git a/MakieRecipes/src/recipeplot.jl b/MakieRecipes/src/recipeplot.jl index c2ad9918bf6..c730ab1ca0c 100644 --- a/MakieRecipes/src/recipeplot.jl +++ b/MakieRecipes/src/recipeplot.jl @@ -1,14 +1,11 @@ @recipe(RecipePlot) do scene - th = merge( - default_theme(scene), - Attributes(palette = Palette(rwong)) - ) + th = merge(default_theme(scene), Attributes(palette=Palette(rwong))) th.color = automatic return th end -function plot!(p::T) where T <: RecipePlot +function plot!(p::T) where {T<:RecipePlot} # What happens here is that I want to lift on every available observable, # so they need to be splatted. This also means that nested attributes @@ -17,18 +14,21 @@ function plot!(p::T) where T <: RecipePlot # After lifting on everything, # Observable(1) is a dummy observable for dispatch. - lift(Observable(1), p.attributes, p.converted, p.converted..., values(p.attributes)...) do _, attrs, args, __lifted... - + lift( + Observable(1), + p.attributes, + p.converted, + p.converted..., + values(p.attributes)..., + ) do _, attrs, args, __lifted... !isempty(p.plots) && empty!(p.plots) - RecipesPipeline.recipe_pipeline!( + return RecipesPipeline.recipe_pipeline!( p, - Dict{Symbol, Any}(keys(attrs) .=> to_value.(values(attrs))), - to_value.(args) + Dict{Symbol,Any}(keys(attrs) .=> to_value.(values(attrs))), + to_value.(args), ) - end return nothing - end diff --git a/RPRMakie/examples/bars.jl b/RPRMakie/examples/bars.jl index 61514ecc546..67475efb0ac 100644 --- a/RPRMakie/examples/bars.jl +++ b/RPRMakie/examples/bars.jl @@ -5,8 +5,10 @@ using Colors: N0f8 RPRMakie.activate!(plugin=RPR.Northstar) fig = Figure(; resolution=(800, 600), fontsize=26) radiance = 10000 -lights = [EnvironmentLight(0.5, load(RPR.assetpath("studio026.exr"))), - PointLight(Vec3f(0, 0, 20), RGBf(radiance, radiance, radiance))] +lights = [ + EnvironmentLight(0.5, load(RPR.assetpath("studio026.exr"))), + PointLight(Vec3f(0, 0, 20), RGBf(radiance, radiance, radiance)), +] ax = LScene(fig[1, 1]; scenekw=(lights=lights,)) Makie.axis3d!(ax.scene, Rect3f(Vec3f(0), Vec3f(1, 1, 1.2))) diff --git a/RPRMakie/examples/earth_topography.jl b/RPRMakie/examples/earth_topography.jl index 7f52cc43ca2..9d6ee8ea5bb 100644 --- a/RPRMakie/examples/earth_topography.jl +++ b/RPRMakie/examples/earth_topography.jl @@ -17,21 +17,23 @@ function glow_material(data_normed) end return ( - reflection_weight = 1, - reflection_color = RGBf(0.5, 0.5, 1.0), - reflection_metalness = 0, - reflection_ior = 1.4, - diffuse_weight = 1, - emission_weight = emission_weight', - emission_color = emission_color', + reflection_weight=1, + reflection_color=RGBf(0.5, 0.5, 1.0), + reflection_metalness=0, + reflection_ior=1.4, + diffuse_weight=1, + emission_weight=emission_weight', + emission_color=emission_color', ) end RPRMakie.activate!(iterations=32, plugin=RPR.Northstar) fig = Figure(; resolution=(2000, 800)) radiance = 30000 -lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), - PointLight(Vec3f(0, 100, 100), RGBf(radiance, radiance, radiance))] +lights = [ + EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), + PointLight(Vec3f(0, 100, 100), RGBf(radiance, radiance, radiance)), +] ax = LScene(fig[1, 1]; show_axis=false, scenekw=(lights=lights,)) @@ -40,9 +42,15 @@ data_normed = ((data .- mini) ./ (maxi - mini)) material = glow_material(data_normed) -pltobj = surface!(ax, lon, lat, data_normed .* 20; - material=material, colormap=[:black, :white, :brown], - colorrange=(0.2, 0.8) .* 20) +pltobj = surface!( + ax, + lon, + lat, + data_normed .* 20; + material=material, + colormap=[:black, :white, :brown], + colorrange=(0.2, 0.8) .* 20, +) # Set the camera to a nice angle cam = cameracontrols(ax.scene) cam.eyeposition[] = Vec3f(3, -300, 300) diff --git a/RPRMakie/examples/lego.jl b/RPRMakie/examples/lego.jl index 46ac94c5f77..184520004ec 100644 --- a/RPRMakie/examples/lego.jl +++ b/RPRMakie/examples/lego.jl @@ -9,7 +9,7 @@ colors = Dict( "leg" => "#3369E8", "torso" => "#D50F25", "head" => "yellow", - "hand" => "yellow" + "hand" => "yellow", ) origins = Dict( @@ -47,15 +47,15 @@ function plot_lego_figure(s, floor=true) figure = Dict() # Plot hierarchical mesh! figure["torso"] = plot_part!(s, s, "torso") - figure["head"] = plot_part!(s, figure["torso"], "head") - figure["eyes_mouth"] = plot_part!(s, figure["head"], "eyes_mouth") - figure["arm_right"] = plot_part!(s, figure["torso"], "arm_right") - figure["hand_right"] = plot_part!(s, figure["arm_right"], "hand_right") - figure["arm_left"] = plot_part!(s, figure["torso"], "arm_left") - figure["hand_left"] = plot_part!(s, figure["arm_left"], "hand_left") - figure["belt"] = plot_part!(s, figure["torso"], "belt") - figure["leg_right"] = plot_part!(s, figure["belt"], "leg_right") - figure["leg_left"] = plot_part!(s, figure["belt"], "leg_left") + figure["head"] = plot_part!(s, figure["torso"], "head") + figure["eyes_mouth"] = plot_part!(s, figure["head"], "eyes_mouth") + figure["arm_right"] = plot_part!(s, figure["torso"], "arm_right") + figure["hand_right"] = plot_part!(s, figure["arm_right"], "hand_right") + figure["arm_left"] = plot_part!(s, figure["torso"], "arm_left") + figure["hand_left"] = plot_part!(s, figure["arm_left"], "hand_left") + figure["belt"] = plot_part!(s, figure["torso"], "belt") + figure["leg_right"] = plot_part!(s, figure["belt"], "leg_right") + figure["leg_left"] = plot_part!(s, figure["belt"], "leg_left") # lift the little guy up translate!(figure["torso"], 0, 0, 20) # add some floor @@ -67,7 +67,7 @@ RPRMakie.activate!(iterations=200, plugin=RPR.Northstar) radiance = 50000 lights = [ EnvironmentLight(1.5, rotl90(load(assetpath("sunflowers_1k.hdr"))')), - PointLight(Vec3f(50, 0, 200), RGBf(radiance, radiance, radiance*1.1)), + PointLight(Vec3f(50, 0, 200), RGBf(radiance, radiance, radiance * 1.1)), ] s = Scene(resolution=(500, 500), lights=lights) @@ -78,12 +78,12 @@ c.far[] = 1000 update_cam!(s, c, Vec3f(100, 30, 80), Vec3f(0, 0, -10)) figure = plot_lego_figure(s) -rot_joints_by = 0.25*pi +rot_joints_by = 0.25 * pi total_translation = 50 animation_strides = 10 a1 = LinRange(0, rot_joints_by, animation_strides) -angles = [a1; reverse(a1[1:end-1]); -a1[2:end]; reverse(-a1[1:end-1]);] +angles = [a1; reverse(a1[1:(end - 1)]); -a1[2:end]; reverse(-a1[1:(end - 1)])] nsteps = length(angles); #Number of animation steps translations = LinRange(0, total_translation, nsteps) @@ -93,5 +93,5 @@ Makie.record(s, "lego_walk.mp4", zip(translations, angles)) do (translation, ang for name in ["arm_left", "arm_right", "leg_left", "leg_right"] rotate!(figure[name], rotation_axes[name], angle) end - translate!(figure["torso"], translation, 0, 20) + return translate!(figure["torso"], translation, 0, 20) end diff --git a/RPRMakie/examples/materials.jl b/RPRMakie/examples/materials.jl index 65e4a92283b..2bf994a7771 100644 --- a/RPRMakie/examples/materials.jl +++ b/RPRMakie/examples/materials.jl @@ -4,8 +4,10 @@ using Colors: N0f8 image = begin radiance = 500 - lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), - PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] + lights = [ + EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), + PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1)), + ] fig = Figure(; resolution=(1500, 700)) ax = LScene(fig[1, 1]; show_axis=false, scenekw=(lights=lights,)) screen = Screen(ax.scene; plugin=RPR.Northstar, iterations=400) @@ -19,9 +21,11 @@ image = begin dielectric = RPR.DielectricBrdfX(matsys) gold = RPR.SurfaceGoldX(matsys) - materials = [glass chrome; - gold dielectric; - emissive plastic] + materials = [ + glass chrome + gold dielectric + emissive plastic + ] mesh!(ax, load(Makie.assetpath("matball_floor.obj")); color=:white) palette = reshape(Makie.default_palettes.color[][1:6], size(materials)) diff --git a/RPRMakie/examples/opengl_interop.jl b/RPRMakie/examples/opengl_interop.jl index 40a08cb4d7a..694157a5abf 100644 --- a/RPRMakie/examples/opengl_interop.jl +++ b/RPRMakie/examples/opengl_interop.jl @@ -8,16 +8,27 @@ h = (u, v) -> -cos(u - 3 * v) * (5 / 4 + sin(3 * u)); u = range(0; stop=2π, length=150) v = range(0; stop=2π, length=150) radiance = 500 -lights = [EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), - PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1))] +lights = [ + EnvironmentLight(1.0, load(RPR.assetpath("studio026.exr"))), + PointLight(Vec3f(10), RGBf(radiance, radiance, radiance * 1.1)), +] fig = Figure(; resolution=(1500, 1000)) ax = LScene(fig[1, 1]; show_axis=false, scenekw=(lights=lights,)) screen = RPRMakie.Screen(size(ax.scene); plugin=RPR.Tahoe) material = RPR.UberMaterial(screen.matsys) -surface!(ax, f.(u, v'), g.(u, v'), h.(u, v'); ambient=Vec3f(0.5), diffuse=Vec3f(1), specular=0.5, - colormap=:balance, material=material) +surface!( + ax, + f.(u, v'), + g.(u, v'), + h.(u, v'); + ambient=Vec3f(0.5), + diffuse=Vec3f(1), + specular=0.5, + colormap=:balance, + material=material, +) function Input(fig, val::RGB) hue = Slider(fig; range=1:380, width=200) @@ -42,18 +53,30 @@ function Input(fig, val::Bool) return toggle.active, toggle end -sliders = (reflection_color=Input(fig, RGB(0, 0, 0)), reflection_weight=Input(fig, Vec4(0)), - reflection_roughness=Input(fig, Vec4(0)), reflection_anisotropy=Input(fig, Vec4(0)), - reflection_anisotropy_rotation=Input(fig, Vec4(0)), reflection_mode=Input(fig, Vec4(0)), - reflection_ior=Input(fig, Vec4(0)), reflection_metalness=Input(fig, Vec4(0)), - refraction_color=Input(fig, RGB(0, 0, 0)), refraction_weight=Input(fig, Vec4(0)), - refraction_roughness=Input(fig, Vec4(0)), refraction_ior=Input(fig, Vec4(0)), - refraction_absorption_color=Input(fig, RGB(0, 0, 0)), - refraction_absorption_distance=Input(fig, Vec4(0)), refraction_caustics=Input(fig, true), - sss_scatter_color=Input(fig, RGB(0, 0, 0)), sss_scatter_distance=Input(fig, Vec4(0)), - sss_scatter_direction=Input(fig, Vec4(0)), sss_weight=Input(fig, Vec4(0)), - sss_multiscatter=Input(fig, false), backscatter_weight=Input(fig, Vec4(0)), - backscatter_color=Input(fig, RGB(0, 0, 0))) +sliders = ( + reflection_color=Input(fig, RGB(0, 0, 0)), + reflection_weight=Input(fig, Vec4(0)), + reflection_roughness=Input(fig, Vec4(0)), + reflection_anisotropy=Input(fig, Vec4(0)), + reflection_anisotropy_rotation=Input(fig, Vec4(0)), + reflection_mode=Input(fig, Vec4(0)), + reflection_ior=Input(fig, Vec4(0)), + reflection_metalness=Input(fig, Vec4(0)), + refraction_color=Input(fig, RGB(0, 0, 0)), + refraction_weight=Input(fig, Vec4(0)), + refraction_roughness=Input(fig, Vec4(0)), + refraction_ior=Input(fig, Vec4(0)), + refraction_absorption_color=Input(fig, RGB(0, 0, 0)), + refraction_absorption_distance=Input(fig, Vec4(0)), + refraction_caustics=Input(fig, true), + sss_scatter_color=Input(fig, RGB(0, 0, 0)), + sss_scatter_distance=Input(fig, Vec4(0)), + sss_scatter_direction=Input(fig, Vec4(0)), + sss_weight=Input(fig, Vec4(0)), + sss_multiscatter=Input(fig, false), + backscatter_weight=Input(fig, Vec4(0)), + backscatter_color=Input(fig, RGB(0, 0, 0)), +) labels = [] inputs = [] diff --git a/RPRMakie/examples/sea_cables.jl b/RPRMakie/examples/sea_cables.jl index 4c9a6b14a0f..5e4bab86ad1 100644 --- a/RPRMakie/examples/sea_cables.jl +++ b/RPRMakie/examples/sea_cables.jl @@ -23,7 +23,7 @@ toLines = GeoInterface.coordinates.(GeoInterface.geometry.(feat)) # be the same line and be in the same array. # some 3D transformations -function toCartesian(lon, lat; r = 1.02, cxyz = (0, 0, 0)) +function toCartesian(lon, lat; r=1.02, cxyz=(0, 0, 0)) x = cxyz[1] + r * cosd(lat) * cosd(lon) y = cxyz[2] + r * cosd(lat) * sind(lon) z = cxyz[3] + r * sind(lat) @@ -46,14 +46,20 @@ for i in 1:length(toLines) end end -earth_img = load(Downloads.download("https://upload.wikimedia.org/wikipedia/commons/5/56/Blue_Marble_Next_Generation_%2B_topography_%2B_bathymetry.jpg")) +earth_img = load( + Downloads.download( + "https://upload.wikimedia.org/wikipedia/commons/5/56/Blue_Marble_Next_Generation_%2B_topography_%2B_bathymetry.jpg", + ), +) # the actual plot ! RPRMakie.activate!(; iterations=100) scene = with_theme(theme_dark()) do fig = Figure(; resolution=(1000, 1000)) radiance = 30 - lights = [EnvironmentLight(0.5, load(RPR.assetpath("starmap_4k.tif"))), - PointLight(Vec3f(1, 1, 3), RGBf(radiance, radiance, radiance))] + lights = [ + EnvironmentLight(0.5, load(RPR.assetpath("starmap_4k.tif"))), + PointLight(Vec3f(1, 1, 3), RGBf(radiance, radiance, radiance)), + ] ax = LScene(fig[1, 1]; show_axis=false, scenekw=(lights=lights,)) n = 1024 ÷ 4 # 2048 θ = LinRange(0, pi, n) diff --git a/RPRMakie/src/RPRMakie.jl b/RPRMakie/src/RPRMakie.jl index b3ddead9794..3b15fec02c5 100644 --- a/RPRMakie/src/RPRMakie.jl +++ b/RPRMakie/src/RPRMakie.jl @@ -30,7 +30,7 @@ function ScreenConfig(iterations::Int, max_recursion::Int, render_resource, rend iterations, max_recursion, render_resource isa Makie.Automatic ? RPR.RPR_CREATION_FLAGS_ENABLE_GPU0 : render_resource, - render_plugin isa Makie.Automatic ? RPR.Tahoe : render_plugin + render_plugin isa Makie.Automatic ? RPR.Tahoe : render_plugin, ) end diff --git a/RPRMakie/src/lines.jl b/RPRMakie/src/lines.jl index 467ce80572e..bdc14ad16fb 100644 --- a/RPRMakie/src/lines.jl +++ b/RPRMakie/src/lines.jl @@ -3,7 +3,7 @@ function line2segments(points) indices = RPR.rpr_int[] count = 0 for i in 1:npoints - push!(indices, i - 1) + push!(indices, i - 1) count += 1 if count == 4 && !(i == npoints) push!(indices, i - 1) @@ -55,8 +55,14 @@ function to_rpr_object(context, matsys, scene, plot::Makie.LineSegments) fill(Float32(plot.linewidth[] / 1000), nsegments) end - curve = RPR.Curve(context, points, indices, radius, Vec2f.(0.0, LinRange(0, 1, nsegments)), - fill(1, nsegments)) + curve = RPR.Curve( + context, + points, + indices, + radius, + Vec2f.(0.0, LinRange(0, 1, nsegments)), + fill(1, nsegments), + ) material = RPR.DiffuseMaterial(matsys) color = to_color(plot.color[]) @@ -73,7 +79,11 @@ function to_rpr_object(context, matsys, scene, plot::Makie.LineSegments) if color isa AbstractVector{<:Colorant} set_color!(copy(color)) elseif color isa AbstractVector{<:Number} - sampler = Makie.sampler(to_colormap(plot.colormap[]), color; scaling=Makie.Scaling(identity, plot.colorrange[])) + sampler = Makie.sampler( + to_colormap(plot.colormap[]), + color; + scaling=Makie.Scaling(identity, plot.colorrange[]), + ) set_color!(collect(sampler)) else material.color = to_color(color) diff --git a/RPRMakie/src/meshes.jl b/RPRMakie/src/meshes.jl index 5f67806d33a..7a1deb9ad75 100644 --- a/RPRMakie/src/meshes.jl +++ b/RPRMakie/src/meshes.jl @@ -1,7 +1,7 @@ function extract_material(matsys, plot) material = if haskey(plot, :material) if plot.material isa Attributes - return RPR.Material(matsys, Dict(map(((k,v),)-> k => to_value(v), plot.material))) + return RPR.Material(matsys, Dict(map(((k, v),) -> k => to_value(v), plot.material))) else return plot.material[] end @@ -10,7 +10,7 @@ function extract_material(matsys, plot) end end -function mesh_material(context, matsys, plot, color_obs = plot.color) +function mesh_material(context, matsys, plot, color_obs=plot.color) specular = plot.specular[] shininess = plot.shininess[] color = to_value(color_obs) @@ -53,13 +53,12 @@ function to_rpr_object(context, matsys, scene, plot::Makie.Mesh) rpr_mesh = RPR.Shape(context, to_value(plot[1])) material = mesh_material(context, matsys, plot) map(plot.model) do m - RPR.transform!(rpr_mesh, m) + return RPR.transform!(rpr_mesh, m) end set!(rpr_mesh, material) return rpr_mesh end - function to_rpr_object(context, matsys, scene, plot::Makie.MeshScatter) # Potentially per instance attributes positions = to_value(plot[1]) @@ -70,7 +69,7 @@ function to_rpr_object(context, matsys, scene, plot::Makie.MeshScatter) RPR.rprShapeSetObjectID(marker, 0) material = if haskey(plot, :material) if plot.material isa Attributes - RPR.Material(matsys, Dict(map(((k,v),)-> k => to_value(v), plot.material))) + RPR.Material(matsys, Dict(map(((k, v),) -> k => to_value(v), plot.material))) else plot.material[] end @@ -78,7 +77,7 @@ function to_rpr_object(context, matsys, scene, plot::Makie.MeshScatter) RPR.DiffuseMaterial(matsys) end set!(marker, material) - for i in 1:(n_instances-1) + for i in 1:(n_instances - 1) inst = RPR.Shape(context, marker) RPR.rprShapeSetObjectID(inst, i) push!(instances, inst) @@ -93,9 +92,9 @@ function to_rpr_object(context, matsys, scene, plot::Makie.MeshScatter) object_id = RPR.InputLookupMaterial(matsys) object_id.value = RPR.RPR_MATERIAL_NODE_LOOKUP_OBJECT_ID - uv = object_id * Vec3f(0, 1/n_instances, 0) + uv = object_id * Vec3f(0, 1 / n_instances, 0) - tex = RPR.Texture(matsys, collect(color_from_num'); uv = uv) + tex = RPR.Texture(matsys, collect(color_from_num'); uv=uv) material.color = tex elseif color isa Colorant @@ -128,7 +127,6 @@ function to_rpr_object(context, matsys, scene, plot::Makie.MeshScatter) return instances end - function to_rpr_object(context, matsys, scene, plot::Makie.Surface) x = plot[1] y = plot[2] @@ -161,12 +159,7 @@ function to_rpr_object(context, matsys, scene, plot::Makie.Surface) end @recipe(Matball, material) do scene - return Attributes( - base = Makie.automatic, - inner = Makie.automatic, - outer = Makie.automatic, - color = :blue - ) + return Attributes(base=Makie.automatic, inner=Makie.automatic, outer=Makie.automatic, color=:blue) end function Makie.plot!(plot::Matball) diff --git a/RPRMakie/src/scene.jl b/RPRMakie/src/scene.jl index 20ea24b3067..60694621264 100644 --- a/RPRMakie/src/scene.jl +++ b/RPRMakie/src/scene.jl @@ -14,7 +14,7 @@ function update_rpr_camera!(oldvals, camera, cam_controls, cam) RPR.rprCameraSetFarPlane(camera, far) RPR.rprCameraSetNearPlane(camera, near) h = norm(res) - RPR.rprCameraSetFocalLength(camera, (30*h)/fov) + RPR.rprCameraSetFocalLength(camera, (30 * h) / fov) # RPR_CAMERA_FSTOP # RPR_CAMERA_MODE return new_vals @@ -30,7 +30,7 @@ function insert_plots!(context, matsys, scene, mscene::Makie.Scene, @nospecializ object = to_rpr_object(context, matsys, mscene, plot) if !isnothing(object) if object isa AbstractVector - foreach(x-> push!(scene, x), object) + foreach(x -> push!(scene, x), object) else push!(scene, object) end @@ -45,10 +45,10 @@ end function to_rpr_light(context::RPR.Context, light::Makie.PointLight) pointlight = RPR.PointLight(context) map(light.position) do pos - transform!(pointlight, Makie.translationmatrix(pos)) + return transform!(pointlight, Makie.translationmatrix(pos)) end map(light.radiance) do r - setradiantpower!(pointlight, red(r), green(r), blue(r)) + return setradiantpower!(pointlight, red(r), green(r), blue(r)) end return pointlight end @@ -67,13 +67,13 @@ function to_rpr_light(context::RPR.Context, light::Makie.EnvironmentLight) set!(env_light, last_img) setintensityscale!(env_light, light.intensity[]) on(light.intensity) do i - setintensityscale!(env_light, i) + return setintensityscale!(env_light, i) end on(light.image) do img new_img = RPR.Image(context, img) set!(env_light, new_img) RPR.release(last_img) - last_img = new_img + return last_img = new_img end return env_light end @@ -83,7 +83,7 @@ function to_rpr_scene(context::RPR.Context, matsys, mscene::Makie.Scene) set!(context, scene) # Only set background image if it isn't set by env light, since # background image takes precedence - if !any(x-> x isa Makie.EnvironmentLight, mscene.lights) + if !any(x -> x isa Makie.EnvironmentLight, mscene.lights) env_img = fill(to_color(mscene.backgroundcolor[]), 1, 1) img = RPR.Image(context, env_img) RPR.rprSceneSetBackgroundImage(scene, img) @@ -135,12 +135,11 @@ function replace_scene_rpr!(scene::Makie.Scene, screen=Screen(scene); refresh=Ob end data = RPR.get_data(framebuffer2) im[1] = reverse(reshape(data, screen.fb_size); dims=2) - sleep(1/10) + sleep(1 / 10) end return context, task, rpr_scene end - """ Screen(args...; screen_config...) @@ -157,10 +156,10 @@ mutable struct Screen <: Makie.MakieScreen matsys::RPR.MaterialSystem framebuffer1::RPR.FrameBuffer framebuffer2::RPR.FrameBuffer - fb_size::Tuple{Int, Int} - scene::Union{Nothing, Scene} + fb_size::Tuple{Int,Int} + scene::Union{Nothing,Scene} setup_scene::Bool - rpr_scene::Union{Nothing, RPR.Scene} + rpr_scene::Union{Nothing,RPR.Scene} iterations::Int cleared::Bool end @@ -169,7 +168,7 @@ Base.size(screen::Screen) = screen.fb_size function Base.show(io::IO, ::MIME"image/png", screen::Screen) img = colorbuffer(screen) - FileIO.save(FileIO.Stream{FileIO.format"PNG"}(Makie.raw_io(io)), img) + return FileIO.save(FileIO.Stream{FileIO.format"PNG"}(Makie.raw_io(io)), img) end function Makie.apply_screen_config!(screen::Screen, config::ScreenConfig) @@ -205,9 +204,17 @@ function Screen(fb_size::NTuple{2,<:Integer}, config::ScreenConfig) framebuffer2 = RPR.FrameBuffer(context, RGBA, fb_size) set!(context, RPR.RPR_AOV_COLOR, framebuffer1) return Screen( - context, matsys, framebuffer1, framebuffer2, fb_size, - nothing, false, nothing, - config.iterations, false) + context, + matsys, + framebuffer1, + framebuffer2, + fb_size, + nothing, + false, + nothing, + config.iterations, + false, + ) end function render(screen; clear=true, iterations=screen.iterations) @@ -242,7 +249,7 @@ function Makie.colorbuffer(screen::Screen) r = reverse(reshape(data_1d, screen.fb_size), dims=2) img = rotl90(r) return map(img) do color - RGB{Colors.N0f8}(mapc(x-> clamp(x, 0, 1), color)) + return RGB{Colors.N0f8}(mapc(x -> clamp(x, 0, 1), color)) end end @@ -267,4 +274,4 @@ function Base.insert!(screen::Screen, scene::Scene, plot::AbstractPlot) return screen end -Makie.backend_showable(::Type{Screen}, ::Union{MIME"image/jpeg", MIME"image/png"}) = true +Makie.backend_showable(::Type{Screen}, ::Union{MIME"image/jpeg",MIME"image/png"}) = true diff --git a/RPRMakie/test/lines.jl b/RPRMakie/test/lines.jl index e36c4698486..d7191dd7002 100644 --- a/RPRMakie/test/lines.jl +++ b/RPRMakie/test/lines.jl @@ -18,7 +18,7 @@ begin n = i + 1 y = LinRange(0, i, n) y2 = (y ./ 2) .- 2 - lines!(ax, fill((i-5) ./ 2, n), y2, sin.(y) .+ 1, linewidth=5) + lines!(ax, fill((i - 5) ./ 2, n), y2, sin.(y) .+ 1, linewidth=5) end mesh!(ax, Rect3f(Vec3f(-3, -3, -0.1), Vec3f(6, 6, 0.1)), color=:white) mesh!(ax, Sphere(Point3f(0, 0, 2), 0.1), material=emissive) @@ -31,42 +31,41 @@ begin end begin - - uber1.color =Vec4f(1, 1, 1, 1) - uber1.diffuse_weight =Vec4f(0, 0, 0, 0) - uber1.diffuse_roughness =Vec4f(1, 1, 1, 1) - uber1.reflection_color =Vec4f(0.996078, 0.858824, 0.639216, 0) - uber1.reflection_weight =Vec4f(1, 1, 1, 1) - uber1.reflection_roughness =Vec4f(0, 0, 0, 0) - uber1.reflection_anisotropy =Vec4f(0, 0, 0, 0) - uber1.reflection_anisotropy_rotation =Vec4f(0, 0, 0, 0) - uber1.reflection_ior =Vec4f(1.36, 1.36, 1.36, 1.36) - uber1.refraction_color =Vec4f(0.996078, 0.858824, 0.639216, 0) - uber1.refraction_weight =Vec4f(1, 1, 1, 1) - uber1.refraction_roughness =Vec4f(0, 0, 0, 0) - uber1.refraction_ior =Vec4f(1.36, 1.36, 1.36, 1.36) - uber1.refraction_absorption_color =Vec4f(0.996078, 0.858824, 0.639216, 0) - uber1.refraction_absorption_distance =Vec4f(0, 0, 0, 0) - uber1.refraction_caustics =Vec4f(0) - uber1.coating_color =Vec4f(1, 1, 1, 1) - uber1.coating_weight =Vec4f(0, 0, 0, 0) - uber1.coating_roughness =Vec4f(0, 0, 0, 0) - uber1.coating_ior =Vec4f(3, 3, 3, 3) - uber1.coating_metalness =Vec4f(0, 0, 0, 0) - uber1.coating_transmission_color =Vec4f(1, 1, 1, 1) - uber1.coating_thickness =Vec4f(0, 0, 0, 0) - uber1.sheen =Vec4f(1, 1, 1, 1) - uber1.sheen_tint =Vec4f(0, 0, 0, 0) - uber1.sheen_weight =Vec4f(0, 0, 0, 0) - uber1.emission_color =Vec4f(1, 1, 1, 1) - uber1.emission_weight =Vec3f( 0, 0, 0) - uber1.transparency =Vec4f(0, 0, 0, 0) - uber1.sss_scatter_color =Vec4f(0, 0, 0, 0) - uber1.sss_scatter_distance =Vec4f(0, 0, 0, 0) - uber1.sss_scatter_direction =Vec4f(0, 0, 0, 0) - uber1.sss_weight =Vec4f(0, 0, 0, 0) - uber1.backscatter_weight =Vec4f(0, 0, 0, 0) - uber1.backscatter_color =Vec4f(1, 1, 1, 1) + uber1.color = Vec4f(1, 1, 1, 1) + uber1.diffuse_weight = Vec4f(0, 0, 0, 0) + uber1.diffuse_roughness = Vec4f(1, 1, 1, 1) + uber1.reflection_color = Vec4f(0.996078, 0.858824, 0.639216, 0) + uber1.reflection_weight = Vec4f(1, 1, 1, 1) + uber1.reflection_roughness = Vec4f(0, 0, 0, 0) + uber1.reflection_anisotropy = Vec4f(0, 0, 0, 0) + uber1.reflection_anisotropy_rotation = Vec4f(0, 0, 0, 0) + uber1.reflection_ior = Vec4f(1.36, 1.36, 1.36, 1.36) + uber1.refraction_color = Vec4f(0.996078, 0.858824, 0.639216, 0) + uber1.refraction_weight = Vec4f(1, 1, 1, 1) + uber1.refraction_roughness = Vec4f(0, 0, 0, 0) + uber1.refraction_ior = Vec4f(1.36, 1.36, 1.36, 1.36) + uber1.refraction_absorption_color = Vec4f(0.996078, 0.858824, 0.639216, 0) + uber1.refraction_absorption_distance = Vec4f(0, 0, 0, 0) + uber1.refraction_caustics = Vec4f(0) + uber1.coating_color = Vec4f(1, 1, 1, 1) + uber1.coating_weight = Vec4f(0, 0, 0, 0) + uber1.coating_roughness = Vec4f(0, 0, 0, 0) + uber1.coating_ior = Vec4f(3, 3, 3, 3) + uber1.coating_metalness = Vec4f(0, 0, 0, 0) + uber1.coating_transmission_color = Vec4f(1, 1, 1, 1) + uber1.coating_thickness = Vec4f(0, 0, 0, 0) + uber1.sheen = Vec4f(1, 1, 1, 1) + uber1.sheen_tint = Vec4f(0, 0, 0, 0) + uber1.sheen_weight = Vec4f(0, 0, 0, 0) + uber1.emission_color = Vec4f(1, 1, 1, 1) + uber1.emission_weight = Vec3f(0, 0, 0) + uber1.transparency = Vec4f(0, 0, 0, 0) + uber1.sss_scatter_color = Vec4f(0, 0, 0, 0) + uber1.sss_scatter_distance = Vec4f(0, 0, 0, 0) + uber1.sss_scatter_direction = Vec4f(0, 0, 0, 0) + uber1.sss_weight = Vec4f(0, 0, 0, 0) + uber1.backscatter_weight = Vec4f(0, 0, 0, 0) + uber1.backscatter_color = Vec4f(1, 1, 1, 1) uber1.reflection_mode = UInt(RPR.RPR_UBER_MATERIAL_IOR_MODE_PBR) uber1.emission_mode = UInt(RPR.RPR_UBER_MATERIAL_EMISSION_MODE_SINGLESIDED) @@ -75,133 +74,131 @@ begin uber1.refraction_thin_surface = false end - begin - uber2.color = Vec4f(0.501961f0,0.0f0,0.0f0,0.0f0) - uber2.diffuse_weight = Vec4f(1.0f0,1.0f0,1.0f0,1.0f0) - uber2.diffuse_roughness = Vec4f(0.500000f0,0.500000f0,0.500000f0,0.500000f0) - uber2.reflection_color = Vec4f(0.490196f0,0.490196f0,0.490196f0,0.0f0) - uber2.reflection_weight = Vec4f(0.990000f0,0.990000f0,0.990000f0,0.990000f0) - uber2.reflection_roughness = Vec4f(0.008000f0,0.008000f0,0.008000f0,0.008000f0) - uber2.reflection_anisotropy = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.reflection_anisotropy_rotation = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) + uber2.color = Vec4f(0.501961f0, 0.0f0, 0.0f0, 0.0f0) + uber2.diffuse_weight = Vec4f(1.0f0, 1.0f0, 1.0f0, 1.0f0) + uber2.diffuse_roughness = Vec4f(0.500000f0, 0.500000f0, 0.500000f0, 0.500000f0) + uber2.reflection_color = Vec4f(0.490196f0, 0.490196f0, 0.490196f0, 0.0f0) + uber2.reflection_weight = Vec4f(0.990000f0, 0.990000f0, 0.990000f0, 0.990000f0) + uber2.reflection_roughness = Vec4f(0.008000f0, 0.008000f0, 0.008000f0, 0.008000f0) + uber2.reflection_anisotropy = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.reflection_anisotropy_rotation = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) uber2.reflection_mode = 1 - uber2.reflection_ior = Vec4f(1.460000f0,1.460000f0,1.460000f0,1.460000f0) - uber2.refraction_color = Vec4f(1.0f0,1.0f0,1.0f0,1.0f0) - uber2.refraction_weight = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.refraction_roughness = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.refraction_ior = Vec4f(1.500000f0,1.500000f0,1.500000f0,1.500000f0) + uber2.reflection_ior = Vec4f(1.460000f0, 1.460000f0, 1.460000f0, 1.460000f0) + uber2.refraction_color = Vec4f(1.0f0, 1.0f0, 1.0f0, 1.0f0) + uber2.refraction_weight = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.refraction_roughness = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.refraction_ior = Vec4f(1.500000f0, 1.500000f0, 1.500000f0, 1.500000f0) uber2.refraction_thin_surface = Vec4f(0) - uber2.refraction_absorption_color = Vec4f(1.0f0,1.0f0,1.0f0,0.0f0) - uber2.refraction_absorption_distance = Vec4f(1.0f0,1.0f0,1.0f0,0.0f0) + uber2.refraction_absorption_color = Vec4f(1.0f0, 1.0f0, 1.0f0, 0.0f0) + uber2.refraction_absorption_distance = Vec4f(1.0f0, 1.0f0, 1.0f0, 0.0f0) uber2.refraction_caustics = 1 - uber2.coating_color = Vec4f(0.490196f0,0.490196f0,0.490196f0,0.0f0) - uber2.coating_weight = Vec4f(1.0f0,1.0f0,1.0f0,1.0f0) - uber2.coating_roughness = Vec4f(0.008000f0,0.008000f0,0.008000f0,0.008000f0) + uber2.coating_color = Vec4f(0.490196f0, 0.490196f0, 0.490196f0, 0.0f0) + uber2.coating_weight = Vec4f(1.0f0, 1.0f0, 1.0f0, 1.0f0) + uber2.coating_roughness = Vec4f(0.008000f0, 0.008000f0, 0.008000f0, 0.008000f0) uber2.coating_mode = 1 - uber2.coating_ior = Vec4f(1.460000f0,1.460000f0,1.460000f0,1.460000f0) - uber2.coating_metalness = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.coating_transmission_color = Vec4f(0.0f0,0.0f0,0.0f0,1.0f0) - uber2.coating_thickness = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.sheen = Vec4f(1.0f0,1.0f0,1.0f0,1.0f0) - uber2.sheen_tint = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.sheen_weight = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.emission_color = Vec4f(1.0f0,1.0f0,1.0f0,1.0f0) - uber2.emission_weight = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) + uber2.coating_ior = Vec4f(1.460000f0, 1.460000f0, 1.460000f0, 1.460000f0) + uber2.coating_metalness = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.coating_transmission_color = Vec4f(0.0f0, 0.0f0, 0.0f0, 1.0f0) + uber2.coating_thickness = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.sheen = Vec4f(1.0f0, 1.0f0, 1.0f0, 1.0f0) + uber2.sheen_tint = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.sheen_weight = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.emission_color = Vec4f(1.0f0, 1.0f0, 1.0f0, 1.0f0) + uber2.emission_weight = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) uber2.emission_mode = 1 - uber2.transparency = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.sss_scatter_color = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.sss_scatter_distance = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.sss_scatter_direction = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.sss_weight = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) + uber2.transparency = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.sss_scatter_color = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.sss_scatter_distance = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.sss_scatter_direction = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.sss_weight = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) uber2.sss_multiscatter = false - uber2.backscatter_weight = Vec4f(0.0f0,0.0f0,0.0f0,0.0f0) - uber2.backscatter_color = Vec4f(0.501961f0,0.0f0,0.0f0,0.0f0) + uber2.backscatter_weight = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + uber2.backscatter_color = Vec4f(0.501961f0, 0.0f0, 0.0f0, 0.0f0) end begin - uber3.color = Vec4(0.752941,0.596078,0.443137,0.0) - uber3.diffuse_weight = Vec4(1.0,1.0,1.0,1.0) - uber3.diffuse_roughness = Vec4(0.500000,0.500000,0.500000,0.500000) - uber3.reflection_color = Vec4(0.666667,0.490196,0.313726,0.0) - uber3.reflection_weight = Vec4(1.0,1.0,1.0,1.0) - uber3.reflection_roughness = Vec4(0.300000,0.300000,0.300000,0.300000) - uber3.reflection_anisotropy = Vec4(0.0,0.0,0.0,0.0) - uber3.reflection_anisotropy_rotation = Vec4(0.0,0.0,0.0,0.0) + uber3.color = Vec4(0.752941, 0.596078, 0.443137, 0.0) + uber3.diffuse_weight = Vec4(1.0, 1.0, 1.0, 1.0) + uber3.diffuse_roughness = Vec4(0.500000, 0.500000, 0.500000, 0.500000) + uber3.reflection_color = Vec4(0.666667, 0.490196, 0.313726, 0.0) + uber3.reflection_weight = Vec4(1.0, 1.0, 1.0, 1.0) + uber3.reflection_roughness = Vec4(0.300000, 0.300000, 0.300000, 0.300000) + uber3.reflection_anisotropy = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.reflection_anisotropy_rotation = Vec4(0.0, 0.0, 0.0, 0.0) uber3.reflection_mode = 2 - uber3.reflection_ior = Vec4(1.0,1.0,1.0,1.0) - uber3.refraction_color = Vec4(1.0,1.0,1.0,1.0) - uber3.refraction_weight = Vec4(0.0,0.0,0.0,0.0) - uber3.refraction_roughness = Vec4(0.0,0.0,0.0,0.0) - uber3.refraction_ior = Vec4(1.500000,1.500000,1.500000,1.500000) + uber3.reflection_ior = Vec4(1.0, 1.0, 1.0, 1.0) + uber3.refraction_color = Vec4(1.0, 1.0, 1.0, 1.0) + uber3.refraction_weight = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.refraction_roughness = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.refraction_ior = Vec4(1.500000, 1.500000, 1.500000, 1.500000) uber3.refraction_thin_surface = 0 - uber3.refraction_absorption_color = Vec4(1.0,1.0,1.0,0.0) - uber3.refraction_absorption_distance = Vec4(1.0,1.0,1.0,0.0) + uber3.refraction_absorption_color = Vec4(1.0, 1.0, 1.0, 0.0) + uber3.refraction_absorption_distance = Vec4(1.0, 1.0, 1.0, 0.0) uber3.refraction_caustics = 1 - uber3.coating_color = Vec4(0.752941,0.596078,0.443137,0.0) - uber3.coating_weight = Vec4(1.0,1.0,1.0,1.0) - uber3.coating_roughness = Vec4(0.420000,0.420000,0.420000,0.420000) + uber3.coating_color = Vec4(0.752941, 0.596078, 0.443137, 0.0) + uber3.coating_weight = Vec4(1.0, 1.0, 1.0, 1.0) + uber3.coating_roughness = Vec4(0.420000, 0.420000, 0.420000, 0.420000) uber3.coating_mode = 1 - uber3.coating_ior = Vec4(1.700000,1.700000,1.700000,1.700000) - uber3.coating_metalness = Vec4(0.0,0.0,0.0,0.0) - uber3.coating_transmission_color = Vec4(0.0,0.0,0.0,1.0) - uber3.coating_thickness = Vec4(0.0,0.0,0.0,0.0) - uber3.sheen = Vec4(1.0,1.0,1.0,1.0) - uber3.sheen_tint = Vec4(0.0,0.0,0.0,0.0) - uber3.sheen_weight = Vec4(0.0,0.0,0.0,0.0) - uber3.emission_color = Vec4(1.0,1.0,1.0,1.0) - uber3.emission_weight = Vec4(0.0,0.0,0.0,0.0) + uber3.coating_ior = Vec4(1.700000, 1.700000, 1.700000, 1.700000) + uber3.coating_metalness = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.coating_transmission_color = Vec4(0.0, 0.0, 0.0, 1.0) + uber3.coating_thickness = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.sheen = Vec4(1.0, 1.0, 1.0, 1.0) + uber3.sheen_tint = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.sheen_weight = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.emission_color = Vec4(1.0, 1.0, 1.0, 1.0) + uber3.emission_weight = Vec4(0.0, 0.0, 0.0, 0.0) uber3.emission_mode = 1 - uber3.transparency = Vec4(0.0,0.0,0.0,0.0) - uber3.sss_scatter_color = Vec4(0.0,0.0,0.0,0.0) - uber3.sss_scatter_distance = Vec4(0.0,0.0,0.0,0.0) - uber3.sss_scatter_direction = Vec4(0.0,0.0,0.0,0.0) - uber3.sss_weight = Vec4(0.0,0.0,0.0,0.0) + uber3.transparency = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.sss_scatter_color = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.sss_scatter_distance = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.sss_scatter_direction = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.sss_weight = Vec4(0.0, 0.0, 0.0, 0.0) uber3.sss_multiscatter = 0 - uber3.backscatter_weight = Vec4(0.0,0.0,0.0,0.0) - uber3.backscatter_color = Vec4(0.752941,0.596078,0.443137,0.0) + uber3.backscatter_weight = Vec4(0.0, 0.0, 0.0, 0.0) + uber3.backscatter_color = Vec4(0.752941, 0.596078, 0.443137, 0.0) end - begin - uber4.color = Vec4f(1.0,1.0,1.0,1.0) - uber4.diffuse_weight = Vec4f(0.0,0.0,0.0,0.0) - uber4.diffuse_roughness = Vec4f(1.0,1.0,1.0,1.0) - uber4.reflection_color = Vec4f(0.501961,0.501961,0.501961,0.0) - uber4.reflection_weight = Vec4f(1.0,1.0,1.0,1.0) - uber4.reflection_roughness = Vec4f(0.0,0.0,0.0,0.0) - uber4.reflection_anisotropy = Vec4f(0.0,0.0,0.0,0.0) - uber4.reflection_anisotropy_rotation = Vec4f(0.0,0.0,0.0,0.0) + uber4.color = Vec4f(1.0, 1.0, 1.0, 1.0) + uber4.diffuse_weight = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.diffuse_roughness = Vec4f(1.0, 1.0, 1.0, 1.0) + uber4.reflection_color = Vec4f(0.501961, 0.501961, 0.501961, 0.0) + uber4.reflection_weight = Vec4f(1.0, 1.0, 1.0, 1.0) + uber4.reflection_roughness = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.reflection_anisotropy = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.reflection_anisotropy_rotation = Vec4f(0.0, 0.0, 0.0, 0.0) uber4.reflection_mode = 1 - uber4.reflection_ior = Vec4f(1.330000,1.330000,1.330000,1.330000) - uber4.refraction_color = Vec4f(0.501961,0.898039,0.996078,0.0) - uber4.refraction_weight = Vec4f(1.0,1.0,1.0,1.0) - uber4.refraction_roughness = Vec4f(0.0,0.0,0.0,0.0) - uber4.refraction_ior = Vec4f(1.330000,1.330000,1.330000,1.330000) + uber4.reflection_ior = Vec4f(1.330000, 1.330000, 1.330000, 1.330000) + uber4.refraction_color = Vec4f(0.501961, 0.898039, 0.996078, 0.0) + uber4.refraction_weight = Vec4f(1.0, 1.0, 1.0, 1.0) + uber4.refraction_roughness = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.refraction_ior = Vec4f(1.330000, 1.330000, 1.330000, 1.330000) uber4.refraction_thin_surface = 0 - uber4.refraction_absorption_color = Vec4f(0.501961,0.898039,0.996078,0.0) - uber4.refraction_absorption_distance = Vec4f(0.0,0.0,0.0,0.0) + uber4.refraction_absorption_color = Vec4f(0.501961, 0.898039, 0.996078, 0.0) + uber4.refraction_absorption_distance = Vec4f(0.0, 0.0, 0.0, 0.0) uber4.refraction_caustics = 0 - uber4.coating_color = Vec4f(1.0,1.0,1.0,1.0) - uber4.coating_weight = Vec4f(0.0,0.0,0.0,0.0) - uber4.coating_roughness = Vec4f(0.0,0.0,0.0,0.0) + uber4.coating_color = Vec4f(1.0, 1.0, 1.0, 1.0) + uber4.coating_weight = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.coating_roughness = Vec4f(0.0, 0.0, 0.0, 0.0) uber4.coating_mode = 1 - uber4.coating_ior = Vec4f(3.0,3.0,3.0,3.0) - uber4.coating_metalness = Vec4f(0.0,0.0,0.0,0.0) - uber4.coating_transmission_color = Vec4f(1.0,1.0,1.0,1.0) - uber4.coating_thickness = Vec4f(0.0,0.0,0.0,0.0) - uber4.sheen = Vec4f(1.0,1.0,1.0,1.0) - uber4.sheen_tint = Vec4f(0.0,0.0,0.0,0.0) - uber4.sheen_weight = Vec4f(0.0,0.0,0.0,0.0) - uber4.emission_color = Vec4f(1.0,1.0,1.0,1.0) - uber4.emission_weight = Vec4f(0.0,0.0,0.0,0.0) + uber4.coating_ior = Vec4f(3.0, 3.0, 3.0, 3.0) + uber4.coating_metalness = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.coating_transmission_color = Vec4f(1.0, 1.0, 1.0, 1.0) + uber4.coating_thickness = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.sheen = Vec4f(1.0, 1.0, 1.0, 1.0) + uber4.sheen_tint = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.sheen_weight = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.emission_color = Vec4f(1.0, 1.0, 1.0, 1.0) + uber4.emission_weight = Vec4f(0.0, 0.0, 0.0, 0.0) uber4.emission_mode = 1 - uber4.transparency = Vec4f(0.0,0.0,0.0,0.0) - uber4.sss_scatter_color = Vec4f(0.0,0.0,0.0,0.0) - uber4.sss_scatter_distance = Vec4f(0.0,0.0,0.0,0.0) - uber4.sss_scatter_direction = Vec4f(0.0,0.0,0.0,0.0) - uber4.sss_weight = Vec4f(0.0,0.0,0.0,0.0) + uber4.transparency = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.sss_scatter_color = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.sss_scatter_distance = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.sss_scatter_direction = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.sss_weight = Vec4f(0.0, 0.0, 0.0, 0.0) uber4.sss_multiscatter = 0 - uber4.backscatter_weight = Vec4f(0.0,0.0,0.0,0.0) - uber4.backscatter_color = Vec4f(1.0,1.0,1.0,1.0) + uber4.backscatter_weight = Vec4f(0.0, 0.0, 0.0, 0.0) + uber4.backscatter_color = Vec4f(1.0, 1.0, 1.0, 1.0) end diff --git a/ReferenceTests/src/database.jl b/ReferenceTests/src/database.jl index 99edfd79b1e..846c6e21fec 100644 --- a/ReferenceTests/src/database.jl +++ b/ReferenceTests/src/database.jl @@ -4,7 +4,9 @@ function used_functions(code) if @capture(x, f_(xs__)) push!(used_functions, Symbol(string(f))) end - if @capture(x, f_(xs__) do; body__; end) + if @capture(x, f_(xs__) do + return body__ + end) push!(used_functions, Symbol(string(f))) end return x @@ -27,7 +29,7 @@ Records `code` and saves the result to `joinpath(ReferenceTests.RECORDING_DIR[], macro reference_test(name, code) title = string(name) funcs = used_functions(code) - skip = (title in SKIP_TITLES) || any(x-> x in funcs, SKIP_FUNCTIONS) + skip = (title in SKIP_TITLES) || any(x -> x in funcs, SKIP_FUNCTIONS) return quote @testset $(title) begin if $skip @@ -72,11 +74,11 @@ function save_result(path::String, object) return true end -function mark_broken_tests(title_excludes = []; functions=[]) +function mark_broken_tests(title_excludes=[]; functions=[]) empty!(SKIP_TITLES) empty!(SKIP_FUNCTIONS) union!(SKIP_TITLES, title_excludes) - union!(SKIP_FUNCTIONS, functions) + return union!(SKIP_FUNCTIONS, functions) end macro include_reference_tests(path) diff --git a/ReferenceTests/src/runtests.jl b/ReferenceTests/src/runtests.jl index 13526823361..530b5603cc7 100644 --- a/ReferenceTests/src/runtests.jl +++ b/ReferenceTests/src/runtests.jl @@ -1,8 +1,6 @@ -function get_frames(a, b) - return (get_frames(a), get_frames(b)) -end +get_frames(a, b) = (get_frames(a), get_frames(b)) -function get_frames(video) +get_frames(video) = mktempdir() do folder afolder = joinpath(folder, "a") mkpath(afolder) @@ -18,13 +16,10 @@ function get_frames(video) end return load.(aframes) end -end -function compare_media(a::Matrix, b::Matrix; sigma=[1,1]) - Images.test_approx_eq_sigma_eps(a, b, sigma, Inf) -end +compare_media(a::Matrix, b::Matrix; sigma=[1, 1]) = Images.test_approx_eq_sigma_eps(a, b, sigma, Inf) -function compare_media(a, b; sigma=[1,1]) +function compare_media(a, b; sigma=[1, 1]) file, ext = splitext(a) if ext in (".png", ".jpg", ".jpeg", ".JPEG", ".JPG") imga = load(a) @@ -50,13 +45,17 @@ function compare_media(a, b; sigma=[1,1]) end end -function get_all_relative_filepaths_recursively(dir) +get_all_relative_filepaths_recursively(dir) = mapreduce(vcat, walkdir(dir)) do (root, dirs, files) - relpath.(joinpath.(root, files), dir) + return relpath.(joinpath.(root, files), dir) end -end -function record_comparison(base_folder::String; record_folder_name="recorded", reference_name = basename(base_folder), tag=last_major_version()) +function record_comparison( + base_folder::String; + record_folder_name="recorded", + reference_name=basename(base_folder), + tag=last_major_version(), +) record_folder = joinpath(base_folder, record_folder_name) reference_folder = download_refimages(tag; name=reference_name) # we copy the reference images into the output folder, since we want to upload it all as an artifact, to know against what images we compared @@ -71,7 +70,7 @@ function record_comparison(base_folder::String; record_folder_name="recorded", r end open(joinpath(base_folder, "scores.tsv"), "w") do file - paths_scores = sort(collect(pairs(scores)), by = last, rev = true) + paths_scores = sort(collect(pairs(scores)), by=last, rev=true) for (path, score) in paths_scores println(file, score, '\t', path) end @@ -80,17 +79,22 @@ function record_comparison(base_folder::String; record_folder_name="recorded", r return missing_refimages, scores end -function test_comparison(scores; threshold) - @testset "Comparison scores" begin - for (image, score) in pairs(scores) - @testset "$image" begin - @test score <= threshold - end +test_comparison(scores; threshold) = @testset "Comparison scores" begin + for (image, score) in pairs(scores) + @testset "$image" begin + @test score <= threshold end end end -function compare(relative_test_paths::Vector{String}, reference_dir::String, record_dir; o_refdir=reference_dir, missing_refimages=String[], scores=Dict{String,Float64}()) +function compare( + relative_test_paths::Vector{String}, + reference_dir::String, + record_dir; + o_refdir=reference_dir, + missing_refimages=String[], + scores=Dict{String,Float64}(), +) for relative_test_path in relative_test_paths ref_path = joinpath(reference_dir, relative_test_path) rec_path = joinpath(record_dir, relative_test_path) diff --git a/ReferenceTests/src/stable_rng.jl b/ReferenceTests/src/stable_rng.jl index ba257b3dd6b..fcd388fa36c 100644 --- a/ReferenceTests/src/stable_rng.jl +++ b/ReferenceTests/src/stable_rng.jl @@ -11,11 +11,11 @@ randn(args...) = Base.randn(STABLE_RNG, args...) seed_rng!() = Random.seed!(STABLE_RNG, 123) -function Base.rand(r::StableRNGs.LehmerRNG, ::Random.SamplerType{T}) where T <: ColorAlpha +function Base.rand(r::StableRNGs.LehmerRNG, ::Random.SamplerType{T}) where {T<:ColorAlpha} return T(Base.rand(r), Base.rand(r), Base.rand(r), Base.rand(r)) end -function Base.rand(r::StableRNGs.LehmerRNG, ::Random.SamplerType{T}) where T <: AbstractRGB +function Base.rand(r::StableRNGs.LehmerRNG, ::Random.SamplerType{T}) where {T<:AbstractRGB} return T(Base.rand(r), Base.rand(r), Base.rand(r)) end diff --git a/ReferenceTests/src/tests/attributes.jl b/ReferenceTests/src/tests/attributes.jl index e81f432d05f..cb9e9f91775 100644 --- a/ReferenceTests/src/tests/attributes.jl +++ b/ReferenceTests/src/tests/attributes.jl @@ -4,7 +4,7 @@ end @reference_test "isorange, isovalue" begin r = range(-1, stop=1, length=100) - matr = [(x.^2 + y.^2 + z.^2) for x = r, y = r, z = r] + matr = [(x .^ 2 + y .^ 2 + z .^ 2) for x in r, y in r, z in r] volume(matr .* (matr .> 1.4), algorithm=:iso, isorange=0.05, isovalue=1.7) end @@ -15,10 +15,9 @@ end contour(x, y, z, linewidth=3, colormap=:colorwheel, levels=50) end - @reference_test "position" begin fig, ax, sc = scatter(RNG.rand(10), color=:red) - text!(ax, 5, 1.1, text = "adding text", fontsize=0.6) + text!(ax, 5, 1.1, text="adding text", fontsize=0.6) fig end @@ -27,7 +26,7 @@ end end @reference_test "shading" begin - mesh(Sphere(Point3f(0), 1f0), color=:orange, shading=false) + mesh(Sphere(Point3f(0), 1.0f0), color=:orange, shading=false) end @reference_test "visible" begin diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index 04c134fbe1f..e019faf2b27 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -13,29 +13,29 @@ end end @reference_test "heatmap_interpolation" begin - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) data = RNG.rand(32, 32) # the grayscale heatmap hides the problem that interpolation based on values # in GLMakie looks different than interpolation based on colors in CairoMakie - heatmap(f[1, 1], data, interpolate = false, colormap = :grays) - heatmap(f[1, 2], data, interpolate = true, colormap = :grays) + heatmap(f[1, 1], data, interpolate=false, colormap=:grays) + heatmap(f[1, 2], data, interpolate=true, colormap=:grays) data_big = RNG.rand(1000, 1000) - heatmap(f[2, 1], data_big, interpolate = false, colormap = :grays) - heatmap(f[2, 2], data_big, interpolate = true, colormap = :grays) + heatmap(f[2, 1], data_big, interpolate=false, colormap=:grays) + heatmap(f[2, 2], data_big, interpolate=true, colormap=:grays) xs = (1:32) .^ 1.5 ys = (1:32) .^ 1.5 data = RNG.rand(32, 32) - heatmap(f[3, 1], xs, ys, data, interpolate = false, colormap = :grays) + heatmap(f[3, 1], xs, ys, data, interpolate=false, colormap=:grays) f end @reference_test "poly and colormap" begin # example by @Paulms from MakieOrg/Makie.jl#310 points = Point2f[[0.0, 0.0], [0.1, 0.0], [0.1, 0.1], [0.0, 0.1]] - colors = [0.0 ,0.0, 0.5, 0.0] + colors = [0.0, 0.0, 0.5, 0.0] fig, ax, polyplot = poly(points, color=colors, colorrange=(0.0, 1.0)) points = Point2f[[0.1, 0.1], [0.2, 0.1], [0.2, 0.2], [0.1, 0.2]] - colors = [0.5,0.5,1.0,0.3] + colors = [0.5, 0.5, 1.0, 0.3] poly!(ax, points, color=colors, colorrange=(0.0, 1.0)) fig end @@ -56,32 +56,32 @@ end @reference_test "image" begin fig = Figure() - image(fig[1,1], Makie.logo(), axis = (; aspect = DataAspect())) - image(fig[1, 2], RNG.rand(100, 500), axis = (; aspect = DataAspect())) + image(fig[1, 1], Makie.logo(), axis=(; aspect=DataAspect())) + image(fig[1, 2], RNG.rand(100, 500), axis=(; aspect=DataAspect())) fig end @reference_test "FEM polygon 2D" begin coordinates = [ - 0.0 0.0; - 0.5 0.0; - 1.0 0.0; - 0.0 0.5; - 0.5 0.5; - 1.0 0.5; - 0.0 1.0; - 0.5 1.0; - 1.0 1.0; + 0.0 0.0 + 0.5 0.0 + 1.0 0.0 + 0.0 0.5 + 0.5 0.5 + 1.0 0.5 + 0.0 1.0 + 0.5 1.0 + 1.0 1.0 ] connectivity = [ - 1 2 5; - 1 4 5; - 2 3 6; - 2 5 6; - 4 5 8; - 4 7 8; - 5 6 9; - 5 8 9; + 1 2 5 + 1 4 5 + 2 3 6 + 2 5 6 + 4 5 8 + 4 7 8 + 5 6 9 + 5 8 9 ] color = [0.0, 0.0, 0.0, 0.0, -0.375, 0.0, 0.0, 0.0, 0.0] poly(coordinates, connectivity, color=color, strokecolor=(:black, 0.6), strokewidth=4) @@ -89,25 +89,25 @@ end @reference_test "FEM mesh 2D" begin coordinates = [ - 0.0 0.0; - 0.5 0.0; - 1.0 0.0; - 0.0 0.5; - 0.5 0.5; - 1.0 0.5; - 0.0 1.0; - 0.5 1.0; - 1.0 1.0; + 0.0 0.0 + 0.5 0.0 + 1.0 0.0 + 0.0 0.5 + 0.5 0.5 + 1.0 0.5 + 0.0 1.0 + 0.5 1.0 + 1.0 1.0 ] connectivity = [ - 1 2 5; - 1 4 5; - 2 3 6; - 2 5 6; - 4 5 8; - 4 7 8; - 5 6 9; - 5 8 9; + 1 2 5 + 1 4 5 + 2 3 6 + 2 5 6 + 4 5 8 + 4 7 8 + 5 6 9 + 5 8 9 ] color = [0.0, 0.0, 0.0, 0.0, -0.375, 0.0, 0.0, 0.0, 0.0] fig, ax, meshplot = mesh(coordinates, connectivity, color=color, shading=false) @@ -116,38 +116,40 @@ end end @reference_test "colored triangle" begin - mesh( - [(0.0, 0.0), (0.5, 1.0), (1.0, 0.0)], color=[:red, :green, :blue], - shading=false - ) + mesh([(0.0, 0.0), (0.5, 1.0), (1.0, 0.0)], color=[:red, :green, :blue], shading=false) end @reference_test "colored triangle with poly" begin - poly( - [(0.0, 0.0), (0.5, 1.0), (1.0, 0.0)], - color=[:red, :green, :blue], - strokecolor=:black, strokewidth=2 - ) + poly([(0.0, 0.0), (0.5, 1.0), (1.0, 0.0)], color=[:red, :green, :blue], strokecolor=:black, strokewidth=2) end @reference_test "scale_plot" begin t = range(0, stop=1, length=500) # time steps θ = (6π) .* t # angles x = # x coords of spiral - y = # y coords of spiral - lines(t .* cos.(θ), t .* sin.(θ); - color=t, colormap=:algae, linewidth=8, axis = (; aspect = DataAspect())) + y = # y coords of spiral + lines( + t .* cos.(θ), + t .* sin.(θ); + color=t, + colormap=:algae, + linewidth=8, + axis=(; aspect=DataAspect()), + ) end @reference_test "Polygons" begin - points = decompose(Point2f, Circle(Point2f(50), 50f0)) + points = decompose(Point2f, Circle(Point2f(50), 50.0f0)) fig, ax, pol = poly(points, color=:gray, strokewidth=10, strokecolor=:red) # Optimized forms - poly!(ax, [Circle(Point2f(50 + 300), 50f0)], color=:gray, strokewidth=10, strokecolor=:red) - poly!(ax, [Circle(Point2f(50 + i, 50 + i), 10f0) for i = 1:100:400], color=:red) - poly!(ax, [Rect2f(50 + i, 50 + i, 20, 20) for i = 1:100:400], strokewidth=2, strokecolor=:green) - linesegments!(ax, - [Point2f(50 + i, 50 + i) => Point2f(i + 70, i + 70) for i = 1:100:400], linewidth=8, color=:purple + poly!(ax, [Circle(Point2f(50 + 300), 50.0f0)], color=:gray, strokewidth=10, strokecolor=:red) + poly!(ax, [Circle(Point2f(50 + i, 50 + i), 10.0f0) for i in 1:100:400], color=:red) + poly!(ax, [Rect2f(50 + i, 50 + i, 20, 20) for i in 1:100:400], strokewidth=2, strokecolor=:green) + linesegments!( + ax, + [Point2f(50 + i, 50 + i) => Point2f(i + 70, i + 70) for i in 1:100:400], + linewidth=8, + color=:purple, ) fig end @@ -156,9 +158,9 @@ end text( ". This is an annotation!", position=(300, 200), - align=(:center, :center), + align=(:center, :center), fontsize=60, - font="Blackchancery" + font="Blackchancery", ) end @@ -170,12 +172,7 @@ end for r in range(0, stop=2pi, length=20) p = pos .+ (sin(r) * 100.0, cos(r) * 100) push!(posis, p) - text!(ax, "test", - position=p, - fontsize=50, - rotation=1.5pi - r, - align=(:center, :center) - ) + text!(ax, "test", position=p, fontsize=50, rotation=1.5pi - r, align=(:center, :center)) end scatter!(ax, posis, markersize=10) fig @@ -196,23 +193,21 @@ end end @reference_test "Streamplot animation" begin - v(x::Point2{T}, t) where T = Point2{T}(one(T) * x[2] * t, 4 * x[1]) + v(x::Point2{T}, t) where {T} = Point2{T}(one(T) * x[2] * t, 4 * x[1]) sf = Observable(Base.Fix2(v, 0e0)) title_str = Observable("t = 0.00") - sp = streamplot(sf, -2..2, -2..2; - linewidth=2, colormap=:magma, axis=(;title=title_str)) + sp = streamplot(sf, -2 .. 2, -2 .. 2; linewidth=2, colormap=:magma, axis=(; title=title_str)) Record(sp, LinRange(0, 20, 5)) do i sf[] = Base.Fix2(v, i) - title_str[] = "t = $(round(i; sigdigits=2))" + return title_str[] = "t = $(round(i; sigdigits=2))" end end - @reference_test "Line changing colour" begin fig, ax, lineplot = lines(RNG.rand(10); linewidth=10) N = 20 Record(fig, 1:N; framerate=20) do i - lineplot.color = RGBf(i / N, (N - i) / N, 0) # animate scene + return lineplot.color = RGBf(i / N, (N - i) / N, 0) # animate scene end end @@ -225,12 +220,9 @@ let end @reference_test "streamplot" begin P = FitzhughNagumo(0.1, 0.0, 1.5, 0.8) - ff(x, P::FitzhughNagumo) = Point2f( - (x[1] - x[2] - x[1]^3 + P.s) / P.ϵ, - P.γ * x[1] - x[2] + P.β - ) + ff(x, P::FitzhughNagumo) = Point2f((x[1] - x[2] - x[1]^3 + P.s) / P.ϵ, P.γ * x[1] - x[2] + P.β) ff(x) = ff(x, P) - streamplot(ff, -1.5..1.5, -1.5..1.5, colormap=:magma) + streamplot(ff, -1.5 .. 1.5, -1.5 .. 1.5, colormap=:magma) end end @@ -238,32 +230,29 @@ end N = 7 # number of colours in default palette fig = Figure() ax = Axis(fig) - fig[1,1] = ax + fig[1, 1] = ax st = Stepper(fig) xs = 0:9 # data ys = zeros(10) colors = Makie.default_palettes.color[] plots = map(1:N) do i # plot lines - lines!(ax, - xs, ys; - color=colors[i], - linewidth=5 - ) # plot lines with colors + return lines!(ax, xs, ys; color=colors[i], linewidth=5) # plot lines with colors end Makie.step!(st) for (i, rot) in enumerate(LinRange(0, π / 2, N)) Makie.rotate!(plots[i], rot) - arc!(ax, + arc!( + ax, Point2f(0), (8 - i), pi / 2, (pi / 2 - rot); color=plots[i].color, linewidth=5, - linestyle=:dash + linestyle=:dash, ) end @@ -273,10 +262,10 @@ end @reference_test "Axes label rotations" begin axis = ( - xlabel = "a long x label for this axis", - ylabel = "a long y\nlabel for this axis", - xlabelrotation = π / 4, - ylabelrotation = 0, + xlabel="a long x label for this axis", + ylabel="a long y\nlabel for this axis", + xlabelrotation=π / 4, + ylabelrotation=0, ) fig, ax, _ = scatter(0:1; axis) @@ -304,16 +293,16 @@ end @reference_test "Colorbar label rotations" begin axis = ( - xlabel = "x axis label", - ylabel = "y axis label", - xlabelrotation = -π / 10, - ylabelrotation = -π / 3, - yaxisposition = :right, + xlabel="x axis label", + ylabel="y axis label", + xlabelrotation=-π / 10, + ylabelrotation=-π / 3, + yaxisposition=:right, ) fig, _, _ = scatter(0:1; axis) - cb_vert = Colorbar(fig[1, 2]; label = "vertical cbar", labelrotation = 0) - cb_horz = Colorbar(fig[2, 1]; label = "horizontal cbar", labelrotation = π / 5, vertical = false) + cb_vert = Colorbar(fig[1, 2]; label="vertical cbar", labelrotation=0) + cb_horz = Colorbar(fig[2, 1]; label="horizontal cbar", labelrotation=π / 5, vertical=false) st = Stepper(fig) Makie.step!(st) @@ -333,7 +322,7 @@ end y = sin.(x) fig, ax, scatterplot = scatter(x, y) errorbars!(ax, x, y, RNG.rand(10) .+ 0.5, RNG.rand(10) .+ 0.5) - errorbars!(ax, x, y, RNG.rand(10) .+ 0.5, RNG.rand(10) .+ 0.5, color = :red, direction = :x) + errorbars!(ax, x, y, RNG.rand(10) .+ 0.5, RNG.rand(10) .+ 0.5, color=:red, direction=:x) fig end @@ -343,33 +332,30 @@ end lows = zeros(length(vals)) highs = LinRange(0.1, 0.4, length(vals)) - fig, ax, rbars = rangebars(vals, lows, highs, color = :red) - rangebars!(ax, vals, lows, highs, color = LinRange(0, 1, length(vals)), - whiskerwidth = 3, direction = :x) + fig, ax, rbars = rangebars(vals, lows, highs, color=:red) + rangebars!(ax, vals, lows, highs, color=LinRange(0, 1, length(vals)), whiskerwidth=3, direction=:x) fig end - @reference_test "Simple pie chart" begin fig = Figure(resolution=(800, 800)) - pie(fig[1, 1], 1:5, color=collect(1:5), axis=(;aspect=DataAspect())) + pie(fig[1, 1], 1:5, color=collect(1:5), axis=(; aspect=DataAspect())) fig end @reference_test "Hollow pie chart" begin - pie(1:5, color=collect(1.0:5), radius=2, inner_radius=1, axis=(;aspect=DataAspect())) + pie(1:5, color=collect(1.0:5), radius=2, inner_radius=1, axis=(; aspect=DataAspect())) end @reference_test "Open pie chart" begin - pie(0.1:0.1:1.0, normalize=false, axis=(;aspect=DataAspect())) + pie(0.1:0.1:1.0, normalize=false, axis=(; aspect=DataAspect())) end @reference_test "intersecting polygon" begin x = LinRange(0, 2pi, 100) - poly(Point2f.(zip(sin.(x), sin.(2x))), color = :white, strokecolor = :blue, strokewidth = 10) + poly(Point2f.(zip(sin.(x), sin.(2x))), color=:white, strokecolor=:blue, strokewidth=10) end - @reference_test "Line Function" begin x = range(0, stop=3pi) fig, ax, lineplot = lines(x, sin.(x)) @@ -378,65 +364,72 @@ end end @reference_test "Grouped bar" begin - x1 = ["a_right", "a_right", "a_right", "a_right"] - y1 = [2, 3, -3, -2] - grp_dodge1 = [2, 2, 1, 1] - grp_stack1 = [1, 2, 1, 2] + x1 = ["a_right", "a_right", "a_right", "a_right"] + y1 = [2, 3, -3, -2] + grp_dodge1 = [2, 2, 1, 1] + grp_stack1 = [1, 2, 1, 2] - x2 = ["z_left", "z_left", "z_left", "z_left"] - y2 = [2, 3, -3, -2] - grp_dodge2 = [1, 2, 1, 2] - grp_stack2 = [1, 1, 2, 2] + x2 = ["z_left", "z_left", "z_left", "z_left"] + y2 = [2, 3, -3, -2] + grp_dodge2 = [1, 2, 1, 2] + grp_stack2 = [1, 1, 2, 2] perm = [1, 4, 2, 7, 5, 3, 8, 6] x = [x1; x2][perm] - x = categorical(x, levels = ["z_left", "a_right"]) + x = categorical(x, levels=["z_left", "a_right"]) y = [y1; y2][perm] grp_dodge = [grp_dodge1; grp_dodge2][perm] grp_stack = [grp_stack1; grp_stack2][perm] - tbl = (; x = x, grp_dodge = grp_dodge, grp_stack = grp_stack, y = y) + tbl = (; x=x, grp_dodge=grp_dodge, grp_stack=grp_stack, y=y) fig = Figure() - ax = Axis(fig[1,1]) + ax = Axis(fig[1, 1]) - barplot!(ax, levelcode.(tbl.x), tbl.y, dodge = tbl.grp_dodge, stack = tbl.grp_stack, color = tbl.grp_stack) + barplot!(ax, levelcode.(tbl.x), tbl.y, dodge=tbl.grp_dodge, stack=tbl.grp_stack, color=tbl.grp_stack) ax.xticks = (1:2, ["z_left", "a_right"]) fig end - @reference_test "space 2D" begin # This should generate a regular grid with text in a circle in a box. All # sizes and positions are scaled to be equal across all options. - fig = Figure(resolution = (700, 700)) - ax = Axis(fig[1, 1], width = 600, height = 600) + fig = Figure(resolution=(700, 700)) + ax = Axis(fig[1, 1], width=600, height=600) spaces = (:data, :pixel, :relative, :clip) xs = [ [0.1, 0.35, 0.6, 0.85], [0.1, 0.35, 0.6, 0.85] * 600, [0.1, 0.35, 0.6, 0.85], - 2 .* [0.1, 0.35, 0.6, 0.85] .- 1 + 2 .* [0.1, 0.35, 0.6, 0.85] .- 1, ] scales = (0.02, 12, 0.02, 0.04) for (i, space) in enumerate(spaces) for (j, mspace) in enumerate(spaces) s = 1.5scales[i] - mesh!( - ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space = space, - shading = false, color = :blue) - lines!( - ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), - space = space, linewidth = 2, color = :red) + mesh!(ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space=space, shading=false, color=:blue) + lines!(ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space=space, linewidth=2, color=:red) scatter!( - ax, Point2f(xs[i][i], xs[i][j]), color = :orange, marker = Circle, - markersize = 5scales[j], space = space, markerspace = mspace) + ax, + Point2f(xs[i][i], xs[i][j]), + color=:orange, + marker=Circle, + markersize=5scales[j], + space=space, + markerspace=mspace, + ) text!( - ax, "$space\n$mspace", position = Point2f(xs[i][i], xs[i][j]), - fontsize = scales[j], space = space, markerspace = mspace, - align = (:center, :center), color = :black) + ax, + "$space\n$mspace", + position=Point2f(xs[i][i], xs[i][j]), + fontsize=scales[j], + space=space, + markerspace=mspace, + align=(:center, :center), + color=:black, + ) end end xlims!(ax, 0, 1) @@ -453,32 +446,40 @@ end # - (x -> data) row should have stretched circle and text ain x direction # - (not data -> data) should keep aspect ratio for mesh and lines # - (data -> x) should be slightly missaligned with (not data -> x) - fig = Figure(resolution = (700, 700)) - ax = Axis(fig[1, 1], width = 600, height = 600) + fig = Figure(resolution=(700, 700)) + ax = Axis(fig[1, 1], width=600, height=600) spaces = (:data, :pixel, :relative, :clip) xs = [ [0.1, 0.35, 0.6, 0.85], [0.1, 0.35, 0.6, 0.85] * 600, [0.1, 0.35, 0.6, 0.85], - 2 .* [0.1, 0.35, 0.6, 0.85] .- 1 + 2 .* [0.1, 0.35, 0.6, 0.85] .- 1, ] scales = (0.02, 12, 0.02, 0.04) for (i, space) in enumerate(spaces) for (j, mspace) in enumerate(spaces) s = 1.5scales[i] - mesh!( - ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space = space, - shading = false, color = :blue) - lines!( - ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), - space = space, linewidth = 2, color = :red) + mesh!(ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space=space, shading=false, color=:blue) + lines!(ax, Rect2f(xs[i][i] - 2s, xs[i][j] - 2s, 4s, 4s), space=space, linewidth=2, color=:red) scatter!( - ax, Point2f(xs[i][i], xs[i][j]), color = :orange, marker = Circle, - markersize = 5scales[j], space = space, markerspace = mspace) + ax, + Point2f(xs[i][i], xs[i][j]), + color=:orange, + marker=Circle, + markersize=5scales[j], + space=space, + markerspace=mspace, + ) text!( - ax, "$space\n$mspace", position = Point2f(xs[i][i], xs[i][j]), - fontsize = scales[j], space = space, markerspace = mspace, - align = (:center, :center), color = :black) + ax, + "$space\n$mspace", + position=Point2f(xs[i][i], xs[i][j]), + fontsize=scales[j], + space=space, + markerspace=mspace, + align=(:center, :center), + color=:black, + ) end end fig @@ -486,19 +487,19 @@ end @reference_test "Scatter & Text transformations" begin # Check that transformations apply in `space = :data` - fig, ax, p = scatter(Point2f(100, 0.5), marker = 'a', markersize=50) - t = text!(Point2f(100, 0.5), text = "Test", fontsize = 50) + fig, ax, p = scatter(Point2f(100, 0.5), marker='a', markersize=50) + t = text!(Point2f(100, 0.5), text="Test", fontsize=50) translate!(p, -100, 0, 0) translate!(t, -100, 0, 0) # Check that scale and rotate don't act on the marker for scatter (only the position) - p2 = scatter!(ax, Point2f(1, 0), marker= 'a', markersize = 50) - Makie.rotate!(p2, pi/4) + p2 = scatter!(ax, Point2f(1, 0), marker='a', markersize=50) + Makie.rotate!(p2, pi / 4) scale!(p2, 0.5, 0.5, 1) # but do act on glyphs of text - t2 = text!(ax, 1, 0, text = "Test", fontsize = 50) - Makie.rotate!(t2, pi/4) + t2 = text!(ax, 1, 0, text="Test", fontsize=50) + Makie.rotate!(t2, pi / 4) scale!(t2, 0.5, 0.5, 1) xlims!(ax, -0.2, 0.5) @@ -509,19 +510,25 @@ end @reference_test "Array of Images Scatter" begin img = Makie.logo() - scatter(1:2, 1:2, marker = [img, img], markersize=reverse(size(img) ./ 10), axis=(limits=(0.5, 2.5, 0.5, 2.5),)) + scatter( + 1:2, + 1:2, + marker=[img, img], + markersize=reverse(size(img) ./ 10), + axis=(limits=(0.5, 2.5, 0.5, 2.5),), + ) end @reference_test "Image Scatter different sizes" begin img = Makie.logo() img2 = load(Makie.assetpath("doge.png")) images = [img, img2] - markersize = map(img-> Vec2f(reverse(size(img) ./ 10)), images) - scatter(1:2, 1:2, marker = images, markersize=markersize, axis=(limits=(0.5, 2.5, 0.5, 2.5),)) + markersize = map(img -> Vec2f(reverse(size(img) ./ 10)), images) + scatter(1:2, 1:2, marker=images, markersize=markersize, axis=(limits=(0.5, 2.5, 0.5, 2.5),)) end @reference_test "2D surface with explicit color" begin - surface(1:10, 1:10, ones(10, 10); color = [RGBf(x*y/100, 0, 0) for x in 1:10, y in 1:10], shading = false) + surface(1:10, 1:10, ones(10, 10); color=[RGBf(x * y / 100, 0, 0) for x in 1:10, y in 1:10], shading=false) end @reference_test "heatmap and image colormap interpolation" begin @@ -529,19 +536,25 @@ end crange = LinRange(0, 255, 10) len = length(crange) img = zeros(Float32, len, len + 2) - img[:, 1] .= 255f0 + img[:, 1] .= 255.0f0 for (i, v) in enumerate(crange) ib = i + 1 - img[2:end-1, ib] .= v - img[1, ib] = 255-v - img[end, ib] = 255-v + img[2:(end - 1), ib] .= v + img[1, ib] = 255 - v + img[end, ib] = 255 - v end - kw(p, interpolate) = (axis=(title="$(p)(interpolate=$(interpolate))", aspect=DataAspect()), interpolate=interpolate, colormap=[:white, :black]) + function kw(p, interpolate) + return ( + axis=(title="$(p)(interpolate=$(interpolate))", aspect=DataAspect()), + interpolate=interpolate, + colormap=[:white, :black], + ) + end for (i, p) in enumerate([heatmap, image]) for (j, interpolate) in enumerate([true, false]) - ax, pl = p(f[i,j], img; kw(p, interpolate)...) + ax, pl = p(f[i, j], img; kw(p, interpolate)...) hidedecorations!(ax) end end @@ -552,16 +565,16 @@ end n = 100 categorical = [false, true] scales = [exp, identity, log, log10] - fig = Figure(resolution = (500, 250)) + fig = Figure(resolution=(500, 250)) ax = Axis(fig[1, 1]) for (i, cat) in enumerate(categorical) for (j, scale) in enumerate(scales) cg = if cat - cgrad(:viridis, 5; scale = scale, categorical=true) + cgrad(:viridis, 5; scale=scale, categorical=true) else - cgrad(:viridis; scale = scale, categorical=nothing) + cgrad(:viridis; scale=scale, categorical=nothing) end - lines!(ax, Point2f.(LinRange(i+0.1, i+0.9, n), j); color = 1:n, colormap = cg, linewidth = 10) + lines!(ax, Point2f.(LinRange(i + 0.1, i + 0.9, n), j); color=1:n, colormap=cg, linewidth=10) end end ax.xticks[] = ((1:length(categorical)) .+ 0.5, ["categorical=false", "categorical=true"]) @@ -570,13 +583,13 @@ end end @reference_test "colormap with specific values" begin - cmap = cgrad([:black,:white,:orange],[0,0.2,1]) - fig = Figure(resolution=(400,200)) - ax = Axis(fig[1,1]) - x = range(0,1,length=50) - scatter!(fig[1,1],Point2.(x,fill(0.,50)),color=x,colormap=cmap) + cmap = cgrad([:black, :white, :orange], [0, 0.2, 1]) + fig = Figure(resolution=(400, 200)) + ax = Axis(fig[1, 1]) + x = range(0, 1, length=50) + scatter!(fig[1, 1], Point2.(x, fill(0.0, 50)), color=x, colormap=cmap) hidedecorations!(ax) - Colorbar(fig[2,1],vertical=false,colormap=cmap) + Colorbar(fig[2, 1], vertical=false, colormap=cmap) fig end @@ -587,36 +600,57 @@ end @reference_test "minor grid & scales" begin data = LinRange(0.01, 0.99, 200) - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) for (i, scale) in enumerate([log10, log2, log, sqrt, Makie.logit, identity]) row, col = fldmod1(i, 2) - Axis(f[row, col], yscale = scale, title = string(scale), - yminorticksvisible = true, yminorgridvisible = true, - xminorticksvisible = true, xminorgridvisible = true, - yminortickwidth = 4.0, xminortickwidth = 4.0, - yminorgridwidth = 6.0, xminorgridwidth = 6.0, - yminorticks = IntervalsBetween(3)) - - lines!(data, color = :blue) + Axis( + f[row, col], + yscale=scale, + title=string(scale), + yminorticksvisible=true, + yminorgridvisible=true, + xminorticksvisible=true, + xminorgridvisible=true, + yminortickwidth=4.0, + xminortickwidth=4.0, + yminorgridwidth=6.0, + xminorgridwidth=6.0, + yminorticks=IntervalsBetween(3), + ) + + lines!(data, color=:blue) end f end @reference_test "Tooltip" begin - fig, ax, p = scatter(Point2f(0,0)) + fig, ax, p = scatter(Point2f(0, 0)) xlims!(ax, -10, 10) ylims!(ax, -5, 5) - tt = tooltip!(ax, Point2f(0), text = "left", placement = :left) + tt = tooltip!(ax, Point2f(0), text="left", placement=:left) tt.backgroundcolor[] = :red tooltip!( - ax, 0, 0, "above with \nnewline\nand offset", - placement = :above, textpadding = (8, 5, 3, 2), align = 0.8 + ax, + 0, + 0, + "above with \nnewline\nand offset", + placement=:above, + textpadding=(8, 5, 3, 2), + align=0.8, ) - tooltip!(ax, Point2f(0), "below", placement = :below, outline_color = :red, outline_linestyle = :dot) + tooltip!(ax, Point2f(0), "below", placement=:below, outline_color=:red, outline_linestyle=:dot) tooltip!( - ax, 0, 0, text = "right", placement = :right, fontsize = 30, - outline_linewidth = 5, offset = 30, triangle_size = 15, - strokewidth = 2f0, strokecolor = :cyan + ax, + 0, + 0, + text="right", + placement=:right, + fontsize=30, + outline_linewidth=5, + offset=30, + triangle_size=15, + strokewidth=2.0f0, + strokecolor=:cyan, ) fig end @@ -627,7 +661,7 @@ end z = -sqrt.(x .^ 2 .+ y .^ 2) .+ 0.1 .* RNG.randn.() f, ax, tr = tricontourf(x, y, z) - scatter!(x, y, color = z, strokewidth = 1, strokecolor = :black) + scatter!(x, y, color=z, strokewidth=1, strokecolor=:black) Colorbar(f[1, 2], tr) f end @@ -637,8 +671,8 @@ end y = RNG.randn(50) z = -sqrt.(x .^ 2 .+ y .^ 2) .+ 0.1 .* RNG.randn.() - f, ax, tr = tricontourf(x, y, z, levels = -1.8:0.2:-0.4, extendhigh = :red, extendlow = :orange) - scatter!(x, y, color = z, strokewidth = 1, strokecolor = :black) + f, ax, tr = tricontourf(x, y, z, levels=-1.8:0.2:-0.4, extendhigh=:red, extendlow=:orange) + scatter!(x, y, color=z, strokewidth=1, strokecolor=:black) Colorbar(f[1, 2], tr) f end @@ -648,30 +682,36 @@ end y = RNG.randn(50) z = -sqrt.(x .^ 2 .+ y .^ 2) .+ 0.1 .* RNG.randn.() - f, ax, tr = tricontourf(x, y, z, mode = :relative, levels = 0.2:0.1:1, colormap = :batlow) - scatter!(x, y, color = z, strokewidth = 1, strokecolor = :black, colormap = :batlow) + f, ax, tr = tricontourf(x, y, z, mode=:relative, levels=0.2:0.1:1, colormap=:batlow) + scatter!(x, y, color=z, strokewidth=1, strokecolor=:black, colormap=:batlow) Colorbar(f[1, 2], tr) f end @reference_test "tricontourf manual vs delaunay" begin n = 20 - angles = range(0, 2pi, length = n+1)[1:end-1] - x = [cos.(angles); 2 .* cos.(angles .+ pi/n)] - y = [sin.(angles); 2 .* sin.(angles .+ pi/n)] - z = (x .- 0.5).^2 + (y .- 0.5).^2 .+ 0.5 .* RNG.randn.() + angles = range(0, 2pi, length=n + 1)[1:(end - 1)] + x = [cos.(angles); 2 .* cos.(angles .+ pi / n)] + y = [sin.(angles); 2 .* sin.(angles .+ pi / n)] + z = (x .- 0.5) .^ 2 + (y .- 0.5) .^ 2 .+ 0.5 .* RNG.randn.() triangulation_inner = reduce(hcat, map(i -> [0, 1, n] .+ i, 1:n)) - triangulation_outer = reduce(hcat, map(i -> [n-1, n, 0] .+ i, 1:n)) + triangulation_outer = reduce(hcat, map(i -> [n - 1, n, 0] .+ i, 1:n)) triangulation = hcat(triangulation_inner, triangulation_outer) - f, ax, _ = tricontourf(x, y, z, triangulation = triangulation, - axis = (; aspect = 1, title = "Manual triangulation")) - scatter!(x, y, color = z, strokewidth = 1, strokecolor = :black) - - tricontourf(f[1, 2], x, y, z, triangulation = Makie.DelaunayTriangulation(), - axis = (; aspect = 1, title = "Delaunay triangulation")) - scatter!(x, y, color = z, strokewidth = 1, strokecolor = :black) + f, ax, _ = + tricontourf(x, y, z, triangulation=triangulation, axis=(; aspect=1, title="Manual triangulation")) + scatter!(x, y, color=z, strokewidth=1, strokecolor=:black) + + tricontourf( + f[1, 2], + x, + y, + z, + triangulation=Makie.DelaunayTriangulation(), + axis=(; aspect=1, title="Delaunay triangulation"), + ) + scatter!(x, y, color=z, strokewidth=1, strokecolor=:black) f end @@ -679,106 +719,115 @@ end @reference_test "marker offset in data space" begin f = Figure() ax = Axis(f[1, 1]; xticks=0:1, yticks=0:10) - scatter!(ax, fill(0, 10), 0:9, marker=Rect, marker_offset=Vec2f(0,0), transform_marker=true, markerspace=:data, markersize=Vec2f.(1, LinRange(0.1, 1, 10))) + scatter!( + ax, + fill(0, 10), + 0:9, + marker=Rect, + marker_offset=Vec2f(0, 0), + transform_marker=true, + markerspace=:data, + markersize=Vec2f.(1, LinRange(0.1, 1, 10)), + ) lines!(ax, Rect(0, 0, 1, 10), color=:red) f end @reference_test "trimspine" begin - with_theme(Axis = (limits = (0.5, 5.5, 0.3, 3.4), spinewidth = 8, topspinevisible = false, rightspinevisible = false)) do - f = Figure(resolution = (800, 800)) + with_theme( + Axis=(limits=(0.5, 5.5, 0.3, 3.4), spinewidth=8, topspinevisible=false, rightspinevisible=false), + ) do + f = Figure(resolution=(800, 800)) for (i, ts) in enumerate([(true, true), (true, false), (false, true), (false, false)]) - Label(f[0, i], string(ts), tellwidth = false) - Axis(f[1, i], xtrimspine = ts) - Axis(f[2, i], ytrimspine = ts) - Axis(f[3, i], xtrimspine = ts, xreversed = true) - Axis(f[4, i], ytrimspine = ts, yreversed = true) + Label(f[0, i], string(ts), tellwidth=false) + Axis(f[1, i], xtrimspine=ts) + Axis(f[2, i], ytrimspine=ts) + Axis(f[3, i], xtrimspine=ts, xreversed=true) + Axis(f[4, i], ytrimspine=ts, yreversed=true) end for (i, l) in enumerate(["x", "y", "x reversed", "y reversed"]) - Label(f[i, 5], l, tellheight = false) + Label(f[i, 5], l, tellheight=false) end - f + return f end end @reference_test "hexbin bin int" begin - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) x = RNG.rand(300) y = RNG.rand(300) for i in 2:5 - ax = Axis(f[fldmod1(i-1, 2)...], title = "bins = $i", aspect = DataAspect()) - hexbin!(ax, x, y, bins = i) - wireframe!(ax, Rect2f(Point2f.(x, y)), color = :red) - scatter!(ax, x, y, color = :red, markersize = 5) + ax = Axis(f[fldmod1(i - 1, 2)...], title="bins = $i", aspect=DataAspect()) + hexbin!(ax, x, y, bins=i) + wireframe!(ax, Rect2f(Point2f.(x, y)), color=:red) + scatter!(ax, x, y, color=:red, markersize=5) end f end @reference_test "hexbin bin tuple" begin - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) x = RNG.rand(300) y = RNG.rand(300) for i in 2:5 - ax = Axis(f[fldmod1(i-1, 2)...], title = "bins = (3, $i)", aspect = DataAspect()) - hexbin!(ax, x, y, bins = (3, i)) - wireframe!(ax, Rect2f(Point2f.(x, y)), color = :red) - scatter!(ax, x, y, color = :red, markersize = 5) + ax = Axis(f[fldmod1(i - 1, 2)...], title="bins = (3, $i)", aspect=DataAspect()) + hexbin!(ax, x, y, bins=(3, i)) + wireframe!(ax, Rect2f(Point2f.(x, y)), color=:red) + scatter!(ax, x, y, color=:red, markersize=5) end f end - - @reference_test "hexbin two cellsizes" begin - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) x = RNG.rand(300) y = RNG.rand(300) for (i, cellsize) in enumerate([0.1, 0.15, 0.2, 0.25]) - ax = Axis(f[fldmod1(i, 2)...], title = "cellsize = ($cellsize, $cellsize)", aspect = DataAspect()) - hexbin!(ax, x, y, cellsize = (cellsize, cellsize)) - wireframe!(ax, Rect2f(Point2f.(x, y)), color = :red) - scatter!(ax, x, y, color = :red, markersize = 5) + ax = Axis(f[fldmod1(i, 2)...], title="cellsize = ($cellsize, $cellsize)", aspect=DataAspect()) + hexbin!(ax, x, y, cellsize=(cellsize, cellsize)) + wireframe!(ax, Rect2f(Point2f.(x, y)), color=:red) + scatter!(ax, x, y, color=:red, markersize=5) end f end @reference_test "hexbin one cellsize" begin - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) x = RNG.rand(300) y = RNG.rand(300) for (i, cellsize) in enumerate([0.1, 0.15, 0.2, 0.25]) - ax = Axis(f[fldmod1(i, 2)...], title = "cellsize = $cellsize", aspect = DataAspect()) - hexbin!(ax, x, y, cellsize = cellsize) - wireframe!(ax, Rect2f(Point2f.(x, y)), color = :red) - scatter!(ax, x, y, color = :red, markersize = 5) + ax = Axis(f[fldmod1(i, 2)...], title="cellsize = $cellsize", aspect=DataAspect()) + hexbin!(ax, x, y, cellsize=cellsize) + wireframe!(ax, Rect2f(Point2f.(x, y)), color=:red) + scatter!(ax, x, y, color=:red, markersize=5) end f end @reference_test "hexbin threshold" begin - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) x = RNG.randn(100000) y = RNG.randn(100000) for (i, threshold) in enumerate([1, 10, 100, 500]) - ax = Axis(f[fldmod1(i, 2)...], title = "threshold = $threshold", aspect = DataAspect()) - hexbin!(ax, x, y, cellsize = 0.4, threshold = threshold) + ax = Axis(f[fldmod1(i, 2)...], title="threshold = $threshold", aspect=DataAspect()) + hexbin!(ax, x, y, cellsize=0.4, threshold=threshold) end f end @@ -788,10 +837,8 @@ end y = RNG.randn(100000) f = Figure() - hexbin(f[1, 1], x, y, bins = 40, - axis = (aspect = DataAspect(), title = "scale = identity")) - hexbin(f[1, 2], x, y, bins = 40, scale=log10, - axis = (aspect = DataAspect(), title = "scale = log10")) + hexbin(f[1, 1], x, y, bins=40, axis=(aspect=DataAspect(), title="scale = identity")) + hexbin(f[1, 2], x, y, bins=40, scale=log10, axis=(aspect=DataAspect(), title="scale = log10")) f end @@ -812,24 +859,25 @@ end # end @reference_test "Latex labels after the fact" begin - f = Figure(fontsize = 50) + f = Figure(fontsize=50) ax = Axis(f[1, 1]) - ax.xticks = ([3, 6, 9], [L"x" , L"y" , L"z"]) - ax.yticks = ([3, 6, 9], [L"x" , L"y" , L"z"]) + ax.xticks = ([3, 6, 9], [L"x", L"y", L"z"]) + ax.yticks = ([3, 6, 9], [L"x", L"y", L"z"]) f end @reference_test "Rich text" begin - f = Figure(fontsize = 30, resolution = (800, 600)) - ax = Axis(f[1, 1], - limits = (1, 100, 0.001, 1), - xscale = log10, - yscale = log2, - title = rich("A ", rich("title", color = :red, font = :bold_italic)), - xlabel = rich("X", subscript("label", fontsize = 25)), - ylabel = rich("Y", superscript("label")), + f = Figure(fontsize=30, resolution=(800, 600)) + ax = Axis( + f[1, 1], + limits=(1, 100, 0.001, 1), + xscale=log10, + yscale=log2, + title=rich("A ", rich("title", color=:red, font=:bold_italic)), + xlabel=rich("X", subscript("label", fontsize=25)), + ylabel=rich("Y", superscript("label")), ) - Label(f[1, 2], rich("Hi", rich("Hi", offset = (0.2, 0.2), color = :blue)), tellheight = false) - Label(f[1, 3], rich("X", superscript("super"), subscript("sub")), tellheight = false) + Label(f[1, 2], rich("Hi", rich("Hi", offset=(0.2, 0.2), color=:blue)), tellheight=false) + Label(f[1, 3], rich("X", superscript("super"), subscript("sub")), tellheight=false) f end diff --git a/ReferenceTests/src/tests/examples3d.jl b/ReferenceTests/src/tests/examples3d.jl index 938ef68f456..f65799032de 100644 --- a/ReferenceTests/src/tests/examples3d.jl +++ b/ReferenceTests/src/tests/examples3d.jl @@ -1,14 +1,14 @@ @reference_test "Image on Geometry (Moon)" begin moon = loadasset("moon.png") - fig, ax, meshplot = mesh(Sphere(Point3f(0), 1f0), color=moon, shading=false, axis = (;show_axis=false)) + fig, ax, meshplot = mesh(Sphere(Point3f(0), 1.0f0), color=moon, shading=false, axis=(; show_axis=false)) update_cam!(ax.scene, Vec3f(-2, 2, 2), Vec3f(0)) fig end @reference_test "Image on Geometry (Earth)" begin earth = loadasset("earth.png") - m = uv_mesh(Tesselation(Sphere(Point3f(0), 1f0), 60)) + m = uv_mesh(Tesselation(Sphere(Point3f(0), 1.0f0), 60)) mesh(m, color=earth, shading=false) end @@ -19,11 +19,13 @@ end return GeometryBasics.pointmeta(mesh1; color=fill(color, npoints)) end # create an array of differently colored boxes in the direction of the 3 axes - x = Vec3f(0); baselen = 0.2f0; dirlen = 1f0 + x = Vec3f(0) + baselen = 0.2f0 + dirlen = 1.0f0 rectangles = [ (Rect(Vec3f(x), Vec3f(dirlen, baselen, baselen)), RGBAf(1, 0, 0, 1)), (Rect(Vec3f(x), Vec3f(baselen, dirlen, baselen)), RGBAf(0, 1, 0, 1)), - (Rect(Vec3f(x), Vec3f(baselen, baselen, dirlen)), RGBAf(0, 0, 1, 1)) + (Rect(Vec3f(x), Vec3f(baselen, baselen, dirlen)), RGBAf(0, 0, 1, 1)), ] meshes = map(colormesh, rectangles) @@ -31,12 +33,9 @@ end scene = ax.scene center!(scene) cam = cameracontrols(scene) - dir = widths(data_limits(scene)) ./ 2. - dir_scaled = Vec3f( - dir[1] * scene.transformation.scale[][1], - 0.0, - dir[3] * scene.transformation.scale[][2], - ) + dir = widths(data_limits(scene)) ./ 2.0 + dir_scaled = + Vec3f(dir[1] * scene.transformation.scale[][1], 0.0, dir[3] * scene.transformation.scale[][2]) cam.upvector[] = (0.0, 0.0, 1.0) cam.lookat[] = minimum(data_limits(scene)) + dir_scaled cam.eyeposition[] = (cam.lookat[][1], cam.lookat[][2] + 6.3, cam.lookat[][3]) @@ -68,7 +67,7 @@ end j = [1, 2, 3, 2] k = [2, 3, 1, 3] # indices interpreted as triangles (every 3 sequential indices) - indices = [1, 2, 3, 1, 3, 4, 1, 4, 2, 2, 3, 4] + indices = [1, 2, 3, 1, 3, 4, 1, 4, 2, 2, 3, 4] mesh(x, y, z, indices, color=color) end @@ -77,13 +76,13 @@ end end @reference_test "Wireframe of Sphere" begin - wireframe(Sphere(Point3f(0), 1f0)) + wireframe(Sphere(Point3f(0), 1.0f0)) end @reference_test "Wireframe of a Surface" begin function xy_data(x, y) r = sqrt(x^2 + y^2) - r == 0.0 ? 1f0 : (sin(r) / r) + return r == 0.0 ? 1.0f0 : (sin(r) / r) end N = 30 lspace = range(-10, stop=10, length=N) @@ -96,21 +95,18 @@ end N = 30 function xy_data(x, y) r = sqrt(x^2 + y^2) - r == 0.0 ? 1f0 : (sin(r) / r) + return r == 0.0 ? 1.0f0 : (sin(r) / r) end xrange = range(-2, stop=2, length=N) - surf_func(i) = [Float32(xy_data(x * i, y * i)) for x = xrange, y = xrange] - surface( - xrange, xrange, surf_func(10), - color=RNG.rand(RGBAf, 124, 124) - ) + surf_func(i) = [Float32(xy_data(x * i, y * i)) for x in xrange, y in xrange] + surface(xrange, xrange, surf_func(10), color=RNG.rand(RGBAf, 124, 124)) end @reference_test "Meshscatter Function" begin - large_sphere = Sphere(Point3f(0), 1f0) + large_sphere = Sphere(Point3f(0), 1.0f0) positions = decompose(Point3f, large_sphere) - colS = [RGBAf(RNG.rand(), RNG.rand(), RNG.rand(), 1.0) for i = 1:length(positions)] - sizesS = [RNG.rand(Point3f) .* 0.05f0 for i = 1:length(positions)] + colS = [RGBAf(RNG.rand(), RNG.rand(), RNG.rand(), 1.0) for i in 1:length(positions)] + sizesS = [RNG.rand(Point3f) .* 0.05f0 for i in 1:length(positions)] meshscatter(positions, color=colS, markersize=sizesS) end @@ -131,20 +127,20 @@ end p2 = meshscatter!(ax, lift(t -> f.(t * 2.0, range(0, stop=2pi, length=50), 1.5), t), markersize=0.05) linepoints = lift(p1[1], p2[1]) do pos1, pos2 - map((a, b) -> (a => b), pos1, pos2) + return map((a, b) -> (a => b), pos1, pos2) end linesegments!(ax, linepoints, linestyle=:dot) Record(fig, 1:2) do i - t[] = i / 10 + return t[] = i / 10 end end @reference_test "3D Contour with 2D contour slices" begin function test(x, y, z) xy = [x, y, z] - ((xy') * Matrix(I, 3, 3) * xy) / 20 + return ((xy') * Matrix(I, 3, 3) * xy) / 20 end x = range(-2pi, stop=2pi, length=100) # c[4] == fourth argument of the above plotting command @@ -162,21 +158,21 @@ end @reference_test "Contour3d" begin function xy_data(x, y) r = sqrt(x * x + y * y) - r == 0.0 ? 1f0 : (sin(r) / r) + return r == 0.0 ? 1.0f0 : (sin(r) / r) end r = range(-1, stop=1, length=100) contour3d(r, r, (x, y) -> xy_data(10x, 10y), levels=20, linewidth=3) end @reference_test "Arrows 3D" begin - function SphericalToCartesian(r::T, θ::T, ϕ::T) where T <: AbstractArray + function SphericalToCartesian(r::T, θ::T, ϕ::T) where {T<:AbstractArray} x = @.r * sin(θ) * cos(ϕ) y = @.r * sin(θ) * sin(ϕ) z = @.r * cos(θ) - Point3f.(x, y, z) + return Point3f.(x, y, z) end n = 100^2 # number of points to generate - r = ones(n); + r = ones(n) θ = acos.(1 .- 2 .* RNG.rand(n)) φ = 2π * RNG.rand(n) pts = SphericalToCartesian(r, θ, φ) @@ -185,24 +181,25 @@ end @reference_test "Image on Surface Sphere" begin n = 20 - θ = [0;(0.5:n - 0.5) / n;1] - φ = [(0:2n - 2) * 2 / (2n - 1);2] + θ = [0; (0.5:(n - 0.5)) / n; 1] + φ = [(0:(2n - 2)) * 2 / (2n - 1); 2] x = [cospi(φ) * sinpi(θ) for θ in θ, φ in φ] y = [sinpi(φ) * sinpi(θ) for θ in θ, φ in φ] z = [cospi(θ) for θ in θ, φ in φ] - RNG.rand([-1f0, 1f0], 3) + RNG.rand([-1.0f0, 1.0f0], 3) pts = vec(Point3f.(x, y, z)) f, ax, p = surface(x, y, z, color=Makie.logo(), transparency=true) end @reference_test "Arrows on Sphere" begin n = 20 - f = (x, y, z) -> x * exp(cos(y) * z) - ∇f = (x, y, z) -> Point3f(exp(cos(y) * z), -sin(y) * z * x * exp(cos(y) * z), x * cos(y) * exp(cos(y) * z)) + f = (x, y, z) -> x * exp(cos(y) * z) + ∇f = + (x, y, z) -> Point3f(exp(cos(y) * z), -sin(y) * z * x * exp(cos(y) * z), x * cos(y) * exp(cos(y) * z)) ∇ˢf = (x, y, z) -> ∇f(x, y, z) - Point3f(x, y, z) * dot(Point3f(x, y, z), ∇f(x, y, z)) - θ = [0;(0.5:n - 0.5) / n;1] - φ = [(0:2n - 2) * 2 / (2n - 1);2] + θ = [0; (0.5:(n - 0.5)) / n; 1] + φ = [(0:(2n - 2)) * 2 / (2n - 1); 2] x = [cospi(φ) * sinpi(θ) for θ in θ, φ in φ] y = [sinpi(φ) * sinpi(θ) for θ in θ, φ in φ] z = [cospi(θ) for θ in θ, φ in φ] @@ -210,10 +207,7 @@ end pts = vec(Point3f.(x, y, z)) ∇ˢF = vec(∇ˢf.(x, y, z)) .* 0.1f0 surface(x, y, z) - arrows!( - pts, ∇ˢF, - arrowsize=0.03, linecolor=(:white, 0.6), linewidth=0.03 - ) + arrows!(pts, ∇ˢF, arrowsize=0.03, linecolor=(:white, 0.6), linewidth=0.03) current_figure() end @@ -223,8 +217,8 @@ end f(x, y) = (sin(x * 10) + cos(y * 10)) / 4 fig = Figure() - ax1 = fig[1, 1] = Axis(fig, title = "surface") - ax2 = fig[1, 2] = Axis(fig, title = "contour3d") + ax1 = fig[1, 1] = Axis(fig, title="surface") + ax2 = fig[1, 2] = Axis(fig, title="contour3d") surface!(ax1, vx, vy, f) contour3d!(ax2, vx, vy, (x, y) -> f(x, y), levels=15, linewidth=3) fig @@ -234,12 +228,9 @@ end cat = loadasset("cat.obj") vertices = decompose(Point3f, cat) faces = decompose(TriangleFace{Int}, cat) - coordinates = [vertices[i][j] for i = 1:length(vertices), j = 1:3] - connectivity = [faces[i][j] for i = 1:length(faces), j = 1:3] - mesh( - coordinates, connectivity, - color=RNG.rand(length(vertices)) - ) + coordinates = [vertices[i][j] for i in 1:length(vertices), j in 1:3] + connectivity = [faces[i][j] for i in 1:length(faces), j in 1:3] + mesh(coordinates, connectivity, color=RNG.rand(length(vertices))) end @reference_test "OldAxis + Surface" begin @@ -250,7 +241,7 @@ end scene = Scene(resolution=(500, 500), camera=cam3d!) # One way to style the axis is to pass a nested dictionary / named tuple to it. psurf = surface!(scene, vx, vy, f) - axis3d!(scene, frame = (linewidth = 2.0,)) + axis3d!(scene, frame=(linewidth=2.0,)) center!(scene) # One can also directly get the axis object and manipulate it axis = scene[OldAxis] # get axis @@ -269,9 +260,9 @@ end campixel(scene), "Multipole Representation of first resonances of U-238", position=(wh[1] / 2.0, wh[2] - 20.0), - align=(:center, :center), + align=(:center, :center), fontsize=20, - font="helvetica" + font="helvetica", ) c = lines!(scene, Circle(Point2f(0.1, 0.5), 0.1f0), color=:red, offset=Vec3f(0, 0, 1)) psurf.converted[3][] = f.(vx .+ 0.5, (vy .+ 0.5)') @@ -281,81 +272,85 @@ end @reference_test "Fluctuation 3D" begin # define points/edges perturbfactor = 4e1 - N = 3; nbfacese = 30; radius = 0.02 + N = 3 + nbfacese = 30 + radius = 0.02 - large_sphere = Sphere(Point3f(0), 1f0) + large_sphere = Sphere(Point3f(0), 1.0f0) positions = decompose(Point3f, large_sphere, 30) np = length(positions) - pts = [positions[k][l] for k = 1:length(positions), l = 1:3] + pts = [positions[k][l] for k in 1:length(positions), l in 1:3] pts = vcat(pts, 1.1 .* pts + RNG.randn(size(pts)) / perturbfactor) # light position influence ? edges = hcat(collect(1:np), collect(1:np) .+ np) - ne = size(edges, 1); np = size(pts, 1) - cylinder = Cylinder(Point3f(0), Point3f(0, 0, 1.0), 1f0) + ne = size(edges, 1) + np = size(pts, 1) + cylinder = Cylinder(Point3f(0), Point3f(0, 0, 1.0), 1.0f0) # define markers meshes meshC = normal_mesh(Tesselation(cylinder, nbfacese)) meshS = normal_mesh(Tesselation(large_sphere, 20)) # define colors, markersizes and rotations - pG = [Point3f(pts[k, 1], pts[k, 2], pts[k, 3]) for k = 1:np] - lengthsC = sqrt.(sum((pts[edges[:,1], :] .- pts[edges[:, 2], :]).^2, dims=2)) - sizesC = [Vec3f(radius, radius, lengthsC[i]) for i = 1:ne] - sizesC = [Vec3f(1) for i = 1:ne] - colorsp = [RGBA{Float32}(RNG.rand(), RNG.rand(), RNG.rand(), 1.0) for i = 1:np] - colorsC = [(colorsp[edges[i, 1]] .+ colorsp[edges[i, 2]]) / 2.0 for i = 1:ne] - sizesC = [Vec3f(radius, radius, lengthsC[i]) for i = 1:ne] + pG = [Point3f(pts[k, 1], pts[k, 2], pts[k, 3]) for k in 1:np] + lengthsC = sqrt.(sum((pts[edges[:, 1], :] .- pts[edges[:, 2], :]) .^ 2, dims=2)) + sizesC = [Vec3f(radius, radius, lengthsC[i]) for i in 1:ne] + sizesC = [Vec3f(1) for i in 1:ne] + colorsp = [RGBA{Float32}(RNG.rand(), RNG.rand(), RNG.rand(), 1.0) for i in 1:np] + colorsC = [(colorsp[edges[i, 1]] .+ colorsp[edges[i, 2]]) / 2.0 for i in 1:ne] + sizesC = [Vec3f(radius, radius, lengthsC[i]) for i in 1:ne] Qlist = zeros(ne, 4) - for k = 1:ne + for k in 1:ne ct = Cylinder( Point3f(pts[edges[k, 1], 1], pts[edges[k, 1], 2], pts[edges[k, 1], 3]), Point3f(pts[edges[k, 2], 1], pts[edges[k, 2], 2], pts[edges[k, 2], 3]), - 1f0 + 1.0f0, ) Q = GeometryBasics.rotation(ct) - r = 0.5 * sqrt(1 .+ Q[1, 1] .+ Q[2, 2] .+ Q[3, 3]); Qlist[k, 4] = r + r = 0.5 * sqrt(1 .+ Q[1, 1] .+ Q[2, 2] .+ Q[3, 3]) + Qlist[k, 4] = r Qlist[k, 1] = (Q[3, 2] .- Q[2, 3]) / (4 .* r) Qlist[k, 2] = (Q[1, 3] .- Q[3, 1]) / (4 .* r) Qlist[k, 3] = (Q[2, 1] .- Q[1, 2]) / (4 .* r) end - rotationsC = [Vec4f(Qlist[i, 1], Qlist[i, 2], Qlist[i, 3], Qlist[i, 4]) for i = 1:ne] + rotationsC = [Vec4f(Qlist[i, 1], Qlist[i, 2], Qlist[i, 3], Qlist[i, 4]) for i in 1:ne] # plot - fig, ax, meshplot = meshscatter( - pG[edges[:, 1]], - color=colorsC, marker=meshC, - markersize=sizesC, rotations=rotationsC, - ) - meshscatter!( - ax, pG, - color=colorsp, marker=meshS, markersize=radius, - ) + fig, ax, meshplot = + meshscatter(pG[edges[:, 1]], color=colorsC, marker=meshC, markersize=sizesC, rotations=rotationsC) + meshscatter!(ax, pG, color=colorsp, marker=meshS, markersize=radius) fig end @reference_test "Connected Sphere" begin - large_sphere = Sphere(Point3f(0), 1f0) + large_sphere = Sphere(Point3f(0), 1.0f0) positions = decompose(Point3f, large_sphere) linepos = view(positions, RNG.rand(1:length(positions), 1000)) fig, ax, lineplot = lines(linepos, linewidth=0.1, color=:black, transparency=true) scatter!( - ax, positions, markersize=10, - strokewidth=2, strokecolor=:white, - color=RGBAf(0.9, 0.2, 0.4, 0.3), transparency=true, + ax, + positions, + markersize=10, + strokewidth=2, + strokecolor=:white, + color=RGBAf(0.9, 0.2, 0.4, 0.3), + transparency=true, ) fig end @reference_test "image scatter" begin scatter( - 1:10, 1:10, RNG.rand(10, 10) .* 10, + 1:10, + 1:10, + RNG.rand(10, 10) .* 10, rotations=normalize.(RNG.rand(Quaternionf, 10 * 10)), markersize=20, # can also be an array of images for each point # need to be the same size for best performance, though - marker=Makie.logo() + marker=Makie.logo(), ) end @reference_test "Simple meshscatter" begin - large_sphere = Sphere(Point3f(0), 1f0) + large_sphere = Sphere(Point3f(0), 1.0f0) positions = decompose(Point3f, large_sphere) meshscatter(positions, color=RGBAf(0.9, 0.2, 0.4, 1), markersize=0.05) end @@ -363,19 +358,24 @@ end @reference_test "Animated surface and wireframe" begin function xy_data(x, y) r = sqrt(x^2 + y^2) - r == 0.0 ? 1f0 : (sin(r) / r) + return r == 0.0 ? 1.0f0 : (sin(r) / r) end xrange = range(-2, stop=2, length=50) - surf_func(i) = [Float32(xy_data(x * i, y * i)) for x = xrange, y = xrange] + surf_func(i) = [Float32(xy_data(x * i, y * i)) for x in xrange, y in xrange] z = surf_func(20) fig, ax, surf = surface(xrange, xrange, z) - wf = wireframe!(ax, xrange, xrange, lift(x -> x .+ 1.0, surf[3]), - linewidth=2f0, color=lift(x -> to_colormap(x)[5], surf[:colormap]) + wf = wireframe!( + ax, + xrange, + xrange, + lift(x -> x .+ 1.0, surf[3]), + linewidth=2.0f0, + color=lift(x -> to_colormap(x)[5], surf[:colormap]), ) Record(fig, range(5, stop=40, length=3)) do i - surf[3] = surf_func(i) + return surf[3] = surf_func(i) end end @@ -383,19 +383,18 @@ end x = loadasset("cat.obj") mesh(x, color=:black) pos = map(decompose(Point3f, x), GeometryBasics.normals(x)) do p, n - p => p .+ Point(normalize(n) .* 0.05f0) + return p => p .+ Point(normalize(n) .* 0.05f0) end linesegments!(pos, color=:blue) current_figure() end @reference_test "Sphere Mesh" begin - mesh(Sphere(Point3f(0), 1f0), color=:blue) + mesh(Sphere(Point3f(0), 1.0f0), color=:blue) end @reference_test "Unicode Marker" begin - scatter(Point3f[(1, 0, 0), (0, 1, 0), (0, 0, 1)], marker=[:x, :circle, :cross], - markersize=35) + scatter(Point3f[(1, 0, 0), (0, 1, 0), (0, 0, 1)], marker=[:x, :circle, :cross], markersize=35) end @reference_test "Merged color Mesh" begin @@ -405,11 +404,13 @@ end return GeometryBasics.pointmeta(mesh1; color=fill(color, npoints)) end # create an array of differently colored boxes in the direction of the 3 axes - x = Vec3f(0); baselen = 0.2f0; dirlen = 1f0 + x = Vec3f(0) + baselen = 0.2f0 + dirlen = 1.0f0 rectangles = [ (Rect(Vec3f(x), Vec3f(dirlen, baselen, baselen)), RGBAf(1, 0, 0, 1)), (Rect(Vec3f(x), Vec3f(baselen, dirlen, baselen)), RGBAf(0, 1, 0, 1)), - (Rect(Vec3f(x), Vec3f(baselen, baselen, dirlen)), RGBAf(0, 0, 1, 1)) + (Rect(Vec3f(x), Vec3f(baselen, baselen, dirlen)), RGBAf(0, 0, 1, 1)), ] meshes = map(colormesh, rectangles) @@ -425,14 +426,9 @@ end colors = to_colormap(:RdYlBu) N = 5 Record(f, 1:N) do i - t = i/(N/5) + t = i / (N / 5) if length(lineplots) < 20 - p = lines!( - ax, - us, sin.(us .+ t), zeros(100), - color=colors[length(lineplots)], - linewidth=3 - ) + p = lines!(ax, us, sin.(us .+ t), zeros(100), color=colors[length(lineplots)], linewidth=3) pushfirst!(lineplots, p) translate!(p, 0, 0, 0) else @@ -452,7 +448,7 @@ end N = 51 x = range(-2, stop=2, length=N) y = x - z = (-x .* exp.(-x.^2 .- (y').^2)) .* 4 + z = (-x .* exp.(-x .^ 2 .- (y') .^ 2)) .* 4 fig, ax, surfaceplot = surface(x, y, z) xm, ym, zm = minimum(data_limits(ax.scene)) contour!(ax, x, y, z, levels=15, linewidth=2, transformation=(:xy, zm)) @@ -471,25 +467,38 @@ let @reference_test "Streamplot 3D" begin P = FitzhughNagumo(0.1, 0.0, 1.5, 0.8) - f(x, P::FitzhughNagumo) = Point3f( - (x[1] - x[2] - x[1]^3 + P.s) / P.ϵ, - P.γ * x[2] - x[2] + P.β, - P.γ * x[1] - x[3] - P.β, - ) + function f(x, P::FitzhughNagumo) + return Point3f( + (x[1] - x[2] - x[1]^3 + P.s) / P.ϵ, + P.γ * x[2] - x[2] + P.β, + P.γ * x[1] - x[3] - P.β, + ) + end f(x) = f(x, P) - streamplot(f, -1.5..1.5, -1.5..1.5, -1.5..1.5, colormap=:magma, gridsize=(10, 10), arrow_size=0.1, transparency=true) + streamplot( + f, + -1.5 .. 1.5, + -1.5 .. 1.5, + -1.5 .. 1.5, + colormap=:magma, + gridsize=(10, 10), + arrow_size=0.1, + transparency=true, + ) end end @reference_test "Volume on black background" begin - r = LinRange(-3, 3, 100); # our value range + r = LinRange(-3, 3, 100) # our value range ρ(x, y, z) = exp(-(abs(x))) # function (charge density) fig, ax, pl = volume( - r, r, r, # coordinates to plot on + r, + r, + r, # coordinates to plot on ρ, # charge density (functions as colorant) - algorithm=:mip # maximum-intensity-projection + algorithm=:mip, # maximum-intensity-projection ) ax.scene[OldAxis].names.textcolor = :gray # let axis labels be seen on dark background fig.scene.backgroundcolor[] = to_color(:black) @@ -498,32 +507,32 @@ end @reference_test "Depth Shift" begin # Up to some artifacts from fxaa the left side should be blue and the right red. - fig = Figure(resolution = (800, 400)) + fig = Figure(resolution=(800, 400)) prim = Rect3(Point3f(0), Vec3f(1)) - ps = RNG.rand(Point3f, 10) .+ Point3f(0, 0, 1) + ps = RNG.rand(Point3f, 10) .+ Point3f(0, 0, 1) mat = RNG.rand(4, 4) - A = RNG.rand(4,4,4) + A = RNG.rand(4, 4, 4) # This generates two sets of plots each on two axis. Both axes have one set # without depth_shift (0f0, red) and one at ∓10eps(1f0) (blue, left/right axis). # A negative shift should push the plot in the foreground, positive in the background. - for (i, _shift) in enumerate((-10eps(1f0), 10eps(1f0))) - ax = LScene(fig[1, i], show_axis = false) - - for (color, shift) in zip((:red, :blue), (0f0, _shift)) - mesh!(ax, prim, color = color, depth_shift = shift) - lines!(ax, ps, color = color, depth_shift = shift) - linesegments!(ax, ps .+ Point3f(-1, 1, 0), color = color, depth_shift = shift) - scatter!(ax, ps, color = color, markersize=10, depth_shift = shift) - text!(ax, 0, 1, 1.1, text = "Test", color = color, depth_shift = shift) - surface!(ax, -1..0, 1..2, mat, colormap = [color, color], depth_shift = shift) - meshscatter!(ax, ps .+ Point3f(-1, 1, 0), color = color, depth_shift = shift) + for (i, _shift) in enumerate((-10eps(1.0f0), 10eps(1.0f0))) + ax = LScene(fig[1, i], show_axis=false) + + for (color, shift) in zip((:red, :blue), (0.0f0, _shift)) + mesh!(ax, prim, color=color, depth_shift=shift) + lines!(ax, ps, color=color, depth_shift=shift) + linesegments!(ax, ps .+ Point3f(-1, 1, 0), color=color, depth_shift=shift) + scatter!(ax, ps, color=color, markersize=10, depth_shift=shift) + text!(ax, 0, 1, 1.1, text="Test", color=color, depth_shift=shift) + surface!(ax, -1 .. 0, 1 .. 2, mat, colormap=[color, color], depth_shift=shift) + meshscatter!(ax, ps .+ Point3f(-1, 1, 0), color=color, depth_shift=shift) # # left side in axis - heatmap!(ax, 0..1, 0..1, mat, colormap = [color, color], depth_shift = shift) + heatmap!(ax, 0 .. 1, 0 .. 1, mat, colormap=[color, color], depth_shift=shift) # # right side in axis - image!(ax, -1..0, 1..2, mat, colormap = [color, color], depth_shift = shift) - p = volume!(ax, A, colormap = [:white, color], depth_shift = shift) + image!(ax, -1 .. 0, 1 .. 2, mat, colormap=[color, color], depth_shift=shift) + p = volume!(ax, A, colormap=[:white, color], depth_shift=shift) translate!(p, -1, 0, 0) scale!(p, 0.25, 0.25, 0.25) end @@ -533,7 +542,6 @@ end fig end - @reference_test "Order Independent Transparency" begin # top row (yellow, cyan, magenta) contains stacks with the same alpha value # bottom row (red, green, blue) contains stacks with varying alpha values @@ -542,34 +550,30 @@ end r = Rect2f(-1, -1, 2, 2) for x in (0, 1) for (i, a) in enumerate((0.25, 0.5, 0.75, 1.0)) - ps = [Point3f(a, (0.15 + 0.01y)*(2x-1) , 0.2y) for y in 1:8] + ps = [Point3f(a, (0.15 + 0.01y) * (2x - 1), 0.2y) for y in 1:8] if x == 0 cs = [RGBAf(1, 0, 0, 0.75), RGBAf(0, 1, 0, 0.5), RGBAf(0, 0, 1, 0.25)] elseif x == 1 cs = [RGBAf(1, x, 0, a), RGBAf(0, 1, x, a), RGBAf(x, 0, 1, a)] end - idxs = [1, 2, 3, 2, 1, 3, 1, 2, 1, 2, 3][i:7+i] - meshscatter!( - ax, ps, marker = r, - color = cs[idxs], transparency = true - ) + idxs = [1, 2, 3, 2, 1, 3, 1, 2, 1, 2, 3][i:(7 + i)] + meshscatter!(ax, ps, marker=r, color=cs[idxs], transparency=true) end end cam = cameracontrols(ax.scene) - cam.attributes.fov[] = 22f0 + cam.attributes.fov[] = 22.0f0 update_cam!(ax.scene, cam, Vec3f(0.625, 0, 3.5), Vec3f(0.625, 0, 0), Vec3f(0, 1, 0)) fig end - @reference_test "space 3D" begin fig = Figure() for ax in [LScene(fig[1, 1]), Axis3(fig[1, 2])] - mesh!(ax, Rect3(Point3f(-10), Vec3f(20)), color = :orange) - mesh!(ax, Rect2f(0.8, 0.1, 0.1, 0.8), space = :relative, color = :blue, shading = false) - linesegments!(ax, Rect2f(-0.5, -0.5, 1, 1), space = :clip, color = :cyan, linewidth = 5) - text!(ax, 0, 0.52, text = "Clip Space", align = (:center, :bottom), space = :clip) - image!(ax, 0..40, 0..800, [x for x in range(0, 1, length=40), _ in 1:10], space = :pixel) + mesh!(ax, Rect3(Point3f(-10), Vec3f(20)), color=:orange) + mesh!(ax, Rect2f(0.8, 0.1, 0.1, 0.8), space=:relative, color=:blue, shading=false) + linesegments!(ax, Rect2f(-0.5, -0.5, 1, 1), space=:clip, color=:cyan, linewidth=5) + text!(ax, 0, 0.52, text="Clip Space", align=(:center, :bottom), space=:clip) + image!(ax, 0 .. 40, 0 .. 800, [x for x in range(0, 1, length=40), _ in 1:10], space=:pixel) end fig end diff --git a/ReferenceTests/src/tests/figures_and_makielayout.jl b/ReferenceTests/src/tests/figures_and_makielayout.jl index fb91ca36a0a..1b06575f285 100644 --- a/ReferenceTests/src/tests/figures_and_makielayout.jl +++ b/ReferenceTests/src/tests/figures_and_makielayout.jl @@ -1,25 +1,25 @@ @reference_test "Figure and Subplots" begin - fig, _ = scatter(RNG.randn(100, 2), color = :red) - scatter(fig[1, 2], RNG.randn(100, 2), color = :blue) - scatter(fig[2, 1:2], RNG.randn(100, 2), color = :green) - scatter(fig[1:2, 3][1:2, 1], RNG.randn(100, 2), color = :black) - scatter(fig[1:2, 3][3, 1], RNG.randn(100, 2), color = :gray) + fig, _ = scatter(RNG.randn(100, 2), color=:red) + scatter(fig[1, 2], RNG.randn(100, 2), color=:blue) + scatter(fig[2, 1:2], RNG.randn(100, 2), color=:green) + scatter(fig[1:2, 3][1:2, 1], RNG.randn(100, 2), color=:black) + scatter(fig[1:2, 3][3, 1], RNG.randn(100, 2), color=:gray) fig end @reference_test "Figure with Blocks" begin - fig = Figure(resolution = (900, 900)) - ax, sc = scatter(fig[1, 1][1, 1], RNG.randn(100, 2), axis = (;title = "Random Dots", xlabel = "Time")) - sc2 = scatter!(ax, RNG.randn(100, 2) .+ 2, color = :red) + fig = Figure(resolution=(900, 900)) + ax, sc = scatter(fig[1, 1][1, 1], RNG.randn(100, 2), axis=(; title="Random Dots", xlabel="Time")) + sc2 = scatter!(ax, RNG.randn(100, 2) .+ 2, color=:red) ll = fig[1, 1][1, 2] = Legend(fig, [sc, sc2], ["Scatter", "Other"]) - lines(fig[2, 1:2][1, 3][1, 1], 0..3, sin ∘ exp, axis = (;title = "Exponential Sine")) + lines(fig[2, 1:2][1, 3][1, 1], 0 .. 3, sin ∘ exp, axis=(; title="Exponential Sine")) heatmap(fig[2, 1:2][1, 1], RNG.randn(30, 30)) - heatmap(fig[2, 1:2][1, 2], RNG.randn(30, 30), colormap = :grays) - lines!(fig[2, 1:2][1, 2], cumsum(RNG.rand(30)), color = :red, linewidth = 10) + heatmap(fig[2, 1:2][1, 2], RNG.randn(30, 30), colormap=:grays) + lines!(fig[2, 1:2][1, 2], cumsum(RNG.rand(30)), color=:red, linewidth=10) surface(fig[1, 2], collect(1.0:40), collect(1.0:40), (x, y) -> 10 * cos(x) * sin(y)) - fig[2, 1:2][2, :] = Colorbar(fig, vertical = false, - height = 20, ticklabelalign = (:center, :top), flipaxis = false) - fig[3, :] = Menu(fig, options = ["A", "B", "C"]) + fig[2, 1:2][2, :] = + Colorbar(fig, vertical=false, height=20, ticklabelalign=(:center, :top), flipaxis=false) + fig[3, :] = Menu(fig, options=["A", "B", "C"]) lt = fig[0, :] = Label(fig, "Figure Demo") fig[5, :] = Textbox(fig) fig @@ -27,21 +27,21 @@ end @reference_test "menus" begin fig = Figure() - funcs = [sqrt, x->x^2, sin, cos] + funcs = [sqrt, x -> x^2, sin, cos] options = zip(["Square Root", "Square", "Sine", "Cosine"], funcs) - menu1 = Menu(fig, options = ["viridis", "heat", "blues"], default = 1) - menu2 = Menu(fig, options = options, default = "Square") - menu3 = Menu(fig, options = options, default = nothing) - menu4 = Menu(fig, options = options, default = nothing) + menu1 = Menu(fig, options=["viridis", "heat", "blues"], default=1) + menu2 = Menu(fig, options=options, default="Square") + menu3 = Menu(fig, options=options, default=nothing) + menu4 = Menu(fig, options=options, default=nothing) fig[1, 1] = grid!( [ - Label(fig, "A", width = nothing) Label(fig, "C", width = nothing); - menu1 menu3; - Label(fig, "B", width = nothing) Label(fig, "D", width = nothing); - menu2 menu4; - ] + Label(fig, "A", width=nothing) Label(fig, "C", width=nothing) + menu1 menu3 + Label(fig, "B", width=nothing) Label(fig, "D", width=nothing) + menu2 menu4 + ], ) menu2.is_open = true menu4.is_open = true @@ -50,19 +50,19 @@ end @reference_test "Label with text wrapping" begin lorem_ipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - fig = Figure(resolution = (1000, 660)) - m!(fig, lbl) = mesh!(fig.scene, lbl.layoutobservables.computedbbox, color = (:red, 0.5), shading=false) - lbl1 = Label(fig[1, 1:2], "HEADER "^10, fontsize = 40, word_wrap = true) + fig = Figure(resolution=(1000, 660)) + m!(fig, lbl) = mesh!(fig.scene, lbl.layoutobservables.computedbbox, color=(:red, 0.5), shading=false) + lbl1 = Label(fig[1, 1:2], "HEADER "^10, fontsize=40, word_wrap=true) m!(fig, lbl1) - lbl2 = Label(fig[2, 1], lorem_ipsum, word_wrap = true, justification = :left) + lbl2 = Label(fig[2, 1], lorem_ipsum, word_wrap=true, justification=:left) m!(fig, lbl2) lbl3 = Label(fig[2, 2], "Smaller label\n <$('-'^12) pad $('-'^12)>") m!(fig, lbl3) - lbl4 = Label(fig[3, 1], "test", word_wrap = true) + lbl4 = Label(fig[3, 1], "test", word_wrap=true) m!(fig, lbl4) - lbl5 = Label(fig[3, 2], lorem_ipsum, word_wrap = true) + lbl5 = Label(fig[3, 2], lorem_ipsum, word_wrap=true) m!(fig, lbl5) fig end @@ -70,54 +70,50 @@ end @reference_test "Axis titles and subtitles" begin f = Figure() - Axis( - f[1, 1], - title = "First Title", - subtitle = "This is a longer subtitle" - ) + Axis(f[1, 1], title="First Title", subtitle="This is a longer subtitle") Axis( f[1, 2], - title = "Second Title", - subtitle = "This is a longer subtitle", - titlealign = :left, - subtitlecolor = :gray50, - titlegap = 10, - titlesize = 20, - subtitlesize = 15, + title="Second Title", + subtitle="This is a longer subtitle", + titlealign=:left, + subtitlecolor=:gray50, + titlegap=10, + titlesize=20, + subtitlesize=15, ) Axis( f[2, 1], - title = "Third Title", - titlecolor = :gray50, - titlefont = "TeX Gyre Heros Bold Italic Makie", - titlealign = :right, - titlesize = 25, + title="Third Title", + titlecolor=:gray50, + titlefont="TeX Gyre Heros Bold Italic Makie", + titlealign=:right, + titlesize=25, ) Axis( f[2, 2], - title = "Fourth Title\nWith Line Break", - subtitle = "This is an even longer subtitle,\nthat also has a line break.", - titlealign = :left, - subtitlegap = 2, - titlegap = 5, - subtitlefont = "TeX Gyre Heros Italic Makie", - subtitlelineheight = 0.9, - titlelineheight = 0.9, + title="Fourth Title\nWith Line Break", + subtitle="This is an even longer subtitle,\nthat also has a line break.", + titlealign=:left, + subtitlegap=2, + titlegap=5, + subtitlefont="TeX Gyre Heros Italic Makie", + subtitlelineheight=0.9, + titlelineheight=0.9, ) f end @reference_test "Legend draw order" begin - with_theme(Lines = (linewidth = 10,)) do + with_theme(Lines=(linewidth=10,)) do f = Figure() - ax = Axis(f[1, 1], backgroundcolor = :gray80) + ax = Axis(f[1, 1], backgroundcolor=:gray80) for i in 1:3 - lines!(ax,( 1:10) .* i, label = "$i") + lines!(ax, (1:10) .* i, label="$i") end # To verify that RGB values differ across entries - axislegend(ax, position = :lt, patchcolor = :red, patchsize = (100, 100), bgcolor = :gray50); - Legend(f[1, 2], ax, patchcolor = :gray80, patchsize = (100, 100), bgcolor = :gray50); - f + axislegend(ax, position=:lt, patchcolor=:red, patchsize=(100, 100), bgcolor=:gray50) + Legend(f[1, 2], ax, patchcolor=:gray80, patchsize=(100, 100), bgcolor=:gray50) + return f end end diff --git a/ReferenceTests/src/tests/primitives.jl b/ReferenceTests/src/tests/primitives.jl index 0d64146d5dd..c3d96cac2f9 100644 --- a/ReferenceTests/src/tests/primitives.jl +++ b/ReferenceTests/src/tests/primitives.jl @@ -1,19 +1,17 @@ # @reference_test "lines and linestyles" begin quote # For now disabled until we fix GLMakie linestyle - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(resolution=(800, 800), camera=campixel!) scalar = 30 points = Point2f[(1, 1), (1, 2), (2, 3), (2, 1)] - linestyles = [ - :solid, :dash, :dot, :dashdot, :dashdotdot, - [1, 2, 3], [1, 2, 4, 5] - ] + linestyles = [:solid, :dash, :dot, :dashdot, :dashdotdot, [1, 2, 3], [1, 2, 4, 5]] for linewidth in 1:10 for (i, linestyle) in enumerate(linestyles) - lines!(s, - scalar .* (points .+ Point2f(linewidth*2, i * 3.25)), - linewidth = linewidth, - linestyle = linestyle, + lines!( + s, + scalar .* (points .+ Point2f(linewidth * 2, i * 3.25)), + linewidth=linewidth, + linestyle=linestyle, ) end end @@ -21,7 +19,7 @@ quote end @reference_test "lines with gaps" begin - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(resolution=(800, 800), camera=campixel!) points = [ Point2f[(1, 0), (2, 0.5), (NaN, NaN), (4, 0.5), (5, 0)], Point2f[(NaN, NaN), (2, 0.5), (3, 0), (4, 0.5), (5, 0)], @@ -31,143 +29,129 @@ end Point2f[(NaN, NaN), (NaN, NaN), (NaN, NaN), (NaN, NaN), (NaN, NaN)], ] for (i, p) in enumerate(points) - lines!(s, (p .+ Point2f(0, i)) .* 100, linewidth = 10) + lines!(s, (p .+ Point2f(0, i)) .* 100, linewidth=10) end s end @reference_test "scatters" begin - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(resolution=(800, 800), camera=campixel!) markersizes = 0:2:30 - markers = [:circle, :rect, :cross, :utriangle, :dtriangle, - 'a', 'x', 'h', 'g', 'Y', 'J', 'α', '↑' - ] + markers = [:circle, :rect, :cross, :utriangle, :dtriangle, 'a', 'x', 'h', 'g', 'Y', 'J', 'α', '↑'] for (i, ms) in enumerate(markersizes) for (j, m) in enumerate(markers) - scatter!(s, - Point2f(i, j) .* 45, - marker = m, - markersize = ms, - ) + scatter!(s, Point2f(i, j) .* 45, marker=m, markersize=ms) end end s end @reference_test "scatter rotations" begin - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(resolution=(800, 800), camera=campixel!) - rotations = range(0, 2pi, length = 15) - markers = [:circle, :rect, :cross, :utriangle, :dtriangle, - 'a', 'x', 'h', 'g', 'Y', 'J', 'α', '↑' - ] + rotations = range(0, 2pi, length=15) + markers = [:circle, :rect, :cross, :utriangle, :dtriangle, 'a', 'x', 'h', 'g', 'Y', 'J', 'α', '↑'] for (i, rot) in enumerate(rotations) for (j, m) in enumerate(markers) p = Point2f(i, j) .* 45 - scatter!(s, - p, - marker = m, - markersize = 30, - rotations = rot, - ) - scatter!(s, p, color = :red, markersize = 6) + scatter!(s, p, marker=m, markersize=30, rotations=rot) + scatter!(s, p, color=:red, markersize=6) end end s end @reference_test "scatter with stroke" begin - s = Scene(resolution = (350, 700), camera = campixel!) + s = Scene(resolution=(350, 700), camera=campixel!) # half stroke, half glow strokes = range(1, 4, length=7) outline_colors = [:red, :green, :blue, :yellow, :purple, :cyan, :black] colors = [ - :red, :green, :blue, - :yellow, :purple, :cyan, - :white, :black, - RGBAf(1, 0, 0, 0), RGBAf(0, 1, 0, 0), RGBAf(0, 0, 1, 0), - RGBAf(1, 0, 1, 0), RGBAf(0, 1, 1, 0), RGBAf(1, 1, 0, 0), + :red, + :green, + :blue, + :yellow, + :purple, + :cyan, + :white, + :black, + RGBAf(1, 0, 0, 0), + RGBAf(0, 1, 0, 0), + RGBAf(0, 0, 1, 0), + RGBAf(1, 0, 1, 0), + RGBAf(0, 1, 1, 0), + RGBAf(1, 1, 0, 0), ] - markers = [:circle, :rect, :cross, :utriangle, :dtriangle, - 'a', 'x', 'h', 'g', 'Y', 'J', 'α', '↑', 'o' - ] + markers = [:circle, :rect, :cross, :utriangle, :dtriangle, 'a', 'x', 'h', 'g', 'Y', 'J', 'α', '↑', 'o'] for i in eachindex(strokes) oc = outline_colors[i] strokewidth = strokes[i] for (j, (m, c)) in enumerate(zip(markers, colors)) p = Point2f(i, j) .* 45 - scatter!(s, - p, - marker = m, markersize = 30, color = c, - strokewidth = strokewidth, strokecolor = oc, - ) + scatter!(s, p, marker=m, markersize=30, color=c, strokewidth=strokewidth, strokecolor=oc) end end s end @reference_test "scatter with glow" begin - s = Scene(resolution = (350, 700), camera = campixel!) + s = Scene(resolution=(350, 700), camera=campixel!) # half stroke, half glow glows = range(4, 1, length=7) outline_colors = [:red, :green, :blue, :yellow, :purple, :cyan, :black] colors = [ - :red, :green, :blue, - :yellow, :purple, :cyan, - :white, :black, - RGBAf(1, 0, 0, 0), RGBAf(0, 1, 0, 0), RGBAf(0, 0, 1, 0), - RGBAf(1, 0, 1, 0), RGBAf(0, 1, 1, 0), RGBAf(1, 1, 0, 0), + :red, + :green, + :blue, + :yellow, + :purple, + :cyan, + :white, + :black, + RGBAf(1, 0, 0, 0), + RGBAf(0, 1, 0, 0), + RGBAf(0, 0, 1, 0), + RGBAf(1, 0, 1, 0), + RGBAf(0, 1, 1, 0), + RGBAf(1, 1, 0, 0), ] - markers = [:circle, :rect, :cross, :utriangle, :dtriangle, - 'a', 'x', 'h', 'g', 'Y', 'J', 'α', '↑', 'o' - ] + markers = [:circle, :rect, :cross, :utriangle, :dtriangle, 'a', 'x', 'h', 'g', 'Y', 'J', 'α', '↑', 'o'] for i in eachindex(glows) oc = outline_colors[i] glowwidth = glows[i] for (j, (m, c)) in enumerate(zip(markers, colors)) p = Point2f(i, j) .* 45 - scatter!(s, - p, - marker = m, markersize = 30, color = c, - glowwidth = glowwidth, glowcolor = oc, - ) + scatter!(s, p, marker=m, markersize=30, color=c, glowwidth=glowwidth, glowcolor=oc) end end s end - @reference_test "scatter image markers" begin - pixel_types = [ RGBA, RGBAf, RGBA{Float16}, ARGB, ARGB{Float16}, RGB, RGBf, RGB{Float16} ] - rotations = [ 2pi/3 * (i-1) for i = 1:length(pixel_types) ] - s = Scene(resolution = (100+100*length(pixel_types), 400), camera = campixel!) + pixel_types = [RGBA, RGBAf, RGBA{Float16}, ARGB, ARGB{Float16}, RGB, RGBf, RGB{Float16}] + rotations = [2pi / 3 * (i - 1) for i in 1:length(pixel_types)] + s = Scene(resolution=(100 + 100 * length(pixel_types), 400), camera=campixel!) filename = Makie.assetpath("icon_transparent.png") marker_image = FileIO.load(filename) for (i, (rot, pxtype)) in enumerate(zip(rotations, pixel_types)) marker = convert.(pxtype, marker_image) - p = Point2f((i-1) * 100 + 100, 200) - scatter!(s, - p, - marker = marker, - markersize = 75, - rotations = rot, - ) + p = Point2f((i - 1) * 100 + 100, 200) + scatter!(s, p, marker=marker, markersize=75, rotations=rot) end s end - @reference_test "basic polygon shapes" begin - s = Scene(resolution = (800, 800), camera = campixel!) + s = Scene(resolution=(800, 800), camera=campixel!) scalefactor = 70 Pol = Makie.GeometryBasics.Polygon polys = [ @@ -180,7 +164,7 @@ end # one hole Pol( Point2f[(1, 1), (1, 2), (2, 2), (2, 1)], - [Point2f[(1.3, 1.3), (1.3, 1.7), (1.7, 1.7), (1.7, 1.3)]] + [Point2f[(1.3, 1.3), (1.3, 1.7), (1.7, 1.7), (1.7, 1.3)]], ), # two holes Pol( @@ -188,39 +172,30 @@ end [ Point2f[(1.15, 1.15), (1.15, 1.85), (1.4, 1.85), (1.4, 1.15)], Point2f[(1.6, 1.15), (1.6, 1.85), (1.85, 1.85), (1.85, 1.15)], - ] + ], ), # hole half same as exterior - Pol( - Point2f[(1, 1), (1, 2), (2, 2), (2, 1)], - [Point2f[(1, 1), (1, 2), (2, 2)]], - ), + Pol(Point2f[(1, 1), (1, 2), (2, 2), (2, 1)], [Point2f[(1, 1), (1, 2), (2, 2)]]), # point self intersection - Pol( - Point2f[(1, 1), (2, 1), (2, 2), (1.5, 1), (1, 2)], - ), + Pol(Point2f[(1, 1), (2, 1), (2, 2), (1.5, 1), (1, 2)]), ] linewidths = 0:2:9 for (i, p) in enumerate(polys) for (j, lw) in enumerate(linewidths) - t = Transformation(scale=Vec3f(scalefactor), translation = Vec3f(1.3 * (i-1), 1.3 * j, 0) .* scalefactor) - poly!( - s, - p, - transformation = t, - color = (:red, 0.5), - strokewidth = lw, + t = Transformation( + scale=Vec3f(scalefactor), + translation=Vec3f(1.3 * (i - 1), 1.3 * j, 0) .* scalefactor, ) + poly!(s, p, transformation=t, color=(:red, 0.5), strokewidth=lw) end end s end - @reference_test "BezierPath markers" begin - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) ax = Axis(f[1, 1]) markers = [ @@ -247,16 +222,15 @@ end ] for (i, marker) in enumerate(markers) - scatter!(Point2f.(1:5, i), marker = marker, markersize = range(10, 30, length = 5), color = :black) - scatter!(Point2f.(1:5, i), markersize = 4, color = :white) + scatter!(Point2f.(1:5, i), marker=marker, markersize=range(10, 30, length=5), color=:black) + scatter!(Point2f.(1:5, i), markersize=4, color=:white) end f end - @reference_test "complex_bezier_markers" begin - f = Figure(resolution = (800, 800)) + f = Figure(resolution=(800, 800)) ax = Axis(f[1, 1]) arrow = BezierPath([ @@ -268,7 +242,7 @@ end LineTo(Point(-0.3, -1)), LineTo(Point(-0.15, -0.3)), LineTo(Point(-0.3, -0.3)), - ClosePath() + ClosePath(), ]) circle_with_hole = BezierPath([ @@ -283,38 +257,35 @@ end batsymbol_string = "M96.84 141.998c-4.947-23.457-20.359-32.211-25.862-13.887-11.822-22.963-37.961-16.135-22.041 6.289-3.005-1.295-5.872-2.682-8.538-4.191-8.646-5.318-15.259-11.314-19.774-17.586-3.237-5.07-4.994-10.541-4.994-16.229 0-19.774 21.115-36.758 50.861-43.694.446-.078.909-.154 1.372-.231-22.657 30.039 9.386 50.985 15.258 24.645l2.528-24.367 5.086 6.52H103.205l5.07-6.52 2.543 24.367c5.842 26.278 37.746 5.502 15.414-24.429 29.777 6.951 50.891 23.936 50.891 43.709 0 15.136-12.406 28.651-31.609 37.267 14.842-21.822-10.867-28.266-22.549-5.549-5.502-18.325-21.147-9.341-26.125 13.886z" batsymbol = Makie.scale( - BezierPath(batsymbol_string, fit = true, flipy = true, bbox = Rect2f((0, 0), (1, 1)), keep_aspect = false), - 1.5 + BezierPath(batsymbol_string, fit=true, flipy=true, bbox=Rect2f((0, 0), (1, 1)), keep_aspect=false), + 1.5, ) gh_string = "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" - github = BezierPath(gh_string, fit = true, flipy = true) - - two_circles_with_holes = Makie.scale(BezierPath([ - MoveTo(Point(2.25, 0)), - EllipticalArc(Point(1.25, 0), 1, 1, 0, 0, 2pi), - ClosePath(), - MoveTo(Point(-0.25, 0)), - EllipticalArc(Point(-1.25, 0), 1, 1, 0, 0, 2pi), - ClosePath(), - MoveTo(Point(2, 0)), - EllipticalArc(Point(1.25, 0), 0.75, 0.75, 0, 0, -2pi), - ClosePath(), - MoveTo(Point(-1, 0)), - EllipticalArc(Point(-1.25, 0), 0.25, 0.25, 0, 0, -2pi), - ClosePath(), - ]), 0.5) + github = BezierPath(gh_string, fit=true, flipy=true) + + two_circles_with_holes = Makie.scale( + BezierPath([ + MoveTo(Point(2.25, 0)), + EllipticalArc(Point(1.25, 0), 1, 1, 0, 0, 2pi), + ClosePath(), + MoveTo(Point(-0.25, 0)), + EllipticalArc(Point(-1.25, 0), 1, 1, 0, 0, 2pi), + ClosePath(), + MoveTo(Point(2, 0)), + EllipticalArc(Point(1.25, 0), 0.75, 0.75, 0, 0, -2pi), + ClosePath(), + MoveTo(Point(-1, 0)), + EllipticalArc(Point(-1.25, 0), 0.25, 0.25, 0, 0, -2pi), + ClosePath(), + ]), + 0.5, + ) - markers = [ - arrow, - circle_with_hole, - batsymbol, - github, - two_circles_with_holes, - ] + markers = [arrow, circle_with_hole, batsymbol, github, two_circles_with_holes] for (i, marker) in enumerate(markers) - scatter!(Point2f.(1:5, i), marker = marker, markersize = range(10, 50, length = 5), color = :black) + scatter!(Point2f.(1:5, i), marker=marker, markersize=range(10, 50, length=5), color=:black) end limits!(ax, 0, 6, 0, length(markers) + 1) @@ -325,12 +296,17 @@ end @reference_test "polygon markers" begin p_big = decompose(Point2f, Circle(Point2f(0), 1)) p_small = decompose(Point2f, Circle(Point2f(0), 0.5)) - marker = [Polygon(p_big, [p_small]), Polygon(reverse(p_big), [p_small]), Polygon(p_big, [reverse(p_small)]), Polygon(reverse(p_big), [reverse(p_small)])] + marker = [ + Polygon(p_big, [p_small]), + Polygon(reverse(p_big), [p_small]), + Polygon(p_big, [reverse(p_small)]), + Polygon(reverse(p_big), [reverse(p_small)]), + ] scatter(1:4, fill(0, 4), marker=marker, markersize=100, color=1:4, axis=(limits=(0, 5, -1, 1),)) end function centered_rect(w, h) - wh, hh = w/2, h/2 + wh, hh = w / 2, h / 2 return Point2f[(-wh, -hh), (-wh, hh), (wh, hh), (wh, -hh)] end @@ -365,7 +341,7 @@ function plot_row!(scene, yoffset, reverse) plot_test!(scene, 0, yoffset + 0, 0.4, reverse) plot_test!(scene, 300, yoffset + 0, 0.3, reverse) plot_test!(scene, 600, yoffset + 0, 0.4, reverse, create_rect) - plot_test!(scene, 900, yoffset + 0, 0.3, reverse, create_rect) + return plot_test!(scene, 900, yoffset + 0, 0.3, reverse, create_rect) end function draw_marker_test!(scene, marker, center; markersize=300) @@ -380,14 +356,19 @@ function draw_marker_test!(scene, marker, center; markersize=300) w, h = widths(inkbb) .* markersize ox, oy = origin(inkbb) .* markersize mhalf = markersize / 2 - bbmin = center .+ Point2f(-w/2, -h/2) + bbmin = center .+ Point2f(-w / 2, -h / 2) inkbb_scaled = Rect2f(bbmin..., w, h) lines!(scene, inkbb_scaled, linewidth=5, color=:green) - points = Point2f[(center[1], center[2] - h/2), (center[1], center[2] + h/2), (center[1] - w/2, center[2]), (center[1] + w/2, center[2])] + points = Point2f[ + (center[1], center[2] - h / 2), + (center[1], center[2] + h / 2), + (center[1] - w / 2, center[2]), + (center[1] + w / 2, center[2]), + ] linesegments!(scene, points, color=:red) - scene + return scene end @reference_test "marke glyph alignment" begin diff --git a/ReferenceTests/src/tests/recipes.jl b/ReferenceTests/src/tests/recipes.jl index 547920a0538..25689eb8aa4 100644 --- a/ReferenceTests/src/tests/recipes.jl +++ b/ReferenceTests/src/tests/recipes.jl @@ -2,12 +2,12 @@ import Makie: Plot, default_theme, plot!, to_value struct Simulation grid::Vector{Point3f} end - # Probably worth having a macro for this! -function Makie.default_theme(scene::SceneLike, ::Type{<: Plot(Simulation)}) - Theme( +# Probably worth having a macro for this! +function Makie.default_theme(scene::SceneLike, ::Type{<:Plot(Simulation)}) + return Theme( advance=0, molecule_sizes=[0.08, 0.04, 0.04], - molecule_colors=[:maroon, :deepskyblue2, :deepskyblue2] + molecule_colors=[:maroon, :deepskyblue2, :deepskyblue2], ) end # The recipe! - will get called for plot(!)(x::SimulationResult) @@ -15,19 +15,19 @@ function Makie.plot!(p::Plot(Simulation)) sim = to_value(p[1]) # first argument is the SimulationResult # when advance changes, get new positions from the simulation mpos = lift(p[:advance]) do i - sim.grid .+ RNG.rand(Point3f, length(sim.grid)) .* 0.01f0 + return sim.grid .+ RNG.rand(Point3f, length(sim.grid)) .* 0.01f0 end # size shouldn't change, so we might as well get the value instead of signal pos = to_value(mpos) N = length(pos) sizes = lift(p[:molecule_sizes]) do s - repeat(s, outer=N ÷ 3) + return repeat(s, outer=N ÷ 3) end sizes = lift(p[:molecule_sizes]) do s - repeat(s, outer=N ÷ 3) + return repeat(s, outer=N ÷ 3) end colors = lift(p[:molecule_colors]) do c - repeat(c, outer=N ÷ 3) + return repeat(c, outer=N ÷ 3) end scene = meshscatter!(p, mpos, markersize=sizes, color=colors) indices = Int[] @@ -37,18 +37,18 @@ function Makie.plot!(p::Plot(Simulation)) meshplot = p.plots[end] # meshplot is the last plot we added to p # meshplot[1] -> the positions (first argument) converted to points, so # we don't do the conversion 2 times for linesegments! - linesegments!(p, lift(x -> view(x, indices), meshplot[1])) + return linesegments!(p, lift(x -> view(x, indices), meshplot[1])) end @reference_test "Type recipe for molecule simulation" begin - # To write out a video of the whole simulation n = 5 r = range(-1, stop=1, length=n) grid = Point3f.(r, reshape(r, (1, n, 1)), reshape(r, (1, 1, n))) - molecules = map(1:(n^3) * 3) do i + molecules = map(1:((n^3) * 3)) do i i3 = ((i - 1) ÷ 3) + 1 - xy = 0.1; z = 0.08 + xy = 0.1 + z = 0.08 i % 3 == 1 && return grid[i3] i % 3 == 2 && return grid[i3] + Point3f(xy, xy, z) i % 3 == 0 && return grid[i3] + Point3f(-xy, xy, z) @@ -56,6 +56,6 @@ end result = Simulation(molecules) fig, ax, molecule_plot = plot(result) Record(fig, 1:3) do i - molecule_plot[:advance] = i + return molecule_plot[:advance] = i end end diff --git a/ReferenceTests/src/tests/short_tests.jl b/ReferenceTests/src/tests/short_tests.jl index 1518f5482d7..3cb3a9f70db 100644 --- a/ReferenceTests/src/tests/short_tests.jl +++ b/ReferenceTests/src/tests/short_tests.jl @@ -1,6 +1,11 @@ -@reference_test "thick arc" arc(Point2f(0), 10f0, 0f0, pi, linewidth=20) +@reference_test "thick arc" arc(Point2f(0), 10.0f0, 0.0f0, pi, linewidth=20) -@reference_test "stroked rect poly" poly(Recti(0, 0, 200, 200), strokewidth=20, strokecolor=:red, color=(:black, 0.4)) +@reference_test "stroked rect poly" poly( + Recti(0, 0, 200, 200), + strokewidth=20, + strokecolor=:red, + color=(:black, 0.4), +) @reference_test "array of rects poly" begin f, ax, pl = poly([Rect(0, 0, 20, 20)]) @@ -15,14 +20,26 @@ end end @reference_test "lines number color" lines(RNG.rand(10), RNG.rand(10), color=RNG.rand(10), linewidth=10) -@reference_test "lines array of colors" lines(RNG.rand(10), RNG.rand(10), color=RNG.rand(RGBAf, 10), linewidth=10) -@reference_test "scatter interval" scatter(0..1, RNG.rand(10), markersize=RNG.rand(10) .* 20) +@reference_test "lines array of colors" lines( + RNG.rand(10), + RNG.rand(10), + color=RNG.rand(RGBAf, 10), + linewidth=10, +) +@reference_test "scatter interval" scatter(0 .. 1, RNG.rand(10), markersize=RNG.rand(10) .* 20) @reference_test "scatter linrange" scatter(LinRange(0, 1, 10), RNG.rand(10)) @reference_test "scatter rotation" begin angles = range(0, stop=2pi, length=20) pos = Point2f.(sin.(angles), cos.(angles)) - f, ax, pl = scatter(pos, markersize=0.2, markerspace=:data, rotations=-angles, marker='▲', axis=(;aspect = DataAspect())) + f, ax, pl = scatter( + pos, + markersize=0.2, + markerspace=:data, + rotations=-angles, + marker='▲', + axis=(; aspect=DataAspect()), + ) scatter!(pos, markersize=10, color=:red) f end @@ -34,40 +51,72 @@ end @reference_test "contour with levels" contour(RNG.randn(100, 90), levels=3) @reference_test "contour with levels array" contour(RNG.randn(100, 90), levels=[0.1, 0.5, 0.8]) -@reference_test "contour with color per level" contour(RNG.randn(33, 30), levels=[0.1, 0.5, 0.9], color=[:black, :green, (:blue, 0.4)], linewidth=2) +@reference_test "contour with color per level" contour( + RNG.randn(33, 30), + levels=[0.1, 0.5, 0.9], + color=[:black, :green, (:blue, 0.4)], + linewidth=2, +) @reference_test "contour with colorrange" contour( - RNG.rand(33, 30) .* 6 .- 3, levels=[-2.5, 0.4, 0.5, 0.6, 2.5], + RNG.rand(33, 30) .* 6 .- 3, + levels=[-2.5, 0.4, 0.5, 0.6, 2.5], colormap=[(:black, 0.2), :red, :blue, :green, (:black, 0.2)], - colorrange=(0.2, 0.8) + colorrange=(0.2, 0.8), ) @reference_test "circle line" lines(Circle(Point2f(0), Float32(1))) @reference_test "streamplot with func" begin - v(x::Point2{T}) where T = Point2{T}(x[2], 4 * x[1]) - streamplot(v, -2..2, -2..2) + v(x::Point2{T}) where {T} = Point2{T}(x[2], 4 * x[1]) + streamplot(v, -2 .. 2, -2 .. 2) end -@reference_test "lines with func" lines(-1..1, x -> x^2) -@reference_test "scatter with func" scatter(-1..1, x -> x^2) +@reference_test "lines with func" lines(-1 .. 1, x -> x^2) +@reference_test "scatter with func" scatter(-1 .. 1, x -> x^2) @reference_test "volume translated" begin r = range(-3pi, stop=3pi, length=100) - fig, ax, vplot = Makie.volume(r, r, r, (x, y, z) -> cos(x) + sin(y) + cos(z), algorithm=:iso, isorange=0.1f0, axis = (;show_axis=false)) - v2 = volume!(ax, r, r, r, (x, y, z) -> cos(x) + sin(y) + cos(z), algorithm=:mip, - transformation=(translation=Vec3f(6pi, 0, 0),)) + fig, ax, vplot = Makie.volume( + r, + r, + r, + (x, y, z) -> cos(x) + sin(y) + cos(z), + algorithm=:iso, + isorange=0.1f0, + axis=(; show_axis=false), + ) + v2 = volume!( + ax, + r, + r, + r, + (x, y, z) -> cos(x) + sin(y) + cos(z), + algorithm=:mip, + transformation=(translation=Vec3f(6pi, 0, 0),), + ) fig end -@reference_test "meshscatter color numbers" meshscatter(RNG.rand(10), RNG.rand(10), RNG.rand(10), color=RNG.rand(10)) -@reference_test "meshscatter color array" meshscatter(RNG.rand(10), RNG.rand(10), RNG.rand(10), color=RNG.rand(RGBAf, 10), transparency=true) +@reference_test "meshscatter color numbers" meshscatter( + RNG.rand(10), + RNG.rand(10), + RNG.rand(10), + color=RNG.rand(10), +) +@reference_test "meshscatter color array" meshscatter( + RNG.rand(10), + RNG.rand(10), + RNG.rand(10), + color=RNG.rand(RGBAf, 10), + transparency=true, +) @reference_test "transparent mesh texture" begin - s1 = uv_mesh(Sphere(Point3f(0), 1f0)) - f, ax, pl = mesh(uv_mesh(Sphere(Point3f(0), 1f0)), color=RNG.rand(50, 50)) + s1 = uv_mesh(Sphere(Point3f(0), 1.0f0)) + f, ax, pl = mesh(uv_mesh(Sphere(Point3f(0), 1.0f0)), color=RNG.rand(50, 50)) # ugh, bug In GeometryTypes for UVs of non unit spheres. - s2 = uv_mesh(Sphere(Point3f(0), 1f0)) + s2 = uv_mesh(Sphere(Point3f(0), 1.0f0)) s2.position .= s2.position .+ (Point3f(0, 2, 0),) mesh!(s2, color=RNG.rand(RGBAf, 50, 50)) f @@ -78,7 +127,7 @@ end NR = 31 function xy_data(x, y) r = sqrt(x^2 + y^2) - r == 0.0 ? 1f0 : (sin(r) / r) + return r == 0.0 ? 1.0f0 : (sin(r) / r) end lspace = range(-10, stop=10, length=NL) rspace = range(-10, stop=10, length=NR) @@ -86,10 +135,7 @@ end z = Float32[xy_data(x, y) for x in lspace, y in rspace] l = range(0, stop=3, length=NL) r = range(0, stop=3, length=NR) - surface( - l, r, z, - colormap=:Spectral - ) + surface(l, r, z, colormap=:Spectral) end @reference_test "Matrices of data in surfaces" begin @@ -97,7 +143,7 @@ end NR = 31 function xy_data(x, y) r = sqrt(x^2 + y^2) - r == 0.0 ? 1f0 : (sin(r) / r) + return r == 0.0 ? 1.0f0 : (sin(r) / r) end lspace = range(-10, stop=10, length=NL) rspace = range(-10, stop=10, length=NR) @@ -105,54 +151,45 @@ end z = Float32[xy_data(x, y) for x in lspace, y in rspace] l = range(0, stop=3, length=NL) r = range(0, stop=3, length=NR) - surface( - [l for l in l, r in r], [r for l in l, r in r], z, - colormap=:Spectral - ) + surface([l for l in l, r in r], [r for l in l, r in r], z, colormap=:Spectral) end @reference_test "heatmaps & surface" begin - data = - hcat(LinRange(2, 3, 4), LinRange(2, 2.5, 4), LinRange(2.5, 3, 4), [1, NaN, NaN, 5]) + data = hcat(LinRange(2, 3, 4), LinRange(2, 2.5, 4), LinRange(2.5, 3, 4), [1, NaN, NaN, 5]) fig = Figure() - heatmap( - fig[1, 1], - data, - colorrange = (2, 3), - highclip = :red, - lowclip = :black, - nan_color = (:green, 0.5), - ) + heatmap(fig[1, 1], data, colorrange=(2, 3), highclip=:red, lowclip=:black, nan_color=(:green, 0.5)) surface( fig[1, 2], zeros(size(data)), - color = data, - colorrange = (2, 3), - highclip = :red, - lowclip = :black, - nan_color = (:green, 0.5), - shading = false, + color=data, + colorrange=(2, 3), + highclip=:red, + lowclip=:black, + nan_color=(:green, 0.5), + shading=false, ) surface!( Axis(fig[2, 2]), data, - colorrange = (2, 3), - highclip = :red, - lowclip = :black, - nan_color = (:green, 0.5), - shading = false, + colorrange=(2, 3), + highclip=:red, + lowclip=:black, + nan_color=(:green, 0.5), + shading=false, ) fig end @reference_test "log10 heatmap" begin - heatmap(RNG.rand(10, 5), axis = (yscale = log10, xscale=log10)) + heatmap(RNG.rand(10, 5), axis=(yscale=log10, xscale=log10)) end @reference_test "reverse range heatmap" begin - x = [1 0 - 2 3] + x = [ + 1 0 + 2 3 + ] heatmap(1:2, 1:-1:0, x) end @@ -161,15 +198,35 @@ end s = Scene(camera=campixel!, resolution=(res, res)) half = res / 2 linewidth = 10 - xstart = half - (half/2) + xstart = half - (half / 2) xend = xstart + 100 - half_w = linewidth/2 + half_w = linewidth / 2 lines!(s, Point2f[(xstart, half), (xend, half)], linewidth=linewidth) - scatter!(s, Point2f[(xstart, half + half_w), (xstart, half - half_w), (xend, half + half_w), (xend, half - half_w)], color=:red, markersize=2) + scatter!( + s, + Point2f[ + (xstart, half + half_w), + (xstart, half - half_w), + (xend, half + half_w), + (xend, half - half_w), + ], + color=:red, + markersize=2, + ) l2 = linesegments!(s, Point2f[(xstart, half), (xend, half)], linewidth=linewidth, color=:gray) - s2 = scatter!(s, Point2f[(xstart, half + half_w), (xstart, half - half_w), (xend, half + half_w), (xend, half - half_w)], color=:red, markersize=2) + s2 = scatter!( + s, + Point2f[ + (xstart, half + half_w), + (xstart, half - half_w), + (xend, half + half_w), + (xend, half - half_w), + ], + color=:red, + markersize=2, + ) for p in (l2, s2) translate!(p, 0, 20, 0) @@ -179,9 +236,12 @@ end end @reference_test "multipoly with multi strokes" begin - P = Polygon.([Point2f[[0.45, 0.05], [0.64, 0.15], [0.37, 0.62]], - Point2f[[0.32, 0.66], [0.46, 0.59], [0.09, 0.08]]]) - poly(P, color = [:red, :green], strokecolor = [:blue, :red], strokewidth = 2) + P = + Polygon.([ + Point2f[[0.45, 0.05], [0.64, 0.15], [0.37, 0.62]], + Point2f[[0.32, 0.66], [0.46, 0.59], [0.09, 0.08]], + ]) + poly(P, color=[:red, :green], strokecolor=[:blue, :red], strokewidth=2) end @reference_test "fast pixel marker" begin @@ -198,7 +258,7 @@ end @reference_test "barplot lowclip highclip nan_color" begin f = Figure() - attrs = (color=[-Inf, 2, NaN, Inf], colorrange=(2, 3), highclip = :red, lowclip=:green, nan_color=:black) + attrs = (color=[-Inf, 2, NaN, Inf], colorrange=(2, 3), highclip=:red, lowclip=:green, nan_color=:black) barplot(f[1, 1], 1:4; attrs...) poly( f[1, 2], @@ -208,18 +268,26 @@ end Point2f[(2, 1), (4, 1), (4, 2), (2, 2)], Point2f[(0, 1), (2, 1), (2, 2), (0, 2)], ]; - strokewidth=2, attrs... + strokewidth=2, + attrs..., ) meshscatter(f[2, 1], 1:4, zeros(4), 1:4; attrs...) volcano = readdlm(Makie.assetpath("volcano.csv"), ',', Float64) - ax, cf = contourf(f[2, 2], volcano, levels = range(100, 180, length = 10), extendlow = :green, extendhigh = :red, nan_color=:black) + ax, cf = contourf( + f[2, 2], + volcano, + levels=range(100, 180, length=10), + extendlow=:green, + extendhigh=:red, + nan_color=:black, + ) Colorbar(f[:, 3], cf) f end @reference_test "Colorbar" begin f = Figure() - Colorbar(f[1, 1]; size = 200) + Colorbar(f[1, 1]; size=200) f end @@ -237,7 +305,7 @@ end # https://github.com/MakieOrg/Makie.jl/issues/2392 Makie.inline!(false) f = Figure() - Menu(f[1,1], options=["one", "two", "three"]) + Menu(f[1, 1], options=["one", "two", "three"]) screen = display(f; visible=false) # Close the window & redisplay close(screen) @@ -246,18 +314,17 @@ end end @reference_test "space test in transformed axis" begin - f = lines(exp.(0.1*(1.0:100)); axis=(yscale=log10,)) + f = lines(exp.(0.1 * (1.0:100)); axis=(yscale=log10,)) poly!(Rect(1, 1, 100, 100), color=:red, space=:pixel) - scatter!(2*mod.(1:100:10000, 97), 2*mod.(1:101:10000, 97), color=:blue, space=:pixel) + scatter!(2 * mod.(1:100:10000, 97), 2 * mod.(1:101:10000, 97), color=:blue, space=:pixel) scatter!(Point2f(0, 0.25), space=:clip) - lines!([0.5,0.5], [0, 1]; space=:relative) - lines!([50,50], [0, 100]; space=:pixel) - lines!([0,1], [0.25, 0.25]; space=:clip) + lines!([0.5, 0.5], [0, 1]; space=:relative) + lines!([50, 50], [0, 100]; space=:pixel) + lines!([0, 1], [0.25, 0.25]; space=:clip) scatter!(Point2f(0.5, 0), space=:relative) f end - # Needs a way to disable autolimits on show # @reference_test "interactions after close" begin # # After saving, interactions may be cleaned up: diff --git a/ReferenceTests/src/tests/text.jl b/ReferenceTests/src/tests/text.jl index d2b128a2e01..ae9c8dc973d 100644 --- a/ReferenceTests/src/tests/text.jl +++ b/ReferenceTests/src/tests/text.jl @@ -1,16 +1,18 @@ @reference_test "heatmap_with_labels" begin - fig = Figure(resolution = (600, 600)) + fig = Figure(resolution=(600, 600)) ax = fig[1, 1] = Axis(fig) values = RNG.rand(10, 10) heatmap!(ax, values) - text!(ax, - string.(round.(vec(values'), digits = 2)), - position = [Point2f(x, y) for x in 1:10 for y in 1:10], - align = (:center, :center), - color = ifelse.(vec(values') .< 0.3, :white, :black), - fontsize = 12) + text!( + ax, + string.(round.(vec(values'), digits=2)), + position=[Point2f(x, y) for x in 1:10 for y in 1:10], + align=(:center, :center), + color=ifelse.(vec(values') .< 0.3, :white, :black), + fontsize=12, + ) fig end @@ -18,152 +20,172 @@ end pos = [Point2f(0, 0), Point2f(10, 10)] fig = text( ["0 is the ORIGIN of this", "10 says hi"], - position = pos, - axis = (aspect = DataAspect(),), - markerspace = :data, - align = (:center, :center), - fontsize = 2) + position=pos, + axis=(aspect=DataAspect(),), + markerspace=:data, + align=(:center, :center), + fontsize=2, + ) scatter!(pos) fig end @reference_test "single_strings_single_positions" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera=campixel!, resolution=(800, 800)) points = [Point(x, y) .* 200 for x in 1:3 for y in 1:3] - scatter!(scene, points, marker = :circle, markersize = 10px) + scatter!(scene, points, marker=:circle, markersize=10px) i = 1 for halign in (:right, :center, :left), valign in (:top, :center, :bottom) - - for rotation in (-pi/6, 0.0, pi/6) - text!(scene, string(halign) * "/" * string(valign) * - " " * string(round(rad2deg(rotation), digits = 0)) * "°", - color = (:black, 0.5), - position = points[i], - align = (halign, valign), - rotation = rotation) + for rotation in (-pi / 6, 0.0, pi / 6) + text!( + scene, + string(halign) * + "/" * + string(valign) * + " " * + string(round(rad2deg(rotation), digits=0)) * + "°", + color=(:black, 0.5), + position=points[i], + align=(halign, valign), + rotation=rotation, + ) end i += 1 end scene end - @reference_test "multi_strings_multi_positions" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera=campixel!, resolution=(800, 800)) - angles = (-pi/6, 0.0, pi/6) + angles = (-pi / 6, 0.0, pi / 6) points = [Point(x, y) .* 200 for x in 1:3 for y in 1:3 for angle in angles] - aligns = [(halign, valign) for halign in - (:right, :center, :left) for valign in (:top, :center, :bottom) for rotation in angles] - rotations = [rotation for _ in - (:right, :center, :left) for _ in (:top, :center, :bottom) for rotation in angles] + aligns = [ + (halign, valign) for halign in (:right, :center, :left) for valign in (:top, :center, :bottom) for + rotation in angles + ] + rotations = + [rotation for _ in (:right, :center, :left) for _ in (:top, :center, :bottom) for rotation in angles] - strings = [string(halign) * "/" * string(valign) * - " " * string(round(rad2deg(rotation), digits = 0)) * "°" - for halign in (:right, :center, :left) - for valign in (:top, :center, :bottom) - for rotation in angles] + strings = [ + string(halign) * "/" * string(valign) * " " * string(round(rad2deg(rotation), digits=0)) * "°" for + halign in (:right, :center, :left) for valign in (:top, :center, :bottom) for rotation in angles + ] - scatter!(scene, points, marker = :circle, markersize = 10px) + scatter!(scene, points, marker=:circle, markersize=10px) - - text!(scene, points, text = strings, align = aligns, rotation = rotations, - color = [(:black, alpha) for alpha in LinRange(0.3, 0.7, length(points))]) + text!( + scene, + points, + text=strings, + align=aligns, + rotation=rotations, + color=[(:black, alpha) for alpha in LinRange(0.3, 0.7, length(points))], + ) scene end @reference_test "single_strings_single_positions_justification" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera=campixel!, resolution=(800, 800)) points = [Point(x, y) .* 200 for x in 1:3 for y in 1:3] - scatter!(scene, points, marker = :circle, markersize = 10px) + scatter!(scene, points, marker=:circle, markersize=10px) symbols = (:left, :center, :right) for ((justification, halign), point) in zip(Iterators.product(symbols, symbols), points) - - t = text!(scene, "a\nshort\nparagraph", - color = (:black, 0.5), - position = point, - align = (halign, :center), - justification = justification) + t = text!( + scene, + "a\nshort\nparagraph", + color=(:black, 0.5), + position=point, + align=(halign, :center), + justification=justification, + ) bb = boundingbox(t) - wireframe!(scene, bb, color = (:red, 0.2)) + wireframe!(scene, bb, color=(:red, 0.2)) end for (p, al) in zip(points[3:3:end], (:left, :center, :right)) - text!(scene, p .+ (0, 80), text = "align :" * string(al), - align = (:center, :baseline)) + text!(scene, p .+ (0, 80), text="align :" * string(al), align=(:center, :baseline)) end for (p, al) in zip(points[7:9], (:left, :center, :right)) - text!(scene, p .+ (80, 0), text = "justification\n:" * string(al), - align = (:center, :top), rotation = pi/2) + text!( + scene, + p .+ (80, 0), + text="justification\n:" * string(al), + align=(:center, :top), + rotation=pi / 2, + ) end scene end @reference_test "multi_boundingboxes" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) + scene = Scene(camera=campixel!, resolution=(800, 800)) - t1 = text!(scene, + t1 = text!( + scene, fill("makie", 4), - position = [(200, 200) .+ 60 * Point2f(cos(a), sin(a)) for a in pi/4:pi/2:7pi/4], - rotation = pi/4:pi/2:7pi/4, - align = (:left, :center), - fontsize = 30, - markerspace = :data + position=[(200, 200) .+ 60 * Point2f(cos(a), sin(a)) for a in (pi / 4):(pi / 2):(7pi / 4)], + rotation=(pi / 4):(pi / 2):(7pi / 4), + align=(:left, :center), + fontsize=30, + markerspace=:data, ) - wireframe!(scene, boundingbox(t1), color = (:blue, 0.3)) + wireframe!(scene, boundingbox(t1), color=(:blue, 0.3)) - t2 = text!(scene, + t2 = text!( + scene, fill("makie", 4), - position = [(200, 600) .+ 60 * Point2f(cos(a), sin(a)) for a in pi/4:pi/2:7pi/4], - rotation = pi/4:pi/2:7pi/4, - align = (:left, :center), - fontsize = 30, - markerspace = :pixel + position=[(200, 600) .+ 60 * Point2f(cos(a), sin(a)) for a in (pi / 4):(pi / 2):(7pi / 4)], + rotation=(pi / 4):(pi / 2):(7pi / 4), + align=(:left, :center), + fontsize=30, + markerspace=:pixel, ) - wireframe!(scene, boundingbox(t2), color = (:red, 0.3)) + wireframe!(scene, boundingbox(t2), color=(:red, 0.3)) scene end @reference_test "single_boundingboxes" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) - - for a in pi/4:pi/2:7pi/4 + scene = Scene(camera=campixel!, resolution=(800, 800)) - t = text!(scene, + for a in (pi / 4):(pi / 2):(7pi / 4) + t = text!( + scene, "makie", - position = (200, 200) .+ 60 * Point2f(cos(a), sin(a)), - rotation = a, - align = (:left, :center), - fontsize = 30, - markerspace = :data + position=(200, 200) .+ 60 * Point2f(cos(a), sin(a)), + rotation=a, + align=(:left, :center), + fontsize=30, + markerspace=:data, ) - wireframe!(scene, boundingbox(t), color = (:blue, 0.3)) + wireframe!(scene, boundingbox(t), color=(:blue, 0.3)) - t2 = text!(scene, + t2 = text!( + scene, "makie", - position = (200, 600) .+ 60 * Point2f(cos(a), sin(a)), - rotation = a, - align = (:left, :center), - fontsize = 30, - markerspace = :pixel + position=(200, 600) .+ 60 * Point2f(cos(a), sin(a)), + rotation=a, + align=(:left, :center), + fontsize=30, + markerspace=:pixel, ) # these boundingboxes should be invisible because they only enclose the anchor - wireframe!(scene, boundingbox(t2), color = (:red, 0.3)) - + wireframe!(scene, boundingbox(t2), color=(:red, 0.3)) end scene end @@ -171,133 +193,143 @@ end @reference_test "text_in_3d_axis" begin text( fill("Makie", 7), - rotation = [i / 7 * 1.5pi for i in 1:7], - position = [Point3f(0, 0, i/2) for i in 1:7], - color = [cgrad(:viridis)[x] for x in LinRange(0, 1, 7)], - align = (:left, :baseline), - fontsize = 1, - markerspace = :data + rotation=[i / 7 * 1.5pi for i in 1:7], + position=[Point3f(0, 0, i / 2) for i in 1:7], + color=[cgrad(:viridis)[x] for x in LinRange(0, 1, 7)], + align=(:left, :baseline), + fontsize=1, + markerspace=:data, ) end @reference_test "empty_lines" begin - scene = Scene(camera = campixel!, resolution = (800, 800)) - - t1 = text!(scene, "Line1\nLine 2\n\nLine4", - position = (200, 400), align = (:center, :center), markerspace = :data) + scene = Scene(camera=campixel!, resolution=(800, 800)) + + t1 = text!( + scene, + "Line1\nLine 2\n\nLine4", + position=(200, 400), + align=(:center, :center), + markerspace=:data, + ) - wireframe!(scene, boundingbox(t1), color = (:red, 0.3)) + wireframe!(scene, boundingbox(t1), color=(:red, 0.3)) - t2 = text!(scene, "\nLine 2\nLine 3\n\n\nLine6\n\n", - position = (400, 400), align = (:center, :center), markerspace = :data) + t2 = text!( + scene, + "\nLine 2\nLine 3\n\n\nLine6\n\n", + position=(400, 400), + align=(:center, :center), + markerspace=:data, + ) - wireframe!(scene, boundingbox(t2), color = (:blue, 0.3)) + wireframe!(scene, boundingbox(t2), color=(:blue, 0.3)) scene end - @reference_test "3D screenspace annotations" begin positions = RNG.rand(Point3f, 10) fig, ax, p = meshscatter(positions, color=:white) text!( fill("Annotation", 10), - position = positions, - align = (:center, :center), - fontsize = 20, - markerspace = :pixel, - overdraw=false) + position=positions, + align=(:center, :center), + fontsize=20, + markerspace=:pixel, + overdraw=false, + ) fig end - @reference_test "Text offset" begin - f = Figure(resolution = (1000, 1000)) + f = Figure(resolution=(1000, 1000)) barplot(f[1, 1], 3:5) - text!(1, 3, text = "bar 1", offset = (0, 10), align = (:center, :baseline)) - text!([(2, 4), (3, 5)], text = ["bar 2", "bar 3"], - offset = [(0, -10), (0, -20)], - align = (:center, :top), color = :white) + text!(1, 3, text="bar 1", offset=(0, 10), align=(:center, :baseline)) + text!( + [(2, 4), (3, 5)], + text=["bar 2", "bar 3"], + offset=[(0, -10), (0, -20)], + align=(:center, :top), + color=:white, + ) scatter(f[1, 2], Point2f(0, 0)) - text!(0, 0, text = "hello", offset = (40, 0), align = (:left, :center)) - text!(0, 0, text = "hello", offset = (40, 0), align = (:left, :center), - rotation = -pi/4) - text!(0, 0, text = "hello", offset = (40, 0), align = (:left, :center), - rotation = pi/4) + text!(0, 0, text="hello", offset=(40, 0), align=(:left, :center)) + text!(0, 0, text="hello", offset=(40, 0), align=(:left, :center), rotation=-pi / 4) + text!(0, 0, text="hello", offset=(40, 0), align=(:left, :center), rotation=pi / 4) scatter(f[2, 1], Point2f[(0, 0), (10, 0), (20, 10)]) - text!(0, 0, text = "ABC", markerspace = :data, offset = (0, 0), color = (:red, 0.3), align = (:left, :baseline)) - text!(0, 0, text = "ABC", markerspace = :data, offset = (10, 0), color = (:green, 0.3), align = (:left, :baseline)) - text!(0, 0, text = "ABC", markerspace = :data, offset = (20, 10), color = (:blue, 0.3), align = (:left, :baseline)) + text!(0, 0, text="ABC", markerspace=:data, offset=(0, 0), color=(:red, 0.3), align=(:left, :baseline)) + text!(0, 0, text="ABC", markerspace=:data, offset=(10, 0), color=(:green, 0.3), align=(:left, :baseline)) + text!(0, 0, text="ABC", markerspace=:data, offset=(20, 10), color=(:blue, 0.3), align=(:left, :baseline)) LScene(f[2, 2], show_axis=false) scatter!(Point3f[(0, 0, 0), (2, 2, 2)]) - text!(1, 1, 1, text = "hello", offset = (10, 10)) + text!(1, 1, 1, text="hello", offset=(10, 10)) f end - @reference_test "Log10 text" begin - barplot([1, 10, 100], fillto = 0.1, axis = (yscale = log10,)) - text!([(1, 1), (2, 10), (3, 100)], text = ["bar 1", "bar 2", "bar 3"], - offset = (0, -10), color = :white, align = (:center, :top)) + barplot([1, 10, 100], fillto=0.1, axis=(yscale=log10,)) + text!( + [(1, 1), (2, 10), (3, 100)], + text=["bar 1", "bar 2", "bar 3"], + offset=(0, -10), + color=:white, + align=(:center, :top), + ) tightlimits!(current_axis(), Bottom()) current_figure() end @reference_test "latex strings" begin - f, ax , l = lines(cumsum(RNG.randn(1000)), - axis = ( - title = L"\sum_k{x y_k}", - xlabel = L"\lim_{x →\infty} A^j v_{(a + b)_k}^i \sqrt{23.5} x!= \sqrt{\frac{1+6}{4+a+g}}\int_{0}^{2π} \sin(x) dx", - ylabel = L"x + y - \sin(x) × \tan(y) + \sqrt{2}", - ), - figure = (fontsize = 18,) + f, ax, l = lines( + cumsum(RNG.randn(1000)), + axis=( + title=L"\sum_k{x y_k}", + xlabel=L"\lim_{x →\infty} A^j v_{(a + b)_k}^i \sqrt{23.5} x!= \sqrt{\frac{1+6}{4+a+g}}\int_{0}^{2π} \sin(x) dx", + ylabel=L"x + y - \sin(x) × \tan(y) + \sqrt{2}", + ), + figure=(fontsize=18,), ) - text!(500, 0, text = L"\int_{0}^{2π} \sin(x) dx") + text!(500, 0, text=L"\int_{0}^{2π} \sin(x) dx") Legend(f[1, 2], [l, l, l], [L"\sum{xy}", L"a\int_0^5x^2+2ab", L"||x-y||^2"]) f end @reference_test "latex hlines in axis" begin - text(1, 1, text = L"\frac{\sqrt{x + y}}{\sqrt{x + y}}", fontsize = 50, rotation = pi/4, - align = (:center, :center)) + text( + 1, + 1, + text=L"\frac{\sqrt{x + y}}{\sqrt{x + y}}", + fontsize=50, + rotation=pi / 4, + align=(:center, :center), + ) end @reference_test "latex simple" begin - s = Scene(camera = campixel!) - t = text!(s, - L"\sqrt{2}", - position = (50, 50), - rotation = pi/2, - markerspace = :data) + s = Scene(camera=campixel!) + t = text!(s, L"\sqrt{2}", position=(50, 50), rotation=pi / 2, markerspace=:data) s end @reference_test "latex bb" begin - s = Scene(camera = campixel!) - t = text!(s, - L"\int_0^5x^2+2ab", - position = Point2f(50, 50), - rotation = 0.0, - markerspace = :data) + s = Scene(camera=campixel!) + t = text!(s, L"\int_0^5x^2+2ab", position=Point2f(50, 50), rotation=0.0, markerspace=:data) wireframe!(s, boundingbox(t)) s end @reference_test "latex updates" begin - s = Scene(camera = campixel!) + s = Scene(camera=campixel!) st = Stepper(s) textnode = Observable([L"\int_0^5x^2+2ab", L"\int_0^5x^2+2ab"]) posnode = Observable(Point2f[(50, 50), (100, 100)]) - t = text!(s, - textnode, - position = posnode, - rotation = 0.0, - markerspace = :data) + t = text!(s, textnode, position=posnode, rotation=0.0, markerspace=:data) Makie.step!(st) ## change lengths @@ -308,16 +340,11 @@ end end @reference_test "update annotation style" begin - s = Scene(camera = campixel!) + s = Scene(camera=campixel!) st = Stepper(s) - textposnode = Observable([ - (L"\int_0^5x^2+2ab", Point2f(50, 50)), - (L"\int_0^5x^2+2ab", Point2f(100, 100)), - ]) + textposnode = Observable([(L"\int_0^5x^2+2ab", Point2f(50, 50)), (L"\int_0^5x^2+2ab", Point2f(100, 100))]) - t = text!(s, - textposnode, - markerspace = :data) + t = text!(s, textposnode, markerspace=:data) Makie.step!(st) ## change lengths @@ -327,23 +354,28 @@ end end @reference_test "latex ticks" begin - lines(0..25, x -> 4 * sin(x) / (cos(3x) + 4), figure = (fontsize = 25,), - axis = ( - xticks = (0:10:20, [L"10^{-3.5}", L"10^{-4.5}", L"10^{-5.5}"]), - yticks = ([-1, 0, 1], [L"\sum_%$i{xy}" for i in 1:3]), - yticklabelrotation = pi/8, - title = L"\int_0^1{x^2}", - xlabel = L"\sum_k{x_k ⋅ y_k}", - ylabel = L"\int_a^b{\sqrt{abx}}" + lines( + 0 .. 25, + x -> 4 * sin(x) / (cos(3x) + 4), + figure=(fontsize=25,), + axis=( + xticks=(0:10:20, [L"10^{-3.5}", L"10^{-4.5}", L"10^{-5.5}"]), + yticks=([-1, 0, 1], [L"\sum_%$i{xy}" for i in 1:3]), + yticklabelrotation=pi / 8, + title=L"\int_0^1{x^2}", + xlabel=L"\sum_k{x_k ⋅ y_k}", + ylabel=L"\int_a^b{\sqrt{abx}}", ), ) end - @reference_test "dynamic latex ticks" begin - lines(0..25, x -> 4 * sin(x) / (cos(3x) + 4), - figure = (fontsize = 16,), - axis = (xtickformat = (xs -> [L"e^{\sqrt{%$x}}+\sum" for x in xs]), )) + lines( + 0 .. 25, + x -> 4 * sin(x) / (cos(3x) + 4), + figure=(fontsize=16,), + axis=(xtickformat=(xs -> [L"e^{\sqrt{%$x}}+\sum" for x in xs]),), + ) end @reference_test "Word Wrapping" begin @@ -351,10 +383,40 @@ end fig = Figure(resolution=(600, 500)) ax = Axis(fig[1, 1]) - text!(ax, 0, 0, text = latexstring(L"$1$ " * lorem_ipsum), word_wrap_width=250, fontsize = 12, align = (:left, :bottom), justification = :left, color = :black) - text!(ax, 0, 0, text = lorem_ipsum, word_wrap_width=250, fontsize = 12, align = (:left, :top), justification = :right, color = :black) - text!(ax, 0, 0, text = lorem_ipsum, word_wrap_width=250, fontsize = 12, align = (:right, :bottom), justification = :center, color = :red) - text!(ax, -0.3, 0, text = lorem_ipsum, word_wrap_width=200, fontsize = 12, align = (:center, :top), color = :blue) + text!( + ax, + 0, + 0, + text=latexstring(L"$1$ " * lorem_ipsum), + word_wrap_width=250, + fontsize=12, + align=(:left, :bottom), + justification=:left, + color=:black, + ) + text!( + ax, + 0, + 0, + text=lorem_ipsum, + word_wrap_width=250, + fontsize=12, + align=(:left, :top), + justification=:right, + color=:black, + ) + text!( + ax, + 0, + 0, + text=lorem_ipsum, + word_wrap_width=250, + fontsize=12, + align=(:right, :bottom), + justification=:center, + color=:red, + ) + text!(ax, -0.3, 0, text=lorem_ipsum, word_wrap_width=200, fontsize=12, align=(:center, :top), color=:blue) xlims!(ax, -0.8, 0.8) ylims!(ax, -0.8, 0.6) fig diff --git a/ReferenceTests/src/tests/updating.jl b/ReferenceTests/src/tests/updating.jl index ea1bb97c44f..b067cccff36 100644 --- a/ReferenceTests/src/tests/updating.jl +++ b/ReferenceTests/src/tests/updating.jl @@ -1,54 +1,82 @@ @reference_test "updating 2d primitives" begin fig = Figure() t = Observable(1) - text(fig[1, 1], lift(i-> map(j-> ("$j", Point2f(j*30, 0)), 1:i), t), axis=(limits=(0, 380, -10, 10),), fontsize=50) - scatter(fig[1, 2], lift(i-> Point2f.((1:i).*30, 0), t), axis=(limits=(0, 330, -10, 10),), markersize=50) - linesegments(fig[2, 1], lift(i-> Point2f.((2:2:4i).*30, 0), t), axis=(limits=(30, 650, -10, 10),), linewidth=20) - lines(fig[2, 2], lift(i-> Point2f.((2:2:4i).*30, 0), t), axis=(limits=(30, 650, -10, 10),), linewidth=20) + text( + fig[1, 1], + lift(i -> map(j -> ("$j", Point2f(j * 30, 0)), 1:i), t), + axis=(limits=(0, 380, -10, 10),), + fontsize=50, + ) + scatter( + fig[1, 2], + lift(i -> Point2f.((1:i) .* 30, 0), t), + axis=(limits=(0, 330, -10, 10),), + markersize=50, + ) + linesegments( + fig[2, 1], + lift(i -> Point2f.((2:2:(4i)) .* 30, 0), t), + axis=(limits=(30, 650, -10, 10),), + linewidth=20, + ) + lines( + fig[2, 2], + lift(i -> Point2f.((2:2:(4i)) .* 30, 0), t), + axis=(limits=(30, 650, -10, 10),), + linewidth=20, + ) st = Stepper(fig) foreach(1:5) do i t[] = i - Makie.step!(st) + return Makie.step!(st) end foreach(5:-1:1) do i t[] = i - Makie.step!(st) + return Makie.step!(st) end st end @reference_test "updating multiple meshes" begin - points = Observable(Point3f[(1,0,0), (0,1,0), (0,0,1)]) + points = Observable(Point3f[(1, 0, 0), (0, 1, 0), (0, 0, 1)]) - meshes = map(p->Makie.normal_mesh(Sphere(p, 0.2)), points[]) - colors = map(p->RGBf(normalize(p)...), points[]) + meshes = map(p -> Makie.normal_mesh(Sphere(p, 0.2)), points[]) + colors = map(p -> RGBf(normalize(p)...), points[]) - fig, ax, pl = mesh(meshes; color = colors) + fig, ax, pl = mesh(meshes; color=colors) st = Stepper(fig) Makie.step!(st) on(points) do pts - pl[1].val = map(p->Makie.normal_mesh(Sphere(p, 0.2)), points[]) - pl.color.val = map(p->RGBf(normalize(p)...), points[]) - notify(pl[1]) + pl[1].val = map(p -> Makie.normal_mesh(Sphere(p, 0.2)), points[]) + pl.color.val = map(p -> RGBf(normalize(p)...), points[]) + return notify(pl[1]) end - append!(points[], Point3f[(0,1,1), (1,0,1), (1,1,0)]) + append!(points[], Point3f[(0, 1, 1), (1, 0, 1), (1, 1, 0)]) notify(points) Makie.step!(st) end -function generate_plot(N = 3) +function generate_plot(N=3) points = Observable(Point2f[]) color = Observable(RGBAf[]) - fig, ax, pl = scatter(points, color=color, markersize=1.0, marker=Circle, markerspace=:data, axis=(type=Axis, aspect=DataAspect(), limits=(0.4, N + 0.6, 0.4, N + 0.6),), figure=(resolution=(800, 800),)) + fig, ax, pl = scatter( + points, + color=color, + markersize=1.0, + marker=Circle, + markerspace=:data, + axis=(type=Axis, aspect=DataAspect(), limits=(0.4, N + 0.6, 0.4, N + 0.6)), + figure=(resolution=(800, 800),), + ) function update_func(ij) push!(points.val, Point2f(Tuple(ij))) - push!(color.val, RGBAf((Tuple(ij)./N)..., 0, 1)) + push!(color.val, RGBAf((Tuple(ij) ./ N)..., 0, 1)) notify(color) - notify(points) + return notify(points) end return fig, CartesianIndices((N, N)), update_func end diff --git a/ReferenceTests/src/visual-regression.jl b/ReferenceTests/src/visual-regression.jl index a0a362e94df..f5fbf254b99 100644 --- a/ReferenceTests/src/visual-regression.jl +++ b/ReferenceTests/src/visual-regression.jl @@ -1,12 +1,12 @@ """ `m = maxfinite(A)` calculates the maximum value in `A`, ignoring any values that are not finite (Inf or NaN). """ -function maxfinite(A::AbstractArray{T}) where T +function maxfinite(A::AbstractArray{T}) where {T} ret = sentinel_max(T) for a in A ret = maxfinite_scalar(a, ret) end - ret + return ret end function maxfinite(f, A::AbstractArray) @@ -14,63 +14,59 @@ function maxfinite(f, A::AbstractArray) for a in A ret = maxfinite_scalar(f(a), ret) end - ret + return ret end """ `m = maxabsfinite(A)` calculates the maximum absolute value in `A`, ignoring any values that are not finite (Inf or NaN). """ -function maxabsfinite(A::AbstractArray{T}) where T +function maxabsfinite(A::AbstractArray{T}) where {T} ret = sentinel_min(typeof(abs(A[1]))) for a in A ret = maxfinite_scalar(abs(a), ret) end - ret + return ret end minfinite_scalar(a::T, b::T) where {T} = isfinite(a) ? (b < a ? b : a) : b maxfinite_scalar(a::T, b::T) where {T} = isfinite(a) ? (b > a ? b : a) : b -minfinite_scalar(a::T, b::T) where {T <: Union{Integer,FixedPoint}} = b < a ? b : a -maxfinite_scalar(a::T, b::T) where {T <: Union{Integer,FixedPoint}} = b > a ? b : a +minfinite_scalar(a::T, b::T) where {T<:Union{Integer,FixedPoint}} = b < a ? b : a +maxfinite_scalar(a::T, b::T) where {T<:Union{Integer,FixedPoint}} = b > a ? b : a minfinite_scalar(a, b) = minfinite_scalar(promote(a, b)...) maxfinite_scalar(a, b) = maxfinite_scalar(promote(a, b)...) -function minfinite_scalar(c1::C, c2::C) where C <: AbstractRGB - C(minfinite_scalar(c1.r, c2.r), - minfinite_scalar(c1.g, c2.g), - minfinite_scalar(c1.b, c2.b)) +function minfinite_scalar(c1::C, c2::C) where {C<:AbstractRGB} + return C(minfinite_scalar(c1.r, c2.r), minfinite_scalar(c1.g, c2.g), minfinite_scalar(c1.b, c2.b)) end -function maxfinite_scalar(c1::C, c2::C) where C <: AbstractRGB - C(maxfinite_scalar(c1.r, c2.r), - maxfinite_scalar(c1.g, c2.g), - maxfinite_scalar(c1.b, c2.b)) +function maxfinite_scalar(c1::C, c2::C) where {C<:AbstractRGB} + return C(maxfinite_scalar(c1.r, c2.r), maxfinite_scalar(c1.g, c2.g), maxfinite_scalar(c1.b, c2.b)) end -sentinel_min(::Type{T}) where {T <: Union{Integer,FixedPoint}} = typemax(T) -sentinel_max(::Type{T}) where {T <: Union{Integer,FixedPoint}} = typemin(T) -sentinel_min(::Type{T}) where {T <: AbstractFloat} = convert(T, NaN) -sentinel_max(::Type{T}) where {T <: AbstractFloat} = convert(T, NaN) -sentinel_min(::Type{C}) where {C <: AbstractRGB} = _sentinel_min(C, eltype(C)) -_sentinel_min(::Type{C},::Type{T}) where {C <: AbstractRGB,T} = (s = sentinel_min(T); C(s, s, s)) -sentinel_max(::Type{C}) where {C <: AbstractRGB} = _sentinel_max(C, eltype(C)) -_sentinel_max(::Type{C},::Type{T}) where {C <: AbstractRGB,T} = (s = sentinel_max(T); C(s, s, s)) +sentinel_min(::Type{T}) where {T<:Union{Integer,FixedPoint}} = typemax(T) +sentinel_max(::Type{T}) where {T<:Union{Integer,FixedPoint}} = typemin(T) +sentinel_min(::Type{T}) where {T<:AbstractFloat} = convert(T, NaN) +sentinel_max(::Type{T}) where {T<:AbstractFloat} = convert(T, NaN) +sentinel_min(::Type{C}) where {C<:AbstractRGB} = _sentinel_min(C, eltype(C)) +_sentinel_min(::Type{C}, ::Type{T}) where {C<:AbstractRGB,T} = (s = sentinel_min(T); C(s, s, s)) +sentinel_max(::Type{C}) where {C<:AbstractRGB} = _sentinel_max(C, eltype(C)) +_sentinel_max(::Type{C}, ::Type{T}) where {C<:AbstractRGB,T} = (s = sentinel_max(T); C(s, s, s)) -difftype(::Type{T}) where {T <: Integer} = Int -difftype(::Type{T}) where {T <: Real} = Float32 +difftype(::Type{T}) where {T<:Integer} = Int +difftype(::Type{T}) where {T<:Real} = Float32 difftype(::Type{Float64}) = Float64 -difftype(::Type{CV}) where {CV <: Colorant} = difftype(CV, eltype(CV)) -difftype(::Type{CV}, ::Type{T}) where {CV <: RGBA,T <: Real} = RGBA{Float32} -difftype(::Type{CV}, ::Type{Float64}) where {CV <: RGBA} = RGBA{Float64} -difftype(::Type{CV}, ::Type{Float64}) where {CV <: Gray} = Gray{Float64} -difftype(::Type{CV}, ::Type{T}) where {CV <: BGRA,T <: Real} = BGRA{Float32} -difftype(::Type{CV}, ::Type{Float64}) where {CV <: BGRA} = BGRA{Float64} -difftype(::Type{CV}, ::Type{T}) where {CV <: AbstractRGB,T <: Real} = RGB{Float32} -difftype(::Type{CV}, ::Type{Float64}) where {CV <: AbstractRGB} = RGB{Float64} +difftype(::Type{CV}) where {CV<:Colorant} = difftype(CV, eltype(CV)) +difftype(::Type{CV}, ::Type{T}) where {CV<:RGBA,T<:Real} = RGBA{Float32} +difftype(::Type{CV}, ::Type{Float64}) where {CV<:RGBA} = RGBA{Float64} +difftype(::Type{CV}, ::Type{Float64}) where {CV<:Gray} = Gray{Float64} +difftype(::Type{CV}, ::Type{T}) where {CV<:BGRA,T<:Real} = BGRA{Float32} +difftype(::Type{CV}, ::Type{Float64}) where {CV<:BGRA} = BGRA{Float64} +difftype(::Type{CV}, ::Type{T}) where {CV<:AbstractRGB,T<:Real} = RGB{Float32} +difftype(::Type{CV}, ::Type{Float64}) where {CV<:AbstractRGB} = RGB{Float64} -accum(::Type{T}) where {T <: Integer} = Int -accum(::Type{Float32}) = Float32 -accum(::Type{T}) where {T <: Real} = Float64 -accum(::Type{C}) where {C <: Colorant} = base_colorant_type(C){accum(eltype(C))} +accum(::Type{T}) where {T<:Integer} = Int +accum(::Type{Float32}) = Float32 +accum(::Type{T}) where {T<:Real} = Float64 +accum(::Type{C}) where {C<:Colorant} = base_colorant_type(C){accum(eltype(C))} function sumdiff(f, A::AbstractArray, B::AbstractArray) axes(A) == axes(B) || throw(DimensionMismatch("A and B must have the same axes")) T = promote_type(difftype(eltype(A)), difftype(eltype(B))) @@ -79,7 +75,7 @@ function sumdiff(f, A::AbstractArray, B::AbstractArray) x = convert(T, a) - convert(T, b) s += f(x) end - s + return s end "`s = ssd(A, B)` computes the sum-of-squared differences over arrays/images A and B" @@ -88,15 +84,16 @@ ssd(A::AbstractArray, B::AbstractArray) = sumdiff(abs2, A, B) "`s = sad(A, B)` computes the sum-of-absolute differences over arrays/images A and B" sad(A::AbstractArray, B::AbstractArray) = sumdiff(abs, A, B) - function approx_difference( - A::AbstractArray, B::AbstractArray, - sigma::AbstractVector{T}=ones(ndims(A)), - eps::AbstractFloat=1e-2 - ) where T <: Real - + A::AbstractArray, + B::AbstractArray, + sigma::AbstractVector{T}=ones(ndims(A)), + eps::AbstractFloat=1e-2, +) where {T<:Real} if length(sigma) != ndims(A) - error("Invalid sigma in test_approx_eq_sigma_eps. Should be ndims(A)-length vector of the number of pixels to blur. Got: $sigma") + error( + "Invalid sigma in test_approx_eq_sigma_eps. Should be ndims(A)-length vector of the number of pixels to blur. Got: $sigma", + ) end kern = KernelFactors.IIRGaussian(sigma) Af = imfilter(A, kern, NA()) diff --git a/WGLMakie/src/WGLMakie.jl b/WGLMakie/src/WGLMakie.jl index eaaab22aa03..7bc360baa6c 100644 --- a/WGLMakie/src/WGLMakie.jl +++ b/WGLMakie/src/WGLMakie.jl @@ -43,7 +43,6 @@ include("meshes.jl") include("imagelike.jl") include("display.jl") - """ WGLMakie.activate!(; screen_config...) @@ -74,7 +73,7 @@ function __init__() # We do this in three_plot! atlas = wgl_texture_atlas() Makie.font_render_callback!(atlas) do sd, uv - TEXTURE_ATLAS_CHANGED[] = true + return TEXTURE_ATLAS_CHANGED[] = true end end diff --git a/WGLMakie/src/display.jl b/WGLMakie/src/display.jl index ef843258194..84867e0e299 100644 --- a/WGLMakie/src/display.jl +++ b/WGLMakie/src/display.jl @@ -14,7 +14,8 @@ const WEB_MIMES = ( MIME"text/html", MIME"application/vnd.webio.application+html", MIME"application/prs.juno.plotpane+html", - MIME"juliavscode/html") + MIME"juliavscode/html", +) """ * `framerate = 30`: Set framerate (frames per second) to a higher number for smoother animations, or to a lower to use less resources. @@ -37,7 +38,7 @@ $(Base.doc(MakieScreen)) mutable struct Screen <: Makie.MakieScreen three::Channel{ThreeDisplay} display::Any - scene::Union{Nothing, Scene} + scene::Union{Nothing,Scene} end for M in WEB_MIMES @@ -47,7 +48,7 @@ for M in WEB_MIMES three, canvas, init_obs = three_display(session, scene) Makie.push_screen!(scene, three) on(init_obs) do _ - put!(screen.three, three) + return put!(screen.three, three) end return canvas end @@ -57,18 +58,14 @@ for M in WEB_MIMES end end -function Makie.backend_showable(::Type{Screen}, ::T) where {T<:MIME} - return T in WEB_MIMES -end +Makie.backend_showable(::Type{Screen}, ::T) where {T<:MIME} = T in WEB_MIMES # TODO implement Base.close(screen::Screen) = nothing -function Base.size(screen::Screen) - return size(screen.scene) -end +Base.size(screen::Screen) = size(screen.scene) -function get_three(screen::Screen; timeout = 100) +function get_three(screen::Screen; timeout=100) tstart = time() while true sleep(0.001) @@ -94,7 +91,7 @@ Screen(scene::Scene, config::ScreenConfig, ::IO, ::MIME) = Screen(scene) Screen(scene::Scene, config::ScreenConfig, ::Makie.ImageStorageFormat) = Screen(scene) function Base.empty!(screen::Screen) - screen.scene = nothing + return screen.scene = nothing # TODO, empty state in JS, to be able to reuse screen end @@ -104,7 +101,7 @@ function Base.display(screen::Screen, scene::Scene; kw...) app = App() do session, request three, canvas, done_init = three_display(session, scene) on(done_init) do _ - put!(screen.three, three) + return put!(screen.three, three) end return canvas end @@ -113,9 +110,7 @@ function Base.display(screen::Screen, scene::Scene; kw...) return screen end -function Base.delete!(td::Screen, scene::Scene, plot::AbstractPlot) - delete!(get_three(td), scene, plot) -end +Base.delete!(td::Screen, scene::Scene, plot::AbstractPlot) = delete!(get_three(td), scene, plot) function session2image(sessionlike) yield() @@ -131,9 +126,7 @@ function session2image(sessionlike) return ImageMagick.load_(bytes) end -function Makie.colorbuffer(screen::ThreeDisplay) - return session2image(screen) -end +Makie.colorbuffer(screen::ThreeDisplay) = session2image(screen) function Makie.colorbuffer(screen::Screen) if screen.display !== true @@ -146,7 +139,7 @@ function Makie.colorbuffer(screen::Screen) return session2image(three) end -function wait_for_three(three_ref::Base.RefValue{ThreeDisplay}; timeout = 30)::Union{Nothing, ThreeDisplay} +function wait_for_three(three_ref::Base.RefValue{ThreeDisplay}; timeout=30)::Union{Nothing,ThreeDisplay} # Screen is not guaranteed to get displayed in the browser, so we wait a while # to see if anything gets displayed! tstart = time() @@ -170,5 +163,5 @@ end function Base.insert!(td::Screen, scene::Scene, plot::Combined) disp = get_three(td) disp === nothing && error("Plot needs to be displayed to insert additional plots") - insert!(disp, scene, plot) + return insert!(disp, scene, plot) end diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index c5c146b2de3..3650b03bb54 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -24,7 +24,7 @@ function draw_mesh(mscene::Scene, mesh, plot; uniforms...) get!(uniforms, :color, false) get!(uniforms, :pattern, false) get!(uniforms, :model, plot.model) - get!(uniforms, :depth_shift, 0f0) + get!(uniforms, :depth_shift, 0.0f0) get!(uniforms, :lightposition, Vec3f(1)) get!(uniforms, :ambient, Vec3f(1)) get!(uniforms, :interpolate_in_fragment_shader, true) @@ -42,8 +42,8 @@ xy_convert(x, n) = Float32[LinRange(extrema(x)..., n + 1);] function limits_to_uvmesh(plot) px, py, pz = plot[1], plot[2], plot[3] - px = map((x, z)-> xy_convert(x, size(z, 1)), px, pz) - py = map((y, z)-> xy_convert(y, size(z, 2)), py, pz) + px = map((x, z) -> xy_convert(x, size(z, 1)), px, pz) + py = map((y, z) -> xy_convert(y, size(z, 2)), py, pz) # Special path for ranges of length 2 which # can be displayed as a rectangle t = Makie.transform_func_obs(plot)[] @@ -53,12 +53,14 @@ function limits_to_uvmesh(plot) ymin, ymax = extrema(y) return Rect2(xmin, ymin, xmax - xmin, ymax - ymin) end - positions = Buffer(lift(rect-> decompose(Point2f, rect), rect)) + positions = Buffer(lift(rect -> decompose(Point2f, rect), rect)) faces = Buffer(lift(rect -> decompose(GLTriangleFace, rect), rect)) uv = Buffer(lift(decompose_uv, rect)) - else - grid(x, y, trans, space) = Makie.matrix_grid(p-> apply_transform(trans, p, space), x, y, zeros(length(x), length(y))) - rect = lift((x, y) -> Tesselation(Rect2(0f0, 0f0, 1f0, 1f0), (length(x), length(y))), px, py) + else + function grid(x, y, trans, space) + return Makie.matrix_grid(p -> apply_transform(trans, p, space), x, y, zeros(length(x), length(y))) + end + rect = lift((x, y) -> Tesselation(Rect2(0.0f0, 0.0f0, 1.0f0, 1.0f0), (length(x), length(y))), px, py) positions = Buffer(lift(grid, px, py, t, get(plot, :space, :data))) faces = Buffer(lift(r -> decompose(GLTriangleFace, r), rect)) uv = Buffer(lift(decompose_uv, rect)) @@ -80,9 +82,9 @@ end function create_shader(mscene::Scene, plot::Surface) # TODO OWN OPTIMIZED SHADER ... Or at least optimize this a bit more ... px, py, pz = plot[1], plot[2], plot[3] - grid(x, y, z, trans, space) = Makie.matrix_grid(p-> apply_transform(trans, p, space), x, y, z) + grid(x, y, z, trans, space) = Makie.matrix_grid(p -> apply_transform(trans, p, space), x, y, z) positions = Buffer(lift(grid, px, py, pz, transform_func_obs(plot), get(plot, :space, :data))) - rect = lift(z -> Tesselation(Rect2(0f0, 0f0, 1f0, 1f0), size(z)), pz) + rect = lift(z -> Tesselation(Rect2(0.0f0, 0.0f0, 1.0f0, 1.0f0), size(z)), pz) faces = Buffer(lift(r -> decompose(GLTriangleFace, r), rect)) uv = Buffer(lift(decompose_uv, rect)) plot_attributes = copy(plot.attributes) @@ -100,20 +102,30 @@ function create_shader(mscene::Scene, plot::Surface) normals = Buffer(lift(surface_normals, px, py, pz)) vertices = GeometryBasics.meta(positions; uv=uv, normals=normals) mesh = GeometryBasics.Mesh(vertices, faces) - return draw_mesh(mscene, mesh, plot_attributes; uniform_color=color, color=false, - shading=plot.shading, diffuse=plot.diffuse, - specular=plot.specular, shininess=plot.shininess, - depth_shift=get(plot, :depth_shift, Observable(0f0)), - backlight=plot.backlight, - highclip=get_color(plot, :highclip), - lowclip=get_color(plot, :lowclip), - nan_color=get_color(plot, :nan_color)) + return draw_mesh( + mscene, + mesh, + plot_attributes; + uniform_color=color, + color=false, + shading=plot.shading, + diffuse=plot.diffuse, + specular=plot.specular, + shininess=plot.shininess, + depth_shift=get(plot, :depth_shift, Observable(0.0f0)), + backlight=plot.backlight, + highclip=get_color(plot, :highclip), + lowclip=get_color(plot, :lowclip), + nan_color=get_color(plot, :nan_color), + ) end -function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) +function create_shader(mscene::Scene, plot::Union{Heatmap,Image}) image = plot[3] - color = Sampler(map(x -> el32convert(x'), image); - minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) + color = Sampler( + map(x -> el32convert(x'), image); + minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest, + ) mesh = limits_to_uvmesh(plot) plot_attributes = copy(plot.attributes) if eltype(color) <: Colorant @@ -121,17 +133,24 @@ function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) delete!(plot_attributes, :colorrange) end - return draw_mesh(mscene, mesh, plot_attributes; - uniform_color=color, color=false, - normals=Vec3f(0), shading=false, - diffuse=plot.diffuse, specular=plot.specular, - colorrange=haskey(plot, :colorrange) ? plot.colorrange : false, - shininess=plot.shininess, - highclip=get_color(plot, :highclip), - lowclip=get_color(plot, :lowclip), - nan_color=get_color(plot, :nan_color), - backlight=0f0, - depth_shift = get(plot, :depth_shift, Observable(0f0))) + return draw_mesh( + mscene, + mesh, + plot_attributes; + uniform_color=color, + color=false, + normals=Vec3f(0), + shading=false, + diffuse=plot.diffuse, + specular=plot.specular, + colorrange=haskey(plot, :colorrange) ? plot.colorrange : false, + shininess=plot.shininess, + highclip=get_color(plot, :highclip), + lowclip=get_color(plot, :lowclip), + nan_color=get_color(plot, :nan_color), + backlight=0.0f0, + depth_shift=get(plot, :depth_shift, Observable(0.0f0)), + ) end function create_shader(mscene::Scene, plot::Volume) @@ -149,17 +168,28 @@ function create_shader(mscene::Scene, plot::Volume) modelinv = lift(inv, model2) algorithm = lift(x -> Cuint(convert_attribute(x, key"algorithm"())), plot.algorithm) - return Program(WebGL(), lasset("volume.vert"), lasset("volume.frag"), box, - volumedata=Sampler(lift(Makie.el32convert, vol)), - modelinv=modelinv, colormap=Sampler(lift(to_colormap, plot.colormap)), - colorrange=lift(Vec2f, plot.colorrange), - isovalue=lift(Float32, plot.isovalue), - isorange=lift(Float32, plot.isorange), - absorption=lift(Float32, get(plot, :absorption, Observable(1f0))), - algorithm=algorithm, - diffuse=plot.diffuse, specular=plot.specular, shininess=plot.shininess, - model=model2, depth_shift = get(plot, :depth_shift, Observable(0f0)), - # these get filled in later by serialization, but we need them - # as dummy values here, so that the correct uniforms are emitted - lightposition=Vec3f(1), eyeposition=Vec3f(1), ambient=Vec3f(1)) + return Program( + WebGL(), + lasset("volume.vert"), + lasset("volume.frag"), + box, + volumedata=Sampler(lift(Makie.el32convert, vol)), + modelinv=modelinv, + colormap=Sampler(lift(to_colormap, plot.colormap)), + colorrange=lift(Vec2f, plot.colorrange), + isovalue=lift(Float32, plot.isovalue), + isorange=lift(Float32, plot.isorange), + absorption=lift(Float32, get(plot, :absorption, Observable(1.0f0))), + algorithm=algorithm, + diffuse=plot.diffuse, + specular=plot.specular, + shininess=plot.shininess, + model=model2, + depth_shift=get(plot, :depth_shift, Observable(0.0f0)), + # these get filled in later by serialization, but we need them + # as dummy values here, so that the correct uniforms are emitted + lightposition=Vec3f(1), + eyeposition=Vec3f(1), + ambient=Vec3f(1), + ) end diff --git a/WGLMakie/src/lines.jl b/WGLMakie/src/lines.jl index 6a8fc668f4e..fff12c6c2f3 100644 --- a/WGLMakie/src/lines.jl +++ b/WGLMakie/src/lines.jl @@ -3,13 +3,9 @@ topoint(x::AbstractVector{Point{N,Float32}}) where {N} = x # GRRR STUPID SubArray, with eltype different from getindex(x, 1) topoint(x::SubArray) = topoint([el for el in x]) -function topoint(x::AbstractArray{<:Point{N,T}}) where {T,N} - return topoint(Point{N,Float32}.(x)) -end +topoint(x::AbstractArray{<:Point{N,T}}) where {T,N} = topoint(Point{N,Float32}.(x)) -function topoint(x::AbstractArray{<:Tuple{P,P}}) where {P<:Point} - return topoint(reinterpret(P, x)) -end +topoint(x::AbstractArray{<:Tuple{P,P}}) where {P<:Point} = topoint(reinterpret(P, x)) function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) # Potentially per instance attributes @@ -19,9 +15,9 @@ function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) return points else # Repeat every second point to connect the lines ! - return topoint(TupleView{2, 1}(points)) + return topoint(TupleView{2,1}(points)) end - trans + return trans end startr = lift(p -> 1:2:(length(p) - 1), positions) endr = lift(p -> 2:2:length(p), positions) @@ -29,8 +25,10 @@ function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) return (positions[startr[]], positions[endr[]]) end - per_instance = Dict{Symbol,Any}(:segment_start => Buffer(lift(first, p_start_end)), - :segment_end => Buffer(lift(last, p_start_end))) + per_instance = Dict{Symbol,Any}( + :segment_start => Buffer(lift(first, p_start_end)), + :segment_end => Buffer(lift(last, p_start_end)), + ) uniforms = Dict{Symbol,Any}() for k in (:linewidth, :color) attribute = lift(plot[k]) do x @@ -39,7 +37,7 @@ function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) return x else # Repeat every second point to connect the lines! - return isscalar(x) ? x : reinterpret(eltype(x), TupleView{2, 1}(x)) + return isscalar(x) ? x : reinterpret(eltype(x), TupleView{2,1}(x)) end end if isscalar(attribute) @@ -57,12 +55,16 @@ function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) uniforms[:resolution] = scene.camera.resolution uniforms[:model] = plot.model - uniforms[:depth_shift] = get(plot, :depth_shift, Observable(0f0)) - positions = meta(Point2f[(0, -1), (0, 1), (1, -1), (1, 1)], - uv=Vec2f[(0, 0), (0, 0), (0, 0), (0, 0)]) + uniforms[:depth_shift] = get(plot, :depth_shift, Observable(0.0f0)) + positions = meta(Point2f[(0, -1), (0, 1), (1, -1), (1, 1)], uv=Vec2f[(0, 0), (0, 0), (0, 0), (0, 0)]) instance = GeometryBasics.Mesh(positions, GLTriangleFace[(1, 2, 3), (2, 4, 3)]) - return InstancedProgram(WebGL(), lasset("line_segments.vert"), - lasset("line_segments.frag"), instance, - VertexArray(; per_instance...); uniforms...) + return InstancedProgram( + WebGL(), + lasset("line_segments.vert"), + lasset("line_segments.frag"), + instance, + VertexArray(; per_instance...); + uniforms..., + ) end diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 9f433ef6486..72599d801f6 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -1,26 +1,20 @@ function vertexbuffer(x, trans, space) pos = decompose(Point, x) - return apply_transform(trans, pos, space) + return apply_transform(trans, pos, space) end -function vertexbuffer(x::Observable, p) - return Buffer(lift(vertexbuffer, x, transform_func_obs(p), get(p, :space, :data))) -end +vertexbuffer(x::Observable, p) = Buffer(lift(vertexbuffer, x, transform_func_obs(p), get(p, :space, :data))) facebuffer(x) = facebuffer(GeometryBasics.faces(x)) facebuffer(x::Observable) = Buffer(lift(facebuffer, x)) -function facebuffer(x::AbstractArray{GLTriangleFace}) - return x -end +facebuffer(x::AbstractArray{GLTriangleFace}) = x function array2color(colors, cmap, crange) cmap = RGBAf.(Colors.color.(to_colormap(cmap)), 1.0) return Makie.interpolated_getindex.((cmap,), colors, (crange,)) end -function array2color(colors::AbstractArray{<:Colorant}, cmap, crange) - return RGBAf.(colors) -end +array2color(colors::AbstractArray{<:Colorant}, cmap, crange) = RGBAf.(colors) function converted_attribute(plot::AbstractPlot, key::Symbol) return lift(plot[key]) do value @@ -118,7 +112,7 @@ function create_shader(scene::Scene, plot::Makie.Mesh) end end - uniforms[:depth_shift] = get(plot, :depth_shift, Observable(0f0)) + uniforms[:depth_shift] = get(plot, :depth_shift, Observable(0.0f0)) uniforms[:normalmatrix] = map(scene.camera.view, plot.model) do v, m i = Vec(1, 2, 3) diff --git a/WGLMakie/src/particles.jl b/WGLMakie/src/particles.jl index b7703701429..0edd9a96066 100644 --- a/WGLMakie/src/particles.jl +++ b/WGLMakie/src/particles.jl @@ -7,9 +7,7 @@ function handle_color!(uniform_dict, instance_dict) else nothing, uniform_dict end - if color isa Colorant || - color isa AbstractVector{<:Colorant} || - color === nothing + if color isa Colorant || color isa AbstractVector{<:Colorant} || color === nothing delete!(uniform_dict, :colormap) elseif color isa AbstractArray{<:Real} uniform_dict[:color_getter] = """ @@ -41,10 +39,25 @@ function handle_color!(uniform_dict, instance_dict) end const IGNORE_KEYS = Set([ - :shading, :overdraw, :rotation, :distancefield, :space, :markerspace, :fxaa, - :visible, :transformation, :alpha, :linewidth, :transparency, :marker, - :lightposition, :cycle, :label, :inspector_clear, :inspector_hover, - :inspector_label + :shading, + :overdraw, + :rotation, + :distancefield, + :space, + :markerspace, + :fxaa, + :visible, + :transformation, + :alpha, + :linewidth, + :transparency, + :marker, + :lightposition, + :cycle, + :label, + :inspector_clear, + :inspector_hover, + :inspector_label, ]) function create_shader(scene::Scene, plot::MeshScatter) @@ -54,7 +67,7 @@ function create_shader(scene::Scene, plot::MeshScatter) return k in per_instance_keys && !(isscalar(v[])) end space = get(plot, :space, :data) - per_instance[:offset] = apply_transform(transform_func_obs(plot), plot[1], space) + per_instance[:offset] = apply_transform(transform_func_obs(plot), plot[1], space) for (k, v) in per_instance per_instance[k] = Buffer(lift_convert(k, v, plot)) @@ -77,7 +90,7 @@ function create_shader(scene::Scene, plot::MeshScatter) uniform_dict[:uv] = Vec2f(0) end - uniform_dict[:depth_shift] = get(plot, :depth_shift, Observable(0f0)) + uniform_dict[:depth_shift] = get(plot, :depth_shift, Observable(0.0f0)) uniform_dict[:backlight] = plot.backlight get!(uniform_dict, :ambient, Vec3f(1)) @@ -89,16 +102,22 @@ function create_shader(scene::Scene, plot::MeshScatter) end end - return InstancedProgram(WebGL(), lasset("particles.vert"), lasset("particles.frag"), - instance, VertexArray(; per_instance...); uniform_dict...) + return InstancedProgram( + WebGL(), + lasset("particles.vert"), + lasset("particles.frag"), + instance, + VertexArray(; per_instance...); + uniform_dict..., + ) end using Makie: to_spritemarker function scatter_shader(scene::Scene, attributes) # Potentially per instance attributes - per_instance_keys = (:pos, :rotations, :markersize, :color, :intensity, - :uv_offset_width, :quad_offset, :marker_offset) + per_instance_keys = + (:pos, :rotations, :markersize, :color, :intensity, :uv_offset_width, :quad_offset, :marker_offset) uniform_dict = Dict{Symbol,Any}() uniform_dict[:image] = false marker = nothing @@ -144,27 +163,32 @@ function scatter_shader(scene::Scene, attributes) end if uniform_dict[:shape_type][] == 3 - uniform_dict[:distancefield] = Sampler(atlas.data, minfilter=:linear, - magfilter=:linear, anisotropic=16f0) + uniform_dict[:distancefield] = + Sampler(atlas.data, minfilter=:linear, magfilter=:linear, anisotropic=16.0f0) uniform_dict[:atlas_texture_size] = Float32(size(atlas, 1)) # Texture must be quadratic else - uniform_dict[:atlas_texture_size] = 0f0 + uniform_dict[:atlas_texture_size] = 0.0f0 uniform_dict[:distancefield] = Observable(false) end handle_color!(uniform_dict, per_instance) - instance = uv_mesh(Rect2(-0.5f0, -0.5f0, 1f0, 1f0)) + instance = uv_mesh(Rect2(-0.5f0, -0.5f0, 1.0f0, 1.0f0)) uniform_dict[:resolution] = scene.camera.resolution - return InstancedProgram(WebGL(), lasset("simple.vert"), lasset("sprites.frag"), - instance, VertexArray(; per_instance...); uniform_dict...) + return InstancedProgram( + WebGL(), + lasset("simple.vert"), + lasset("sprites.frag"), + instance, + VertexArray(; per_instance...); + uniform_dict..., + ) end function create_shader(scene::Scene, plot::Scatter) # Potentially per instance attributes - per_instance_keys = (:offset, :rotations, :markersize, :color, :intensity, - :quad_offset) + per_instance_keys = (:offset, :rotations, :markersize, :color, :intensity, :quad_offset) per_instance = filter(plot.attributes.attributes) do (k, v) return k in per_instance_keys && !(isscalar(v[])) end @@ -173,16 +197,16 @@ function create_shader(scene::Scene, plot::Scatter) mspace = get(attributes, :markerspace, :pixel) cam = scene.camera attributes[:preprojection] = map(space, mspace, cam.projectionview, cam.resolution) do space, mspace, _, _ - Makie.clip_to_space(cam, mspace) * Makie.space_to_clip(cam, space) + return Makie.clip_to_space(cam, mspace) * Makie.space_to_clip(cam, space) end - attributes[:pos] = apply_transform(transform_func_obs(plot), plot[1], space) + attributes[:pos] = apply_transform(transform_func_obs(plot), plot[1], space) quad_offset = get(attributes, :marker_offset, Observable(Vec2f(0))) attributes[:marker_offset] = Vec3f(0) attributes[:quad_offset] = quad_offset attributes[:billboard] = map(rot -> isa(rot, Billboard), plot.rotations) attributes[:model] = plot.model attributes[:markerspace] = plot.markerspace - attributes[:depth_shift] = get(plot, :depth_shift, Observable(0f0)) + attributes[:depth_shift] = get(plot, :depth_shift, Observable(0.0f0)) delete!(attributes, :uv_offset_width) filter!(kv -> !(kv[2] isa Function), attributes) @@ -194,11 +218,14 @@ value_or_first(x::StaticVector) = x value_or_first(x::Mat) = x value_or_first(x) = x -function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.GlyphCollection, <:AbstractVector{<:Makie.GlyphCollection}}}}) +function create_shader( + scene::Scene, + plot::Makie.Text{<:Tuple{<:Union{<:Makie.GlyphCollection,<:AbstractVector{<:Makie.GlyphCollection}}}}, +) glyphcollection = plot[1] - res = map(x->Vec2f(widths(x)), pixelarea(scene)) + res = map(x -> Vec2f(widths(x)), pixelarea(scene)) projview = scene.camera.projectionview - transfunc = Makie.transform_func_obs(scene) + transfunc = Makie.transform_func_obs(scene) pos = plot.position space = plot.space markerspace = plot.markerspace @@ -221,18 +248,17 @@ function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.Gl end atlas = wgl_texture_atlas() glyph_data = map(pos, gcollection, offset, transfunc, space) do pos, gc, offset, transfunc, space - Makie.text_quads(atlas, pos, to_value(gc), offset, transfunc, space) + return Makie.text_quads(atlas, pos, to_value(gc), offset, transfunc, space) end # unpack values from the one signal: positions, char_offset, quad_offset, uv_offset_width, scale = map((1, 2, 3, 4, 5)) do i - lift(getindex, glyph_data, i) + return lift(getindex, glyph_data, i) end uniform_color = lift(glyphcollection) do gc if gc isa AbstractArray - reduce(vcat, (Makie.collect_vector(g.colors, length(g.glyphs)) for g in gc), - init = RGBAf[]) + reduce(vcat, (Makie.collect_vector(g.colors, length(g.glyphs)) for g in gc), init=RGBAf[]) else Makie.collect_vector(gc.colors, length(gc.glyphs)) end @@ -240,8 +266,7 @@ function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.Gl uniform_rotation = lift(glyphcollection) do gc if gc isa AbstractArray - reduce(vcat, (Makie.collect_vector(g.rotations, length(g.glyphs)) for g in gc), - init = Quaternionf[]) + reduce(vcat, (Makie.collect_vector(g.rotations, length(g.glyphs)) for g in gc), init=Quaternionf[]) else Makie.collect_vector(gc.rotations, length(gc.glyphs)) end @@ -250,7 +275,7 @@ function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.Gl cam = scene.camera # gl_attributes[:preprojection] = Observable(Mat4f(I)) preprojection = map(space, markerspace, cam.projectionview, cam.resolution) do s, ms, pv, res - Makie.clip_to_space(cam, ms) * Makie.space_to_clip(cam, s) + return Makie.clip_to_space(cam, ms) * Makie.space_to_clip(cam, s) end uniforms = Dict( @@ -266,7 +291,7 @@ function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.Gl :uv_offset_width => uv_offset_width, :transform_marker => get(plot.attributes, :transform_marker, Observable(true)), :billboard => Observable(false), - :depth_shift => get(plot, :depth_shift, Observable(0f0)) + :depth_shift => get(plot, :depth_shift, Observable(0.0f0)), ) return scatter_shader(scene, uniforms) diff --git a/WGLMakie/src/precompiles.jl b/WGLMakie/src/precompiles.jl index be5fa88c49a..8bdbe9d3d2d 100644 --- a/WGLMakie/src/precompiles.jl +++ b/WGLMakie/src/precompiles.jl @@ -11,7 +11,7 @@ macro compile(block) three_display(Session(), scene) JSServe.jsrender(Session(), figlike) s = serialize_scene(scene) - JSServe.serialize_binary(Session(), Dict(:data=>s)) + JSServe.serialize_binary(Session(), Dict(:data => s)) end end diff --git a/WGLMakie/src/serialization.jl b/WGLMakie/src/serialization.jl index d5c3bce2170..84f22946a28 100644 --- a/WGLMakie/src/serialization.jl +++ b/WGLMakie/src/serialization.jl @@ -13,9 +13,7 @@ function lift_convert(key, value, plot) end end -function Base.pairs(mesh::GeometryBasics.Mesh) - return (kv for kv in GeometryBasics.attributes(mesh)) -end +Base.pairs(mesh::GeometryBasics.Mesh) = (kv for kv in GeometryBasics.attributes(mesh)) # Don't overload faces to not invalidate _faces(x::VertexArray) = GeometryBasics.faces(getfield(x, :data)) @@ -35,53 +33,39 @@ serialize_three(val::Mat4f) = vec(val) serialize_three(val::Mat3) = vec(val) function serialize_three(observable::Observable) - return Dict(:type => "Observable", :id => observable.id, - :value => serialize_three(observable[])) + return Dict(:type => "Observable", :id => observable.id, :value => serialize_three(observable[])) end -function serialize_three(array::AbstractArray) - return serialize_three(flatten_buffer(array)) -end +serialize_three(array::AbstractArray) = serialize_three(flatten_buffer(array)) -function serialize_three(array::Buffer) - return serialize_three(flatten_buffer(array)) -end +serialize_three(array::Buffer) = serialize_three(flatten_buffer(array)) -function serialize_three(array::AbstractArray{UInt8}) - return Dict(:type => "Uint8Array", :data => array) -end +serialize_three(array::AbstractArray{UInt8}) = Dict(:type => "Uint8Array", :data => array) -function serialize_three(array::AbstractArray{Int32}) - return Dict(:type => "Int32Array", :data => array) -end +serialize_three(array::AbstractArray{Int32}) = Dict(:type => "Int32Array", :data => array) -function serialize_three(array::AbstractArray{UInt32}) - return Dict(:type => "Uint32Array", :data => array) -end +serialize_three(array::AbstractArray{UInt32}) = Dict(:type => "Uint32Array", :data => array) -function serialize_three(array::AbstractArray{Float32}) - return Dict(:type => "Float32Array", :data => array) -end +serialize_three(array::AbstractArray{Float32}) = Dict(:type => "Float32Array", :data => array) -function serialize_three(array::AbstractArray{Float16}) - return Dict(:type => "Float32Array", :data => array) -end +serialize_three(array::AbstractArray{Float16}) = Dict(:type => "Float32Array", :data => array) -function serialize_three(array::AbstractArray{Float64}) - return Dict(:type => "Float64Array", :data => array) -end +serialize_three(array::AbstractArray{Float64}) = Dict(:type => "Float64Array", :data => array) -function serialize_three(p::Makie.AbstractPattern) - return serialize_three(Makie.to_image(p)) -end +serialize_three(p::Makie.AbstractPattern) = serialize_three(Makie.to_image(p)) function serialize_three(color::Sampler{T,N}) where {T,N} - tex = Dict(:type => "Sampler", :data => serialize_three(color.data), - :size => [size(color.data)...], :three_format => three_format(T), - :three_type => three_type(eltype(T)), - :minFilter => three_filter(color.minfilter), - :magFilter => three_filter(color.magfilter), - :wrapS => three_repeat(color.repeat[1]), :anisotropy => color.anisotropic) + tex = Dict( + :type => "Sampler", + :data => serialize_three(color.data), + :size => [size(color.data)...], + :three_format => three_format(T), + :three_type => three_type(eltype(T)), + :minFilter => three_filter(color.minfilter), + :magFilter => three_filter(color.magfilter), + :wrapS => three_repeat(color.repeat[1]), + :anisotropy => color.anisotropic, + ) if N > 1 tex[:wrapT] = three_repeat(color.repeat[2]) end @@ -110,14 +94,14 @@ three_type(::Type{N0f8}) = "UnsignedByteType" function three_filter(sym::Symbol) sym === :linear && return "LinearFilter" sym === :nearest && return "NearestFilter" - error("Unknown filter mode '$sym'") + return error("Unknown filter mode '$sym'") end function three_repeat(s::Symbol) s === :clamp_to_edge && return "ClampToEdgeWrapping" s === :mirrored_repeat && return "MirroredRepeatWrapping" s === :repeat && return "RepeatWrapping" - error("Unknown repeat mode '$s'") + return error("Unknown repeat mode '$s'") end """ @@ -126,21 +110,13 @@ Flattens `array` array to be a 1D Vector of Float32 / UInt8. If presented with AbstractArray{<: Colorant/Tuple/SVector}, it will flatten those to their element type. """ -function flatten_buffer(array::AbstractArray{<: Number}) - return array -end +flatten_buffer(array::AbstractArray{<:Number}) = array -function flatten_buffer(array::Buffer) - return flatten_buffer(getfield(array, :data)) -end +flatten_buffer(array::Buffer) = flatten_buffer(getfield(array, :data)) -function flatten_buffer(array::AbstractArray{T}) where {T<:N0f8} - return reinterpret(UInt8, array) -end +flatten_buffer(array::AbstractArray{T}) where {T<:N0f8} = reinterpret(UInt8, array) -function flatten_buffer(array::AbstractArray{T}) where {T} - return flatten_buffer(reinterpret(eltype(T), array)) -end +flatten_buffer(array::AbstractArray{T}) where {T} = flatten_buffer(reinterpret(eltype(T), array)) lasset(paths...) = read(joinpath(@__DIR__, "..", "assets", paths...), String) @@ -151,13 +127,9 @@ isscalar(x::Billboard) = isscalar(x.rotation) isscalar(x::Observable) = isscalar(x[]) isscalar(x) = true -function ShaderAbstractions.type_string(::ShaderAbstractions.AbstractContext, - ::Type{<:Makie.Quaternion}) - return "vec4" -end +ShaderAbstractions.type_string(::ShaderAbstractions.AbstractContext, ::Type{<:Makie.Quaternion}) = "vec4" -function ShaderAbstractions.convert_uniform(::ShaderAbstractions.AbstractContext, - t::Quaternion) +function ShaderAbstractions.convert_uniform(::ShaderAbstractions.AbstractContext, t::Quaternion) return convert(Quaternion, t) end @@ -170,19 +142,15 @@ function wgl_convert(value, key1, key2) end end -function wgl_convert(value::AbstractMatrix, ::key"colormap", key2) - return ShaderAbstractions.Sampler(value) -end +wgl_convert(value::AbstractMatrix, ::key"colormap", key2) = ShaderAbstractions.Sampler(value) function serialize_buffer_attribute(buffer::AbstractVector{T}) where {T} return Dict(:flat => serialize_three(buffer), :type_length => tlength(T)) end -function serialize_named_buffer(buffer) - return Dict(map(pairs(buffer)) do (name, buff) - return name => serialize_buffer_attribute(buff) - end) -end +serialize_named_buffer(buffer) = Dict(map(pairs(buffer)) do (name, buff) + return name => serialize_buffer_attribute(buff) +end) function register_geometry_updates(update_buffer::Observable, named_buffers) for (name, buffer) in pairs(named_buffers) @@ -243,12 +211,15 @@ function serialize_three(program::Program) uniforms = serialize_uniforms(program.uniforms) attribute_updater = Observable(["", [], 0]) register_geometry_updates(attribute_updater, program) - return Dict(:vertexarrays => serialize_named_buffer(program.vertexarray), - :faces => indices, :uniforms => uniforms, - :vertex_source => program.vertex_source, - :fragment_source => program.fragment_source, - :uniform_updater => uniform_updater(program.uniforms), - :attribute_updater => attribute_updater) + return Dict( + :vertexarrays => serialize_named_buffer(program.vertexarray), + :faces => indices, + :uniforms => uniforms, + :vertex_source => program.vertex_source, + :fragment_source => program.fragment_source, + :uniform_updater => uniform_updater(program.uniforms), + :attribute_updater => attribute_updater, + ) end function serialize_scene(scene::Scene, serialized_scenes=[]) @@ -262,14 +233,16 @@ function serialize_scene(scene::Scene, serialized_scenes=[]) nothing end - serialized = Dict(:pixelarea => pixel_area, - :backgroundcolor => lift(hexcolor, scene.backgroundcolor), - :clearscene => scene.clear, - :camera => serialize_camera(scene), - :plots => serialize_plots(scene, scene.plots), - :cam3d_state => cam3d_state, - :visible => scene.visible, - :uuid => js_uuid(scene)) + serialized = Dict( + :pixelarea => pixel_area, + :backgroundcolor => lift(hexcolor, scene.backgroundcolor), + :clearscene => scene.clear, + :camera => serialize_camera(scene), + :plots => serialize_plots(scene, scene.plots), + :cam3d_state => cam3d_state, + :visible => scene.visible, + :uuid => js_uuid(scene), + ) push!(serialized_scenes, serialized) foreach(child -> serialize_scene(child, serialized_scenes), scene.children) diff --git a/WGLMakie/src/three_plot.jl b/WGLMakie/src/three_plot.jl index 430aed731e3..f60e0894f50 100644 --- a/WGLMakie/src/three_plot.jl +++ b/WGLMakie/src/three_plot.jl @@ -5,14 +5,21 @@ end JSServe.session(td::ThreeDisplay) = td.session Base.empty!(::ThreeDisplay) = nothing # TODO implement - function Base.close(screen::ThreeDisplay) # TODO implement end function Base.size(screen::ThreeDisplay) # look at d.qs().clientWidth for displayed width - width, height = round.(Int, WGLMakie.JSServe.evaljs_value(screen.session, WGLMakie.JSServe.js"[document.querySelector('canvas').width, document.querySelector('canvas').height]"; time_out=100)) + width, height = + round.( + Int, + WGLMakie.JSServe.evaljs_value( + screen.session, + WGLMakie.JSServe.js"[document.querySelector('canvas').width, document.querySelector('canvas').height]"; + time_out=100, + ), + ) return (width, height) end @@ -21,9 +28,12 @@ js_uuid(object) = string(objectid(object)) function Base.insert!(td::ThreeDisplay, scene::Scene, plot::Combined) plot_data = serialize_plots(scene, [plot]) - JSServe.evaljs_value(td.session, js""" - $(WGL).insert_plot($(js_uuid(scene)), $plot_data) - """) + JSServe.evaljs_value( + td.session, + js""" + $(WGL).insert_plot($(js_uuid(scene)), $plot_data) +""", + ) return end @@ -49,9 +59,7 @@ end Gets the ThreeJS object representing the plot object. """ -function find_plots(td::ThreeDisplay, plot::AbstractPlot) - return find_plots(JSServe.session(td), plot) -end +find_plots(td::ThreeDisplay, plot::AbstractPlot) = find_plots(JSServe.session(td), plot) function find_plots(session::Session, plot::AbstractPlot) uuids = js_uuid.(Makie.flatten_plots(plot)) @@ -60,11 +68,10 @@ end function JSServe.print_js_code(io::IO, plot::AbstractPlot, context) uuids = js_uuid.(Makie.flatten_plots(plot)) - JSServe.print_js_code(io, js"$(WGL).find_plots($(uuids))", context) + return JSServe.print_js_code(io, js"$(WGL).find_plots($(uuids))", context) end function three_display(session::Session, scene::Scene; screen_config...) - config = Makie.merge_screen_config(ScreenConfig, screen_config)::ScreenConfig serialized = serialize_scene(scene) diff --git a/WGLMakie/test/offline_export.jl b/WGLMakie/test/offline_export.jl index 0d08ca7c066..e38e813ac2b 100644 --- a/WGLMakie/test/offline_export.jl +++ b/WGLMakie/test/offline_export.jl @@ -1,8 +1,6 @@ using JSServe, WGLMakie, Makie -function handler(session, request) - return scatter(1:4, color=1:4) -end +handler(session, request) = scatter(1:4, color=1:4) dir = joinpath(@__DIR__, "exported") isdir(dir) || mkdir(dir) diff --git a/WGLMakie/test/runtests.jl b/WGLMakie/test/runtests.jl index 73dd5873a13..2c71af6ff24 100644 --- a/WGLMakie/test/runtests.jl +++ b/WGLMakie/test/runtests.jl @@ -6,7 +6,7 @@ using ImageMagick, FileIO using WGLMakie, Makie, Test using Pkg path = normpath(joinpath(dirname(pathof(Makie)), "..", "ReferenceTests")) -Pkg.develop(PackageSpec(path = path)) +Pkg.develop(PackageSpec(path=path)) using ReferenceTests @testset "mimes" begin @@ -52,7 +52,7 @@ excludes = Set([ "Array of Images Scatter", "Image Scatter different sizes", "scatter with stroke", - "scatter with glow" + "scatter with glow", ]) @testset "refimages" begin @@ -60,5 +60,5 @@ excludes = Set([ ReferenceTests.mark_broken_tests(excludes) recorded_files, recording_dir = @include_reference_tests "refimages.jl" missing_images, scores = ReferenceTests.record_comparison(recording_dir) - ReferenceTests.test_comparison(scores; threshold = 0.032) + ReferenceTests.test_comparison(scores; threshold=0.032) end diff --git a/src/Makie.jl b/src/Makie.jl index 9de6f9550e9..49087b856d5 100644 --- a/src/Makie.jl +++ b/src/Makie.jl @@ -5,7 +5,7 @@ if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@max_m end module ContoursHygiene - import Contour +import Contour end using .ContoursHygiene @@ -68,23 +68,71 @@ using Base.Iterators: repeated, drop import Base: getindex, setindex!, push!, append!, parent, get, get!, delete!, haskey using Observables: listeners, to_value, notify -using MakieCore: SceneLike, MakieScreen, ScenePlot, AbstractScene, AbstractPlot, Transformable, Attributes, Combined, Theme, Plot -using MakieCore: Arrows, Heatmap, Image, Lines, LineSegments, Mesh, MeshScatter, Poly, Scatter, Surface, Text, Volume, Wireframe -using MakieCore: ConversionTrait, NoConversion, PointBased, SurfaceLike, ContinuousSurface, DiscreteSurface, VolumeLike +using MakieCore: + SceneLike, + MakieScreen, + ScenePlot, + AbstractScene, + AbstractPlot, + Transformable, + Attributes, + Combined, + Theme, + Plot +using MakieCore: + Arrows, + Heatmap, + Image, + Lines, + LineSegments, + Mesh, + MeshScatter, + Poly, + Scatter, + Surface, + Text, + Volume, + Wireframe +using MakieCore: + ConversionTrait, NoConversion, PointBased, SurfaceLike, ContinuousSurface, DiscreteSurface, VolumeLike using MakieCore: Key, @key_str, Automatic, automatic, @recipe using MakieCore: Pixel, px, Unit, Billboard using MakieCore: not_implemented_for -import MakieCore: plot, plot!, theme, plotfunc, plottype, merge_attributes!, calculated_attributes!, -get_attribute, plotsym, plotkey, attributes, used_attributes -import MakieCore: arrows, heatmap, image, lines, linesegments, mesh, meshscatter, poly, scatter, surface, text, volume -import MakieCore: arrows!, heatmap!, image!, lines!, linesegments!, mesh!, meshscatter!, poly!, scatter!, surface!, text!, volume! +import MakieCore: + plot, + plot!, + theme, + plotfunc, + plottype, + merge_attributes!, + calculated_attributes!, + get_attribute, + plotsym, + plotkey, + attributes, + used_attributes +import MakieCore: + arrows, heatmap, image, lines, linesegments, mesh, meshscatter, poly, scatter, surface, text, volume +import MakieCore: + arrows!, + heatmap!, + image!, + lines!, + linesegments!, + mesh!, + meshscatter!, + poly!, + scatter!, + surface!, + text!, + volume! import MakieCore: convert_arguments, convert_attribute, default_theme, conversion_trait export @L_str export ConversionTrait, NoConversion, PointBased, SurfaceLike, ContinuousSurface, DiscreteSurface, VolumeLike export Pixel, px, Unit, plotkey, attributes, used_attributes -const RealVector{T} = AbstractVector{T} where T <: Number +const RealVector{T} = AbstractVector{T} where {T<:Number} const RGBAf = RGBA{Float32} const RGBf = RGB{Float32} const NativeFont = FreeTypeAbstraction.FTFont @@ -169,7 +217,6 @@ include("stats/boxplot.jl") include("stats/violin.jl") include("stats/hexbin.jl") - # Interactiveness include("interaction/events.jl") include("interaction/interactive_api.jl") @@ -240,14 +287,24 @@ export to_world export mouseover, onpick, pick, Events, Keyboard, Mouse, mouse_selection, is_mouseinside export ispressed, Exclusively export connect_screen -export window_area, window_open, mouse_buttons, mouse_position, mouseposition_px, - scroll, keyboard_buttons, unicode_input, dropped_files, hasfocus, entered_window +export window_area, + window_open, + mouse_buttons, + mouse_position, + mouseposition_px, + scroll, + keyboard_buttons, + unicode_input, + dropped_files, + hasfocus, + entered_window export disconnect! export DataInspector export Consume # Raymarching algorithms -export RaymarchAlgorithm, IsoValue, Absorption, MaximumIntensityProjection, AbsorptionRGBA, IndexedAbsorptionRGBA +export RaymarchAlgorithm, + IsoValue, Absorption, MaximumIntensityProjection, AbsorptionRGBA, IndexedAbsorptionRGBA export Billboard # Reexports of @@ -268,7 +325,6 @@ export PlotSpec export plot!, plot export abline! # until deprecation removal - export Stepper, replay_events, record_events, RecordEvents, record, VideoStream export VideoStream, recordframe!, record, Record export save @@ -283,19 +339,17 @@ export assetpath function icon() path = assetpath("icons") imgs = FileIO.load.(joinpath.(path, readdir(path))) - icons = map(img-> RGBA{Colors.N0f8}.(img), imgs) + icons = map(img -> RGBA{Colors.N0f8}.(img), imgs) return reinterpret.(NTuple{4,UInt8}, icons) end -function logo() - FileIO.load(assetpath("logo.png")) -end +logo() = FileIO.load(assetpath("logo.png")) function __init__() # Make GridLayoutBase default row and colgaps themeable when using Makie # This mutates module-level state so it could mess up other libraries using # GridLayoutBase at the same time as Makie, which is unlikely, though - GridLayoutBase.DEFAULT_COLGAP_GETTER[] = function() + GridLayoutBase.DEFAULT_COLGAP_GETTER[] = function () ct = Makie.current_default_theme() if haskey(ct, :colgap) ct[:colgap][] @@ -303,7 +357,7 @@ function __init__() GridLayoutBase.DEFAULT_COLGAP[] end end - GridLayoutBase.DEFAULT_ROWGAP_GETTER[] = function() + GridLayoutBase.DEFAULT_ROWGAP_GETTER[] = function () ct = Makie.current_default_theme() if haskey(ct, :rowgap) ct[:rowgap][] @@ -316,7 +370,7 @@ function __init__() cfg_path = joinpath(homedir(), ".config", "makie", "theme.jl") if isfile(cfg_path) @warn "The global configuration file is no longer supported." * - "Please include the file manually with `include(\"$cfg_path\")` before plotting." + "Please include the file manually with `include(\"$cfg_path\")` before plotting." end end @@ -331,9 +385,23 @@ include("basic_recipes/text.jl") include("basic_recipes/raincloud.jl") include("deprecated.jl") -export Arrows , Heatmap , Image , Lines , LineSegments , Mesh , MeshScatter , Poly , Scatter , Surface , Text , Volume , Wireframe -export arrows , heatmap , image , lines , linesegments , mesh , meshscatter , poly , scatter , surface , text , volume , wireframe -export arrows! , heatmap! , image! , lines! , linesegments! , mesh! , meshscatter! , poly! , scatter! , surface! , text! , volume! , wireframe! +export Arrows, + Heatmap, Image, Lines, LineSegments, Mesh, MeshScatter, Poly, Scatter, Surface, Text, Volume, Wireframe +export arrows, + heatmap, image, lines, linesegments, mesh, meshscatter, poly, scatter, surface, text, volume, wireframe +export arrows!, + heatmap!, + image!, + lines!, + linesegments!, + mesh!, + meshscatter!, + poly!, + scatter!, + surface!, + text!, + volume!, + wireframe! export PointLight, EnvironmentLight, AmbientLight, SSAO diff --git a/src/basic_recipes/ablines.jl b/src/basic_recipes/ablines.jl index 5a3f794b54f..bc3752f38f0 100644 --- a/src/basic_recipes/ablines.jl +++ b/src/basic_recipes/ablines.jl @@ -7,26 +7,20 @@ You can pass one or multiple intercepts or slopes. All style attributes are the same as for `LineSegments`. """ @recipe(ABLines) do scene - Theme(; - xautolimits = false, - yautolimits = false, - default_theme(LineSegments, scene)..., - cycle = :color, - ) + return Theme(; xautolimits=false, yautolimits=false, default_theme(LineSegments, scene)..., cycle=:color) end function Makie.plot!(p::ABLines) scene = Makie.parent_scene(p) transf = transform_func(scene) - - - is_identity_transform(transf) || throw(ArgumentError("ABLines is only defined for the identity transform, not $(typeof(transf)).")) + is_identity_transform(transf) || + throw(ArgumentError("ABLines is only defined for the identity transform, not $(typeof(transf)).")) limits = lift(projview_to_2d_limits, scene.camera.projectionview) points = Observable(Point2f[]) - + onany(limits, p[1], p[2]) do lims, intercept, slope inv = inverse_transform(transf) empty!(points[]) @@ -35,18 +29,22 @@ function Makie.plot!(p::ABLines) f(x) = intercept + slope * x xmin, xmax = first.(extrema(lims)) push!(points[], Point2f(xmin, f(xmin))) - push!(points[], Point2f(xmax, f(xmax))) + return push!(points[], Point2f(xmax, f(xmax))) end - notify(points) + return notify(points) end notify(p[1]) linesegments!(p, points; p.attributes...) - p + return p end function abline!(args...; kwargs...) - Base.depwarn("abline! is deprecated and will be removed in the future. Use ablines / ablines! instead." , :abline!, force = true) - ablines!(args...; kwargs...) + Base.depwarn( + "abline! is deprecated and will be removed in the future. Use ablines / ablines! instead.", + :abline!, + force=true, + ) + return ablines!(args...; kwargs...) end diff --git a/src/basic_recipes/annotations.jl b/src/basic_recipes/annotations.jl index 941614d2301..526f30e2999 100644 --- a/src/basic_recipes/annotations.jl +++ b/src/basic_recipes/annotations.jl @@ -7,19 +7,21 @@ Plots an array of texts at each position in `positions`. $(ATTRIBUTES) """ @recipe(Annotations, text, position) do scene - default_theme(scene, Text) + return default_theme(scene, Text) end -function convert_arguments(::Type{<: Annotations}, - strings::AbstractVector{<: AbstractString}, - text_positions::AbstractVector{<: Point{N}}) where N +function convert_arguments( + ::Type{<:Annotations}, + strings::AbstractVector{<:AbstractString}, + text_positions::AbstractVector{<:Point{N}}, +) where {N} return (map(strings, text_positions) do str, pos - (String(str), Point{N, Float32}(pos)) + return (String(str), Point{N,Float32}(pos)) end,) end function plot!(plot::Annotations) # annotations are not necessary anymore with the different text behavior text!(plot, plot[1]; plot.attributes...) - plot + return plot end diff --git a/src/basic_recipes/arc.jl b/src/basic_recipes/arc.jl index 8701e7a51bf..e8f9709f51d 100644 --- a/src/basic_recipes/arc.jl +++ b/src/basic_recipes/arc.jl @@ -15,20 +15,17 @@ Examples: $(ATTRIBUTES) """ @recipe(Arc, origin, radius, start_angle, stop_angle) do scene - Attributes(; - default_theme(scene, Lines)..., - resolution = 361, - ) + return Attributes(; default_theme(scene, Lines)..., resolution=361) end function plot!(p::Arc) args = getindex.(p, (:origin, :radius, :start_angle, :stop_angle, :resolution)) positions = lift(args...) do origin, radius, start_angle, stop_angle, resolution map(range(start_angle, stop=stop_angle, length=resolution)) do angle - origin .+ Point2f((cos(angle), sin(angle)) .* radius) + return origin .+ Point2f((cos(angle), sin(angle)) .* radius) end end attr = Attributes(p) delete!(attr, :resolution) - lines!(p, attr, positions) + return lines!(p, attr, positions) end diff --git a/src/basic_recipes/arrows.jl b/src/basic_recipes/arrows.jl index 9a7e8ac0952..be22f313bda 100644 --- a/src/basic_recipes/arrows.jl +++ b/src/basic_recipes/arrows.jl @@ -39,8 +39,8 @@ function arrow_head(N, marker::Automatic, quality) return :utriangle else merge([ - _circle(Point3f(0), 0.5f0, Vec3f(0,0,-1), quality), - _mantle(Point3f(0), Point3f(0,0,1), 0.5f0, 0f0, quality) + _circle(Point3f(0), 0.5f0, Vec3f(0, 0, -1), quality), + _mantle(Point3f(0), Point3f(0, 0, 1), 0.5f0, 0.0f0, quality), ]) end end @@ -51,20 +51,19 @@ function arrow_tail(N, marker::Automatic, quality) nothing else merge([ - _circle(Point3f(0,0,-1), 0.5f0, Vec3f(0,0,-1), quality), - _mantle(Point3f(0,0,-1), Point3f(0), 0.5f0, 0.5f0, quality) + _circle(Point3f(0, 0, -1), 0.5f0, Vec3f(0, 0, -1), quality), + _mantle(Point3f(0, 0, -1), Point3f(0), 0.5f0, 0.5f0, quality), ]) end end - function _mantle(origin, extremity, r1, r2, N) dphi = 2pi / N # Equivalent to # xy = cos(atan(temp)) # z = sin(atan(temp)) - temp = -(r2-r1) / norm(extremity .- origin) + temp = -(r2 - r1) / norm(extremity .- origin) xy = 1.0 / sqrt(temp^2 + 1) z = temp / sqrt(temp^2 + 1) @@ -72,54 +71,77 @@ function _mantle(origin, extremity, r1, r2, N) normals = Vector{Vec3f}(undef, 2N) faces = Vector{GLTriangleFace}(undef, 2N) - for (i, phi) in enumerate(0:dphi:2pi-0.5dphi) + for (i, phi) in enumerate(0:dphi:(2pi - 0.5dphi)) coords[2i - 1] = origin .+ r1 * Vec3f(cos(phi), sin(phi), 0) coords[2i] = extremity .+ r2 * Vec3f(cos(phi), sin(phi), 0) - normals[2i - 1] = Vec3f(xy*cos(phi), xy*sin(phi), z) - normals[2i] = Vec3f(xy*cos(phi), xy*sin(phi), z) - faces[2i - 1] = GLTriangleFace(2i-1, mod1(2i+1, 2N), 2i) - faces[2i] = GLTriangleFace(mod1(2i+1, 2N), mod1(2i+2, 2N), 2i) + normals[2i - 1] = Vec3f(xy * cos(phi), xy * sin(phi), z) + normals[2i] = Vec3f(xy * cos(phi), xy * sin(phi), z) + faces[2i - 1] = GLTriangleFace(2i - 1, mod1(2i + 1, 2N), 2i) + faces[2i] = GLTriangleFace(mod1(2i + 1, 2N), mod1(2i + 2, 2N), 2i) end - GeometryBasics.Mesh(meta(coords; normals=normals), faces) + return GeometryBasics.Mesh(meta(coords; normals=normals), faces) end # GeometryBasics.Circle doesn't work with Point3f... function _circle(origin, r, normal, N) dphi = 2pi / N - coords = Vector{Point3f}(undef, N+1) - normals = fill(normal, N+1) + coords = Vector{Point3f}(undef, N + 1) + normals = fill(normal, N + 1) faces = Vector{GLTriangleFace}(undef, N) - for (i, phi) in enumerate(0:dphi:2pi-0.5dphi) + for (i, phi) in enumerate(0:dphi:(2pi - 0.5dphi)) coords[i] = origin .+ r * Vec3f(cos(phi), sin(phi), 0) - faces[i] = GLTriangleFace(N+1, mod1(i+1, N), i) + faces[i] = GLTriangleFace(N + 1, mod1(i + 1, N), i) end - coords[N+1] = origin + coords[N + 1] = origin - GeometryBasics.Mesh(meta(coords; normals=normals), faces) + return GeometryBasics.Mesh(meta(coords; normals=normals), faces) end - -convert_arguments(::Type{<: Arrows}, x, y, u, v) = (Point2f.(x, y), Vec2f.(u, v)) -function convert_arguments(::Type{<: Arrows}, x::AbstractVector, y::AbstractVector, u::AbstractMatrix, v::AbstractMatrix) - (vec(Point2f.(x, y')), vec(Vec2f.(u, v))) +convert_arguments(::Type{<:Arrows}, x, y, u, v) = (Point2f.(x, y), Vec2f.(u, v)) +function convert_arguments( + ::Type{<:Arrows}, + x::AbstractVector, + y::AbstractVector, + u::AbstractMatrix, + v::AbstractMatrix, +) + return (vec(Point2f.(x, y')), vec(Vec2f.(u, v))) end -convert_arguments(::Type{<: Arrows}, x, y, z, u, v, w) = (Point3f.(x, y, z), Vec3f.(u, v, w)) +convert_arguments(::Type{<:Arrows}, x, y, z, u, v, w) = (Point3f.(x, y, z), Vec3f.(u, v, w)) -function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N, T}}, V}}) where {N, T, V} +function plot!(arrowplot::Arrows{<:Tuple{AbstractVector{<:Point{N,T}},V}}) where {N,T,V} @extract arrowplot ( - points, directions, colormap, normalize, align, - arrowtail, color, linecolor, linestyle, linewidth, lengthscale, - arrowhead, arrowsize, arrowcolor, quality, + points, + directions, + colormap, + normalize, + align, + arrowtail, + color, + linecolor, + linestyle, + linewidth, + lengthscale, + arrowhead, + arrowsize, + arrowcolor, + quality, # passthrough - diffuse, specular, shininess, - fxaa, ssao, transparency, visible, inspectable + diffuse, + specular, + shininess, + fxaa, + ssao, + transparency, + visible, + inspectable, ) - arrow_c = map((a, c)-> a === automatic ? c : a , arrowcolor, color) - line_c = map((a, c)-> a === automatic ? c : a , linecolor, color) + arrow_c = map((a, c) -> a === automatic ? c : a, arrowcolor, color) + line_c = map((a, c) -> a === automatic ? c : a, linecolor, color) if N == 2 fxaa_bool = @lift($fxaa == automatic ? false : $fxaa) @@ -131,7 +153,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N, T}}, V}}) w else shift = Vec2f(0) end - Point2f(p1 .- shift) => Point2f(p1 .- shift .+ (dir .* s)) + return Point2f(p1 .- shift) => Point2f(p1 .- shift .+ (dir .* s)) end end @@ -154,32 +176,42 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N, T}}, V}}) w angle = ifelse(diff[1] > 0, 2pi - angle, angle) end end - Billboard(angles) + return Billboard(angles) end end linesegments!( - arrowplot, headstart, - color = line_c, colormap = colormap, linestyle = linestyle, - linewidth = @lift($linewidth === automatic ? 1f0 : $linewidth), - fxaa = fxaa_bool, inspectable = inspectable, - transparency = transparency, visible = visible, + arrowplot, + headstart, + color=line_c, + colormap=colormap, + linestyle=linestyle, + linewidth=@lift($linewidth === automatic ? 1.0f0 : $linewidth), + fxaa=fxaa_bool, + inspectable=inspectable, + transparency=transparency, + visible=visible, ) scatter!( arrowplot, - lift(x-> last.(x), headstart), - marker = @lift(arrow_head(2, $arrowhead, $quality)), - markersize = @lift($arrowsize === automatic ? theme(scene, :markersize)[] : $arrowsize), - color = arrow_c, rotations = rotations, strokewidth = 0.0, - colormap = colormap, markerspace = arrowplot.markerspace, - fxaa = fxaa_bool, inspectable = inspectable, - transparency = transparency, visible = visible + lift(x -> last.(x), headstart), + marker=@lift(arrow_head(2, $arrowhead, $quality)), + markersize=@lift($arrowsize === automatic ? theme(scene, :markersize)[] : $arrowsize), + color=arrow_c, + rotations=rotations, + strokewidth=0.0, + colormap=colormap, + markerspace=arrowplot.markerspace, + fxaa=fxaa_bool, + inspectable=inspectable, + transparency=transparency, + visible=visible, ) else fxaa_bool = @lift($fxaa == automatic ? true : $fxaa) - msize = Observable{Union{Vec3f, Vector{Vec3f}}}() - markersize = Observable{Union{Vec3f, Vector{Vec3f}}}() + msize = Observable{Union{Vec3f,Vector{Vec3f}}}() + markersize = Observable{Union{Vec3f,Vector{Vec3f}}}() map!(msize, directions, normalize, linewidth, lengthscale, arrowsize) do dirs, n, linewidth, ls, as ms = as isa Automatic ? Vec3f(0.2, 0.2, 0.3) : as markersize[] = to_3d_scale(ms) @@ -188,7 +220,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N, T}}, V}}) w return broadcast((lw, ls) -> Vec3f(lw, lw, ls), lw, ls) else return broadcast(lw, dirs, ls) do lw, dir, s - Vec3f(lw, lw, norm(dir) * s) + return Vec3f(lw, lw, norm(dir) * s) end end end @@ -200,31 +232,42 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N, T}}, V}}) w else shift = -s .* dir end - Point3f(p .- shift) + return Point3f(p .- shift) end end meshscatter!( arrowplot, - start, rotations = directions, - marker = @lift(arrow_tail(3, $arrowtail, $quality)), - markersize = msize, - color = line_c, colormap = colormap, - fxaa = fxaa_bool, ssao = ssao, - diffuse = diffuse, - specular = specular, shininess = shininess, inspectable = inspectable, - transparency = transparency, visible = visible + start, + rotations=directions, + marker=@lift(arrow_tail(3, $arrowtail, $quality)), + markersize=msize, + color=line_c, + colormap=colormap, + fxaa=fxaa_bool, + ssao=ssao, + diffuse=diffuse, + specular=specular, + shininess=shininess, + inspectable=inspectable, + transparency=transparency, + visible=visible, ) meshscatter!( arrowplot, - start, rotations = directions, - marker = @lift(arrow_head(3, $arrowhead, $quality)), - markersize = markersize, - color = arrow_c, colormap = colormap, - fxaa = fxaa_bool, ssao = ssao, - diffuse = diffuse, - specular = specular, shininess = shininess, inspectable = inspectable, - transparency = transparency, visible = visible + start, + rotations=directions, + marker=@lift(arrow_head(3, $arrowhead, $quality)), + markersize=markersize, + color=arrow_c, + colormap=colormap, + fxaa=fxaa_bool, + ssao=ssao, + diffuse=diffuse, + specular=specular, + shininess=shininess, + inspectable=inspectable, + transparency=transparency, + visible=visible, ) end - end diff --git a/src/basic_recipes/axis.jl b/src/basic_recipes/axis.jl index f9744a8efb5..f447a0244b2 100644 --- a/src/basic_recipes/axis.jl +++ b/src/basic_recipes/axis.jl @@ -1,26 +1,22 @@ module Formatters - using Showoff - - function scientific(ticks::AbstractVector) - Showoff.showoff(ticks, :scientific) - end - - function plain(ticks::AbstractVector) - try - Showoff.showoff(ticks, :plain) - catch e - bt = Base.catch_backtrace() - Base.showerror(stderr, e) - Base.show_backtrace(stdout, bt) - println("with ticks: ", ticks) - String["-Inf", "Inf"] - end +using Showoff + +scientific(ticks::AbstractVector) = Showoff.showoff(ticks, :scientific) + +plain(ticks::AbstractVector) = + try + Showoff.showoff(ticks, :plain) + catch e + bt = Base.catch_backtrace() + Base.showerror(stderr, e) + Base.show_backtrace(stdout, bt) + println("with ticks: ", ticks) + String["-Inf", "Inf"] end end using .Formatters - to_3tuple(x) = ntuple(i -> x, Val(3)) to_3tuple(x::NTuple{3,Any}) = x @@ -36,14 +32,9 @@ Plots a 3-dimensional OldAxis. $(ATTRIBUTES) """ @recipe(Axis3D) do scene - - q1 = qrotation(Vec3f(1, 0, 0), -0.5f0*pi) - q2 = qrotation(Vec3f(0, 0, 1), 1f0*pi) - tickrotations3d = ( - qrotation(Vec3f(0,0,1), -1.5pi), - q2, - qrotation(Vec3f(1, 0, 0), -0.5pi) * q2 - ) + q1 = qrotation(Vec3f(1, 0, 0), -0.5f0 * pi) + q2 = qrotation(Vec3f(0, 0, 1), 1.0f0 * pi) + tickrotations3d = (qrotation(Vec3f(0, 0, 1), -1.5pi), q2, qrotation(Vec3f(1, 0, 0), -0.5pi) * q2) axisnames_rotation3d = tickrotations3d tickalign3d = ( (:left, :center), # x axis @@ -55,138 +46,122 @@ $(ATTRIBUTES) grid_color = RGBAf(0.5, 0.5, 0.5, 0.4) grid_thickness = 1 axis_linewidth = 1.5 - gridthickness = ntuple(x-> 1f0, Val(3)) - axislinewidth = ntuple(x->1.5f0, Val(3)) + gridthickness = ntuple(x -> 1.0f0, Val(3)) + axislinewidth = ntuple(x -> 1.5f0, Val(3)) tsize = 5 # in percent - Attributes( - visible = true, - showticks = (true, true, true), - showaxis = (true, true, true), - showgrid = (true, true, true), - scale = Vec3f(1), - padding = 0.1, - inspectable = false, - fonts = theme(scene, :fonts), - names = Attributes( - axisnames = ("x", "y", "z"), - textcolor = (:black, :black, :black), - rotation = axisnames_rotation3d, - fontsize = (6.0, 6.0, 6.0), - align = axisnames_align3d, - font = lift(to_3tuple, theme(scene, :font)), - gap = 3 + return Attributes( + visible=true, + showticks=(true, true, true), + showaxis=(true, true, true), + showgrid=(true, true, true), + scale=Vec3f(1), + padding=0.1, + inspectable=false, + fonts=theme(scene, :fonts), + names=Attributes( + axisnames=("x", "y", "z"), + textcolor=(:black, :black, :black), + rotation=axisnames_rotation3d, + fontsize=(6.0, 6.0, 6.0), + align=axisnames_align3d, + font=lift(to_3tuple, theme(scene, :font)), + gap=3, ), - - ticks = Attributes( - ranges_labels = (automatic, automatic), - formatter = Formatters.plain, - - textcolor = (tick_color, tick_color, tick_color), - - rotation = tickrotations3d, - fontsize = (tsize, tsize, tsize), - align = tickalign3d, - gap = 3, - font = lift(to_3tuple, theme(scene, :font)), + ticks=Attributes( + ranges_labels=(automatic, automatic), + formatter=Formatters.plain, + textcolor=(tick_color, tick_color, tick_color), + rotation=tickrotations3d, + fontsize=(tsize, tsize, tsize), + align=tickalign3d, + gap=3, + font=lift(to_3tuple, theme(scene, :font)), + ), + frame=Attributes( + linecolor=(grid_color, grid_color, grid_color), + linewidth=(grid_thickness, grid_thickness, grid_thickness), + axislinewidth=(axis_linewidth, axis_linewidth, axis_linewidth), + axiscolor=(:black, :black, :black), ), - - frame = Attributes( - linecolor = (grid_color, grid_color, grid_color), - linewidth = (grid_thickness, grid_thickness, grid_thickness), - axislinewidth = (axis_linewidth, axis_linewidth, axis_linewidth), - axiscolor = (:black, :black, :black), - ) ) end isaxis(x) = false isaxis(x::Axis3D) = true -const Limits{N} = NTuple{N, <:Tuple{<: Number, <: Number}} +const Limits{N} = NTuple{N,<:Tuple{<:Number,<:Number}} -function default_ticks(limits::Limits, ticks, scale_func::Function) - default_ticks.(limits, (ticks,), scale_func) -end +default_ticks(limits::Limits, ticks, scale_func::Function) = default_ticks.(limits, (ticks,), scale_func) -default_ticks(limits::Tuple{Number, Number}, ticks, scale_func::Function) = default_ticks(limits..., ticks, scale_func) +function default_ticks(limits::Tuple{Number,Number}, ticks, scale_func::Function) + return default_ticks(limits..., ticks, scale_func) +end -function default_ticks( - lmin::Number, lmax::Number, - ticks::AbstractVector{<: Number}, scale_func::Function - ) - scale_func.((filter(t -> lmin <= t <= lmax, ticks))) +function default_ticks(lmin::Number, lmax::Number, ticks::AbstractVector{<:Number}, scale_func::Function) + return scale_func.((filter(t -> lmin <= t <= lmax, ticks))) end -function default_ticks( - lmin::Number, lmax::Number, ::Automatic, scale_func::Function - ) +function default_ticks(lmin::Number, lmax::Number, ::Automatic, scale_func::Function) # scale the limits scaled_ticks, mini, maxi = optimize_ticks( Float64(scale_func(lmin)), Float64(scale_func(lmax)); - k_min = 4, # minimum number of ticks - k_max = 8, # maximum number of ticks + k_min=4, # minimum number of ticks + k_max=8, # maximum number of ticks ) length(scaled_ticks) == 1 && isnan(scaled_ticks[1]) && return [-Inf, Inf] - scaled_ticks + return scaled_ticks end -function default_ticks( - lmin::Number, lmax::Number, ticks::Integer, scale_func = identity - ) +function default_ticks(lmin::Number, lmax::Number, ticks::Integer, scale_func=identity) scaled_ticks, mini, maxi = optimize_ticks( Float64(scale_func(lmin)), Float64(scale_func(lmax)); - k_min = ticks, # minimum number of ticks - k_max = ticks, # maximum number of ticks - k_ideal = ticks, + k_min=ticks, # minimum number of ticks + k_max=ticks, # maximum number of ticks + k_ideal=ticks, # `strict_span = false` rewards cases where the span of the # chosen ticks is not too much bigger than amin - amax: - strict_span = false, + strict_span=false, ) - scaled_ticks + return scaled_ticks end -function default_ticks(x::Automatic, limits::Tuple, n) - default_ticks(limits, n, identity) -end +default_ticks(x::Automatic, limits::Tuple, n) = default_ticks(limits, n, identity) -function default_ticks(ticks::Tuple, limits::Tuple, n::Tuple) - default_ticks.(ticks, (limits,), n) -end +default_ticks(ticks::Tuple, limits::Tuple, n::Tuple) = default_ticks.(ticks, (limits,), n) default_ticks(ticks::Tuple, limits::Limits, n) = default_ticks.(ticks, limits, (n,)) default_ticks(ticks::Tuple, limits::Limits, n::Tuple) = default_ticks.(ticks, limits, n) -default_ticks(ticks::AbstractVector{<: Number}, limits, n) = ticks - +default_ticks(ticks::AbstractVector{<:Number}, limits, n) = ticks -function default_labels(x::NTuple{N, Any}, formatter::Function) where N - default_labels.(x, formatter) -end +default_labels(x::NTuple{N,Any}, formatter::Function) where {N} = default_labels.(x, formatter) -function default_labels(x::AbstractVector, y::AbstractVector, formatter::Function = Formatters.plain) - default_labels.((x, y), formatter) +function default_labels(x::AbstractVector, y::AbstractVector, formatter::Function=Formatters.plain) + return default_labels.((x, y), formatter) end -function default_labels(ticks::AbstractVector, formatter::Function = Formatters.plain) +function default_labels(ticks::AbstractVector, formatter::Function=Formatters.plain) if applicable(formatter, ticks) return formatter(ticks) # takes the whole array elseif applicable(formatter, first(ticks)) return formatter.(ticks) else - error("Formatting function $(formatter) is neither applicable to $(typeof(ticks)) nor $(eltype(ticks)).") + error( + "Formatting function $(formatter) is neither applicable to $(typeof(ticks)) nor $(eltype(ticks)).", + ) end end default_labels(x::Automatic, ranges, formatter) = default_labels(ranges, formatter) default_labels(x::Tuple, ranges::Tuple, formatter) = default_labels.(x, ranges, (formatter,)) default_labels(x::Tuple, ranges, formatter) = default_labels.(x, (ranges,), (formatter,)) -default_labels(x::AbstractVector{<: AbstractString}, ranges, formatter::Function) = x -default_labels(x::AbstractVector{<: AbstractString}, ranges::AbstractVector, formatter::Function) = x +default_labels(x::AbstractVector{<:AbstractString}, ranges, formatter::Function) = x +default_labels(x::AbstractVector{<:AbstractString}, ranges::AbstractVector, formatter::Function) = x -function convert_arguments(::Type{<: Axis3D}, limits::Rect) +function convert_arguments(::Type{<:Axis3D}, limits::Rect) e = (minimum(limits), maximum(limits)) return (((e[1][1], e[2][1]), (e[1][2], e[2][2]), (e[1][3], e[2][3])),) end @@ -194,44 +169,59 @@ end a_length(x::AbstractVector) = length(x) a_length(x::Automatic) = x -function calculated_attributes!(::Type{<: Axis3D}, plot) +function calculated_attributes!(::Type{<:Axis3D}, plot) ticks = plot.ticks args = (plot[1], ticks.ranges, ticks.labels, ticks.formatter) ticks[:ranges_labels] = lift(args...) do lims, ranges, labels, formatter num_ticks = labels === automatic ? automatic : a_length.(labels) ranges = default_ticks(ranges, lims, num_ticks) labels = default_labels(labels, ranges, formatter) - (ranges, labels) + return (ranges, labels) end return end -function labelposition(ranges, dim, dir, tgap, origin::StaticVector{N}) where N +function labelposition(ranges, dim, dir, tgap, origin::StaticVector{N}) where {N} a, b = extrema(ranges[dim]) whalf = Float32(((b - a) / 2)) - halfaxis = unit(Point{N, Float32}, dim) .* whalf + halfaxis = unit(Point{N,Float32}, dim) .* whalf - origin .+ (halfaxis .+ (normalize(dir) * tgap)) + return origin .+ (halfaxis .+ (normalize(dir) * tgap)) end -_widths(x::Tuple{<: Number, <: Number}) = x[2] - x[1] +_widths(x::Tuple{<:Number,<:Number}) = x[2] - x[1] _widths(x) = Float32(maximum(x) - minimum(x)) to3tuple(x::Tuple{Any}) = (x[1], x[1], x[1]) -to3tuple(x::Tuple{Any, Any}) = (x[1], x[2], x[2]) -to3tuple(x::Tuple{Any, Any, Any}) = x -to3tuple(x) = ntuple(i-> x, Val(3)) +to3tuple(x::Tuple{Any,Any}) = (x[1], x[2], x[2]) +to3tuple(x::Tuple{Any,Any,Any}) = x +to3tuple(x) = ntuple(i -> x, Val(3)) function draw_axis3d(textbuffer, linebuffer, scale, limits, ranges_labels, fonts, args...) # make sure we extend all args to 3D ranges, ticklabels = ranges_labels args3d = to3tuple.(args) ( - showaxis, showticks, showgrid, - axisnames, axisnames_color, axisnames_size, axisrotation, axisalign, - axisnames_font, titlegap, - gridcolors, gridthickness, axislinewidth, axiscolors, - ttextcolor, trotation, tfontsize, talign, tfont, tgap, + showaxis, + showticks, + showgrid, + axisnames, + axisnames_color, + axisnames_size, + axisrotation, + axisalign, + axisnames_font, + titlegap, + gridcolors, + gridthickness, + axislinewidth, + axiscolors, + ttextcolor, + trotation, + tfontsize, + talign, + tfont, + tgap, padding, ) = args3d # splat to names @@ -239,35 +229,35 @@ function draw_axis3d(textbuffer, linebuffer, scale, limits, ranges_labels, fonts start!(textbuffer) start!(linebuffer) - limit_widths = map(x-> x[2] - x[1], limits) + limit_widths = map(x -> x[2] - x[1], limits) # pad the drawn limits and use them as the ranges - limits = map((lim, p)-> (lim[1] - p, lim[2] + p), limits, limit_widths .* padding) + limits = map((lim, p) -> (lim[1] - p, lim[2] + p), limits, limit_widths .* padding) mini, maxi = first.(limits), last.(limits) - origin = Point{N, Float32}(min.(mini, first.(ranges))) + origin = Point{N,Float32}(min.(mini, first.(ranges))) limit_widths = max.(last.(ranges), maxi) .- origin % = minimum(limit_widths) / 100 # percentage tfontsize = (%) .* tfontsize axisnames_size = (%) .* axisnames_size # index of the direction in which ticks and labels are drawn - offset_indices = Vec(ntuple(i-> ifelse(i != 2, mod1(i + 1, N), 1), N)) + offset_indices = Vec(ntuple(i -> ifelse(i != 2, mod1(i + 1, N), 1), N)) # These need the real limits, not (%), to be scale-aware titlegap = 0.01limit_widths[offset_indices] .* titlegap tgap = 0.01limit_widths[offset_indices] .* tgap for i in 1:N - axis_vec = unit(Point{N, Float32}, i) + axis_vec = unit(Point{N,Float32}, i) width = Float32(limit_widths[i]) stop = origin .+ (width .* axis_vec) if showaxis[i] - append!(linebuffer, [origin, stop], color = axiscolors[i], linewidth = axislinewidth[i]) + append!(linebuffer, [origin, stop], color=axiscolors[i], linewidth=axislinewidth[i]) end if showticks[i] range = ranges[i] j = offset_indices[i] - tickdir = unit(Vec{N, Float32}, j) + tickdir = unit(Vec{N,Float32}, j) offset2 = Float32(limit_widths[j] + tgap[i]) * tickdir for (j, tick) in enumerate(range) labels = ticklabels[i] @@ -276,9 +266,14 @@ function draw_axis3d(textbuffer, linebuffer, scale, limits, ranges_labels, fonts if !isempty(str) startpos = (origin .+ ((Float32(tick - origin[i]) * axis_vec)) .+ offset2) push!( - textbuffer, str, startpos, - color = ttextcolor[i], rotation = trotation[i], - fontsize = tfontsize[i], align = talign[i], font = tfont[i] + textbuffer, + str, + startpos, + color=ttextcolor[i], + rotation=trotation[i], + fontsize=tfontsize[i], + align=talign[i], + font=tfont[i], ) end end @@ -286,45 +281,54 @@ function draw_axis3d(textbuffer, linebuffer, scale, limits, ranges_labels, fonts if !isempty(axisnames[i]) font = to_font(fonts, tfont[i]) tick_widths = maximum(ticklabels[i]) do label - widths(text_bb(label, font, tfontsize[i]))[1] + return widths(text_bb(label, font, tfontsize[i]))[1] end / scale[j] pos = labelposition(ranges, i, tickdir, titlegap[i] + tick_widths, origin) .+ offset2 push!( - textbuffer, to_latex(axisnames[i]), pos, - fontsize = axisnames_size[i], color = axisnames_color[i], - rotation = axisrotation[i], align = axisalign[i], font = axisnames_font[i] + textbuffer, + to_latex(axisnames[i]), + pos, + fontsize=axisnames_size[i], + color=axisnames_color[i], + rotation=axisrotation[i], + align=axisalign[i], + font=axisnames_font[i], ) end end if showgrid[i] c = gridcolors[i] thickness = gridthickness[i] - for _j = (i + 1):(i + N - 1) + for _j in (i + 1):(i + N - 1) j = mod1(_j, N) - dir = unit(Point{N, Float32}, j) + dir = unit(Point{N,Float32}, j) range = ranges[j] for tick in range offset = Float32(tick - origin[j]) * dir - append!( - linebuffer, [origin .+ offset, stop .+ offset], - color = c, linewidth = thickness - ) + append!(linebuffer, [origin .+ offset, stop .+ offset], color=c, linewidth=thickness) end end end - finish!(textbuffer); finish!(linebuffer) + finish!(textbuffer) + finish!(linebuffer) end return end -function plot!(scene::SceneLike, ::Type{<: Axis3D}, attributes::Attributes, args...) +function plot!(scene::SceneLike, ::Type{<:Axis3D}, attributes::Attributes, args...) axis = Axis3D(scene, attributes, args) # Disable any non linear transform for the axis plot! axis.transformation.transform_func[] = identity - textbuffer = TextBuffer(axis, Point3, transparency = true, markerspace = :data, - inspectable = axis.inspectable, visible = axis.visible) - linebuffer = LinesegmentBuffer(axis, Point3, transparency = true, inspectable = axis.inspectable, - visible = axis.visible) + textbuffer = TextBuffer( + axis, + Point3, + transparency=true, + markerspace=:data, + inspectable=axis.inspectable, + visible=axis.visible, + ) + linebuffer = + LinesegmentBuffer(axis, Point3, transparency=true, inspectable=axis.inspectable, visible=axis.visible) tstyle, ticks, frame = to_value.(getindex.(axis, (:names, :ticks, :frame))) titlevals = getindex.(tstyle, (:axisnames, :textcolor, :fontsize, :rotation, :align, :font, :gap)) @@ -332,17 +336,25 @@ function plot!(scene::SceneLike, ::Type{<: Axis3D}, attributes::Attributes, args tvals = getindex.(ticks, (:textcolor, :rotation, :fontsize, :align, :font, :gap)) args = ( getindex.(axis, (:showaxis, :showticks, :showgrid))..., - titlevals..., framevals..., tvals..., axis.padding + titlevals..., + framevals..., + tvals..., + axis.padding, ) map_once( draw_axis3d, - Observable(textbuffer), Observable(linebuffer), scale(scene), - axis[1], axis.ticks.ranges_labels, Observable(axis.fonts), args... + Observable(textbuffer), + Observable(linebuffer), + scale(scene), + axis[1], + axis.ticks.ranges_labels, + Observable(axis.fonts), + args..., ) push!(scene, axis) return axis end -function axis3d!(scene::Scene, lims = data_limits(scene, p -> isaxis(p) || not_in_data_space(p)); kw...) - axis3d!(scene, Attributes(), lims; ticks = (ranges = automatic, labels = automatic), kw...) +function axis3d!(scene::Scene, lims=data_limits(scene, p -> isaxis(p) || not_in_data_space(p)); kw...) + return axis3d!(scene, Attributes(), lims; ticks=(ranges=automatic, labels=automatic), kw...) end diff --git a/src/basic_recipes/band.jl b/src/basic_recipes/band.jl index a14219218f4..5a5321c224c 100644 --- a/src/basic_recipes/band.jl +++ b/src/basic_recipes/band.jl @@ -9,25 +9,24 @@ between the points in `lower` and `upper`. $(ATTRIBUTES) """ @recipe(Band, lowerpoints, upperpoints) do scene - attr = Attributes(; - default_theme(scene, Mesh)..., - colorrange = automatic, - ) + attr = Attributes(; default_theme(scene, Mesh)..., colorrange=automatic) attr[:shading][] = false - attr + return attr end -convert_arguments(::Type{<: Band}, x, ylower, yupper) = (Point2f.(x, ylower), Point2f.(x, yupper)) +convert_arguments(::Type{<:Band}, x, ylower, yupper) = (Point2f.(x, ylower), Point2f.(x, yupper)) function band_connect(n) - ns = 1:n-1 - ns2 = n+1:2n-1 - [GLTriangleFace.(ns, ns .+ 1, ns2); GLTriangleFace.(ns .+ 1, ns2 .+ 1, ns2)] + ns = 1:(n - 1) + ns2 = (n + 1):(2n - 1) + return [GLTriangleFace.(ns, ns .+ 1, ns2); GLTriangleFace.(ns .+ 1, ns2 .+ 1, ns2)] end function Makie.plot!(plot::Band) @extract plot (lowerpoints, upperpoints) - @lift(@assert length($lowerpoints) == length($upperpoints) "length of lower band is not equal to length of upper band!") + @lift( + @assert length($lowerpoints) == length($upperpoints) "length of lower band is not equal to length of upper band!" + ) coordinates = @lift([$lowerpoints; $upperpoints]) connectivity = lift(x -> band_connect(length(x)), plot[1]) @@ -40,7 +39,7 @@ function Makie.plot!(plot::Band) # side to make an even band if length(c) == length(lowerpoints[]) return repeat(to_color(c), 2)::RGBColors - # if there's one color for each band vertex, the colors are used directly + # if there's one color for each band vertex, the colors are used directly elseif length(c) == 2 * length(lowerpoints[]) return to_color(c)::RGBColors else @@ -53,17 +52,13 @@ function Makie.plot!(plot::Band) attr = Attributes(plot) attr[:color] = meshcolor - mesh!(plot, attr, coordinates, connectivity) + return mesh!(plot, attr, coordinates, connectivity) end -function fill_view(x, y1, y2, where::Nothing) - x, y1, y2 -end -function fill_view(x, y1, y2, where::Function) - fill_view(x, y1, y2, where.(x, y1, y2)) -end -function fill_view(x, y1, y2, bools::AbstractVector{<: Union{Integer, Bool}}) - view(x, bools), view(y1, bools), view(y2, bools) +fill_view(x, y1, y2, where::Nothing) = x, y1, y2 +fill_view(x, y1, y2, where::Function) = fill_view(x, y1, y2, where.(x, y1, y2)) +function fill_view(x, y1, y2, bools::AbstractVector{<:Union{Integer,Bool}}) + return view(x, bools), view(y1, bools), view(y2, bools) end """ @@ -71,9 +66,9 @@ end fill the section between 2 lines with the condition `where` """ -function fill_between!(scenelike, x, y1, y2; where = nothing, kw_args...) +function fill_between!(scenelike, x, y1, y2; where=nothing, kw_args...) xv, ylow, yhigh = fill_view(x, y1, y2, where) - band!(scenelike, xv, ylow, yhigh; kw_args...) + return band!(scenelike, xv, ylow, yhigh; kw_args...) end export fill_between! diff --git a/src/basic_recipes/barplot.jl b/src/basic_recipes/barplot.jl index 44517db2eae..79ceb538981 100644 --- a/src/basic_recipes/barplot.jl +++ b/src/basic_recipes/barplot.jl @@ -1,6 +1,4 @@ -function bar_label_formatter(value::Number) - return string(round(value; digits=3)) -end +bar_label_formatter(value::Number) = string(round(value; digits=3)) """ barplot(x, y; kwargs...) @@ -13,51 +11,50 @@ Bar width is determined by the attribute `width`, shrunk by `gap` in the followi $(ATTRIBUTES) """ @recipe(BarPlot, x, y) do scene - Attributes(; - fillto = automatic, - offset = 0.0, - color = theme(scene, :patchcolor), - colormap = theme(scene, :colormap), - colorrange = automatic, - lowclip = automatic, - highclip = automatic, - nan_color = :transparent, - dodge = automatic, - n_dodge = automatic, - gap = 0.2, - dodge_gap = 0.03, - marker = Rect, - stack = automatic, - strokewidth = theme(scene, :patchstrokewidth), - strokecolor = theme(scene, :patchstrokecolor), - width = automatic, - direction = :y, - visible = theme(scene, :visible), - inspectable = theme(scene, :inspectable), - cycle = [:color => :patchcolor], - - bar_labels = nothing, - flip_labels_at = Inf, - label_rotation = 0π, - label_color = theme(scene, :textcolor), - color_over_background = automatic, - color_over_bar = automatic, - label_offset = 5, - label_font = theme(scene, :font), - label_size = 20, - label_formatter = bar_label_formatter, - transparency = false + return Attributes(; + fillto=automatic, + offset=0.0, + color=theme(scene, :patchcolor), + colormap=theme(scene, :colormap), + colorrange=automatic, + lowclip=automatic, + highclip=automatic, + nan_color=:transparent, + dodge=automatic, + n_dodge=automatic, + gap=0.2, + dodge_gap=0.03, + marker=Rect, + stack=automatic, + strokewidth=theme(scene, :patchstrokewidth), + strokecolor=theme(scene, :patchstrokecolor), + width=automatic, + direction=:y, + visible=theme(scene, :visible), + inspectable=theme(scene, :inspectable), + cycle=[:color => :patchcolor], + bar_labels=nothing, + flip_labels_at=Inf, + label_rotation=0π, + label_color=theme(scene, :textcolor), + color_over_background=automatic, + color_over_bar=automatic, + label_offset=5, + label_font=theme(scene, :font), + label_size=20, + label_formatter=bar_label_formatter, + transparency=false, ) end -conversion_trait(::Type{<: BarPlot}) = PointBased() +conversion_trait(::Type{<:BarPlot}) = PointBased() function bar_rectangle(x, y, width, fillto, in_y_direction) # y could be smaller than fillto... ymin = min(fillto, y) ymax = max(fillto, y) w = abs(width) - rect = Rectf(x - (w / 2f0), ymin, w, ymax - ymin) + rect = Rectf(x - (w / 2.0f0), ymin, w, ymax - ymin) return in_y_direction ? rect : flip(rect) end @@ -71,7 +68,11 @@ function compute_x_and_width(x, width, gap, dodge, n_dodge, dodge_gap) elseif eltype(dodge) <: Integer i_dodge = dodge else - ArgumentError("The keyword argument `dodge` currently supports only `AbstractVector{<: Integer}`") |> throw + throw( + ArgumentError( + "The keyword argument `dodge` currently supports only `AbstractVector{<: Integer}`", + ), + ) end n_dodge === automatic && (n_dodge = maximum(i_dodge)) dodge_width = scale_width(dodge_gap, n_dodge) @@ -81,15 +82,13 @@ end scale_width(dodge_gap, n_dodge) = (1 - (n_dodge - 1) * dodge_gap) / n_dodge -function shift_dodge(i, dodge_width, dodge_gap) - (dodge_width - 1) / 2 + (i - 1) * (dodge_width + dodge_gap) -end +shift_dodge(i, dodge_width, dodge_gap) = (dodge_width - 1) / 2 + (i - 1) * (dodge_width + dodge_gap) function stack_from_to_sorted(y) to = cumsum(y) - from = [0.0; to[firstindex(to):end-1]] + from = [0.0; to[firstindex(to):(end - 1)]] - (from = from, to = to) + return (from=from, to=to) end function stack_from_to(i_stack, y) @@ -102,31 +101,35 @@ function stack_from_to(i_stack, y) from, to = stack_from_to_sorted(view(y, perm)) - (from = view(from, inv_perm), to = view(to, inv_perm)) + return (from=view(from, inv_perm), to=view(to, inv_perm)) end function stack_grouped_from_to(i_stack, y, grp) - from = Array{Float64}(undef, length(y)) - to = Array{Float64}(undef, length(y)) + to = Array{Float64}(undef, length(y)) - groupby = StructArray((; grp..., is_pos = y .> 0)) + groupby = StructArray((; grp..., is_pos=y .> 0)) grps = StructArrays.finduniquesorted(groupby) for (grp, inds) in grps - fromto = stack_from_to(i_stack[inds], y[inds]) from[inds] .= fromto.from to[inds] .= fromto.to - end - (from = from, to = to) + return (from=from, to=to) end -function text_attributes(values, in_y_direction, flip_labels_at, color_over_background, color_over_bar, label_offset) +function text_attributes( + values, + in_y_direction, + flip_labels_at, + color_over_background, + color_over_bar, + label_offset, +) aligns = Vec2f[] offsets = Vec2f[] text_colors = RGBAf[] @@ -136,7 +139,7 @@ function text_attributes(values, in_y_direction, flip_labels_at, color_over_back function flip(k) if flip_labels_at isa Number return k > flip_labels_at || k < 0 - elseif flip_labels_at isa Tuple{<:Number, <: Number} + elseif flip_labels_at isa Tuple{<:Number,<:Number} return (k > flip_labels_at[2] || k < 0) && k > flip_labels_at[1] else error("flip_labels_at needs to be a tuple of two numbers (low, high), or a single number (high)") @@ -159,7 +162,17 @@ function text_attributes(values, in_y_direction, flip_labels_at, color_over_back return aligns, offsets, text_colors end -function barplot_labels(xpositions, ypositions, bar_labels, in_y_direction, flip_labels_at, color_over_background, color_over_bar, label_formatter, label_offset) +function barplot_labels( + xpositions, + ypositions, + bar_labels, + in_y_direction, + flip_labels_at, + color_over_background, + color_over_bar, + label_formatter, + label_offset, +) if bar_labels isa Symbol && bar_labels in (:x, :y) bar_labels = map(xpositions, ypositions) do x, y if bar_labels === :x @@ -171,31 +184,56 @@ function barplot_labels(xpositions, ypositions, bar_labels, in_y_direction, flip end if bar_labels isa AbstractVector if length(bar_labels) == length(xpositions) - attributes = text_attributes(ypositions, in_y_direction, flip_labels_at, color_over_background, color_over_bar, label_offset) + attributes = text_attributes( + ypositions, + in_y_direction, + flip_labels_at, + color_over_background, + color_over_bar, + label_offset, + ) label_pos = map(xpositions, ypositions, bar_labels) do x, y, l return (string(l), in_y_direction ? Point2f(x, y) : Point2f(y, x)) end return (label_pos, attributes...) else - error("Labels and bars need to have same length. Found: $(length(xpositions)) bars with these labels: $(bar_labels)") + error( + "Labels and bars need to have same length. Found: $(length(xpositions)) bars with these labels: $(bar_labels)", + ) end else - error("Unsupported label type: $(typeof(bar_labels)). Use: :x, :y, or a vector of values that can be converted to strings.") + error( + "Unsupported label type: $(typeof(bar_labels)). Use: :x, :y, or a vector of values that can be converted to strings.", + ) end end function Makie.plot!(p::BarPlot) - - labels = Observable(Tuple{String, Point2f}[]) + labels = Observable(Tuple{String,Point2f}[]) label_aligns = Observable(Vec2f[]) label_offsets = Observable(Vec2f[]) label_colors = Observable(RGBAf[]) - function calculate_bars(xy, fillto, offset, width, dodge, n_dodge, gap, dodge_gap, stack, - dir, bar_labels, flip_labels_at, label_color, color_over_background, - color_over_bar, label_formatter, label_offset) - + function calculate_bars( + xy, + fillto, + offset, + width, + dodge, + n_dodge, + gap, + dodge_gap, + stack, + dir, + bar_labels, + flip_labels_at, + label_color, + color_over_background, + color_over_bar, + label_formatter, + label_offset, + ) in_y_direction = get((y=true, x=false), dir) do - error("Invalid direction $dir. Options are :x and :y.") + return error("Invalid direction $dir. Options are :x and :y.") end x = first.(xy) @@ -227,10 +265,14 @@ function Makie.plot!(p::BarPlot) end i_stack = stack - from, to = stack_grouped_from_to(i_stack, y, (x = x̂,)) + from, to = stack_grouped_from_to(i_stack, y, (x=x̂,)) y, fillto = to, from else - ArgumentError("The keyword argument `stack` currently supports only `AbstractVector{<: Integer}`") |> throw + throw( + ArgumentError( + "The keyword argument `stack` currently supports only `AbstractVector{<: Integer}`", + ), + ) end # -------------------------------- @@ -240,26 +282,69 @@ function Makie.plot!(p::BarPlot) if !isnothing(bar_labels) oback = color_over_background === automatic ? label_color : color_over_background obar = color_over_bar === automatic ? label_color : color_over_bar - label_args = barplot_labels(x̂, y, bar_labels, in_y_direction, - flip_labels_at, to_color(oback), to_color(obar), - label_formatter, label_offset) + label_args = barplot_labels( + x̂, + y, + bar_labels, + in_y_direction, + flip_labels_at, + to_color(oback), + to_color(obar), + label_formatter, + label_offset, + ) labels[], label_aligns[], label_offsets[], label_colors[] = label_args end return bar_rectangle.(x̂, y .+ offset, barwidth, fillto, in_y_direction) end - bars = lift(calculate_bars, p[1], p.fillto, p.offset, p.width, p.dodge, p.n_dodge, p.gap, - p.dodge_gap, p.stack, p.direction, p.bar_labels, p.flip_labels_at, - p.label_color, p.color_over_background, p.color_over_bar, p.label_formatter, p.label_offset) + bars = lift( + calculate_bars, + p[1], + p.fillto, + p.offset, + p.width, + p.dodge, + p.n_dodge, + p.gap, + p.dodge_gap, + p.stack, + p.direction, + p.bar_labels, + p.flip_labels_at, + p.label_color, + p.color_over_background, + p.color_over_bar, + p.label_formatter, + p.label_offset, + ) poly!( - p, bars, color = p.color, colormap = p.colormap, colorrange = p.colorrange, - strokewidth = p.strokewidth, strokecolor = p.strokecolor, visible = p.visible, - inspectable = p.inspectable, transparency = p.transparency, - highclip = p.highclip, lowclip = p.lowclip, nan_color = p.nan_color, + p, + bars, + color=p.color, + colormap=p.colormap, + colorrange=p.colorrange, + strokewidth=p.strokewidth, + strokecolor=p.strokecolor, + visible=p.visible, + inspectable=p.inspectable, + transparency=p.transparency, + highclip=p.highclip, + lowclip=p.lowclip, + nan_color=p.nan_color, ) if !isnothing(p.bar_labels[]) - text!(p, labels; align=label_aligns, offset=label_offsets, color=label_colors, font=p.label_font, fontsize=p.label_size, rotation=p.label_rotation) + text!( + p, + labels; + align=label_aligns, + offset=label_offsets, + color=label_colors, + font=p.label_font, + fontsize=p.label_size, + rotation=p.label_rotation, + ) end end diff --git a/src/basic_recipes/buffers.jl b/src/basic_recipes/buffers.jl index 823ddbcae32..2e7efdcf89d 100644 --- a/src/basic_recipes/buffers.jl +++ b/src/basic_recipes/buffers.jl @@ -4,17 +4,21 @@ efficiently append + push new values to them =# function LinesegmentBuffer( - scene::SceneLike, ::Type{Point{N}} = Point{2}; - color = RGBAf[], linewidth = Float32[], - kw_args... - ) where N - linesegments!( - scene, Point{N, Float32}[]; color = color, - linewidth = linewidth, kw_args... - ) + scene::SceneLike, + ::Type{Point{N}}=Point{2}; + color=RGBAf[], + linewidth=Float32[], + kw_args..., +) where {N} + return linesegments!(scene, Point{N,Float32}[]; color=color, linewidth=linewidth, kw_args...) end -function append!(lsb::LineSegments, positions::Vector{Point{N, Float32}}; color = :black, linewidth = 1.0) where N +function append!( + lsb::LineSegments, + positions::Vector{Point{N,Float32}}; + color=:black, + linewidth=1.0, +) where {N} thickv = same_length_array(positions, linewidth, key"linewidth"()) colorv = same_length_array(positions, color, key"color"()) append!(lsb[1][], positions) @@ -23,8 +27,8 @@ function append!(lsb::LineSegments, positions::Vector{Point{N, Float32}}; color return end -function push!(tb::LineSegments, positions::Point{N, Float32}; kw_args...) where N - append!(tb, [positions]; kw_args...) +function push!(tb::LineSegments, positions::Point{N,Float32}; kw_args...) where {N} + return append!(tb, [positions]; kw_args...) end function start!(lsb::LineSegments) @@ -43,22 +47,25 @@ function finish!(lsb::LineSegments) end function TextBuffer( - scene::SceneLike, ::Type{Point{N}} = Point{2}; - rotation = [Quaternionf(0,0,0,1)], - color = RGBAf[RGBAf(0,0,0,0)], - fontsize = Float32[0], - font = [defaultfont()], - align = [Vec2f(0)], - kw_args... - ) where N - annotations!( - scene, String[" "], [Point{N, Float32}(0)]; - rotation = rotation, - color = color, - fontsize = fontsize, - font = font, - align = align, - kw_args... + scene::SceneLike, + ::Type{Point{N}}=Point{2}; + rotation=[Quaternionf(0, 0, 0, 1)], + color=RGBAf[RGBAf(0, 0, 0, 0)], + fontsize=Float32[0], + font=[defaultfont()], + align=[Vec2f(0)], + kw_args..., +) where {N} + return annotations!( + scene, + String[" "], + [Point{N,Float32}(0)]; + rotation=rotation, + color=color, + fontsize=fontsize, + font=font, + align=align, + kw_args..., ) end @@ -81,18 +88,26 @@ function finish!(tb::Annotations) return end - -function push!(tb::Annotations, text::String, position::VecTypes{N}; kw_args...) where N - append!(tb, [(String(text), Point{N, Float32}(position))]; kw_args...) +function push!(tb::Annotations, text::String, position::VecTypes{N}; kw_args...) where {N} + return append!(tb, [(String(text), Point{N,Float32}(position))]; kw_args...) end -function append!(tb::Annotations, text::Vector{String}, positions::Vector{Point{N, Float32}}; kw_args...) where N +function append!( + tb::Annotations, + text::Vector{String}, + positions::Vector{Point{N,Float32}}; + kw_args..., +) where {N} text_positions = convert_argument(Annotations, text, positions)[1] append!(tb, text_positions; kw_args...) return end -function append!(tb::Annotations, text_positions::Vector{Tuple{String, Point{N, Float32}}}; kw_args...) where N +function append!( + tb::Annotations, + text_positions::Vector{Tuple{String,Point{N,Float32}}}; + kw_args..., +) where {N} append!(tb[1][], text_positions) kw = Dict(kw_args) for key in (:color, :rotation, :fontsize, :font, :align) diff --git a/src/basic_recipes/contourf.jl b/src/basic_recipes/contourf.jl index 2d8699d64a8..404684e6078 100644 --- a/src/basic_recipes/contourf.jl +++ b/src/basic_recipes/contourf.jl @@ -28,16 +28,16 @@ You can use `tightlimits!(ax)` to tighten the limits similar to the `Int` behavi $(ATTRIBUTES) """ @recipe(Contourf) do scene - Theme( - levels = 10, - mode = :normal, - colormap = theme(scene, :colormap), - extendlow = nothing, - extendhigh = nothing, + return Theme( + levels=10, + mode=:normal, + colormap=theme(scene, :colormap), + extendlow=nothing, + extendhigh=nothing, # TODO, Isoband doesn't seem to support nans? - nan_color = :transparent, - inspectable = theme(scene, :inspectable), - transparency = false + nan_color=:transparent, + inspectable=theme(scene, :inspectable), + transparency=false, ) end @@ -47,40 +47,37 @@ end # _computed_extendlow # _computed_extendhigh -function _get_isoband_levels(levels::Int, mi, ma) - edges = Float32.(LinRange(mi, ma, levels+1)) -end +_get_isoband_levels(levels::Int, mi, ma) = edges = Float32.(LinRange(mi, ma, levels + 1)) function _get_isoband_levels(levels::AbstractVector{<:Real}, mi, ma) edges = Float32.(levels) @assert issorted(edges) - edges + return edges end conversion_trait(::Type{<:Contourf}) = ContinuousSurface() -function _get_isoband_levels(::Val{:normal}, levels, values) - _get_isoband_levels(levels, extrema_nan(values)...) -end +_get_isoband_levels(::Val{:normal}, levels, values) = _get_isoband_levels(levels, extrema_nan(values)...) function _get_isoband_levels(::Val{:relative}, levels::AbstractVector, values) mi, ma = extrema_nan(values) - Float32.(levels .* (ma - mi) .+ mi) + return Float32.(levels .* (ma - mi) .+ mi) end - -function Makie.plot!(c::Contourf{<:Tuple{<:AbstractVector{<:Real}, <:AbstractVector{<:Real}, <:AbstractMatrix{<:Real}}}) +function Makie.plot!( + c::Contourf{<:Tuple{<:AbstractVector{<:Real},<:AbstractVector{<:Real},<:AbstractMatrix{<:Real}}}, +) xs, ys, zs = c[1:3] c.attributes[:_computed_levels] = lift(zs, c.levels, c.mode) do zs, levels, mode - _get_isoband_levels(Val(mode), levels, vec(zs)) + return _get_isoband_levels(Val(mode), levels, vec(zs)) end colorrange = lift(c._computed_levels) do levels - minimum(levels), maximum(levels) + return minimum(levels), maximum(levels) end - computed_colormap = lift(compute_contourf_colormap, c._computed_levels, c.colormap, c.extendlow, - c.extendhigh) + computed_colormap = + lift(compute_contourf_colormap, c._computed_levels, c.colormap, c.extendlow, c.extendhigh) c.attributes[:_computed_colormap] = computed_colormap lowcolor = Observable{RGBAf}() @@ -106,7 +103,7 @@ function Makie.plot!(c::Contourf{<:Tuple{<:AbstractVector{<:Real}, <:AbstractVec @assert issorted(levels) is_extended_low && pushfirst!(levels, -Inf) is_extended_high && push!(levels, Inf) - lows = levels[1:end-1] + lows = levels[1:(end - 1)] highs = levels[2:end] # zs needs to be transposed to match rest of makie @@ -134,19 +131,20 @@ function Makie.plot!(c::Contourf{<:Tuple{<:AbstractVector{<:Real}, <:AbstractVec # it on a first run! calculate_polys(xs[], ys[], zs[], c._computed_levels[], is_extended_low[], is_extended_high[]) - poly!(c, + return poly!( + c, polys, - colormap = c._computed_colormap, - colorrange = colorrange, - highclip = highcolor, - lowclip = lowcolor, - nan_color = c.nan_color, - color = colors, - strokewidth = 0, - strokecolor = :transparent, - shading = false, - inspectable = c.inspectable, - transparency = c.transparency + colormap=c._computed_colormap, + colorrange=colorrange, + highclip=highcolor, + lowclip=lowcolor, + nan_color=c.nan_color, + color=colors, + strokewidth=0, + strokecolor=:transparent, + shading=false, + inspectable=c.inspectable, + transparency=c.transparency, ) end @@ -160,7 +158,6 @@ inner polygons which are holes in the outer polygon. It is possible that one group has multiple outer polygons with multiple holes each. """ function _group_polys(points, ids) - polys = [points[ids .== i] for i in unique(ids)] npolys = length(polys) @@ -171,9 +168,9 @@ function _group_polys(points, ids) # intersecting or overlapping polys, it should be enough to # check if a single point is contained, saving some computation time containment_matrix = [ - p1 != p2 && - PolygonOps.inpolygon(first(p1), p2) == 1 - for p1 in polys_lastdouble, p2 in polys_lastdouble] + p1 != p2 && PolygonOps.inpolygon(first(p1), p2) == 1 for p1 in polys_lastdouble, + p2 in polys_lastdouble + ] unclassified_polyindices = collect(1:size(containment_matrix, 1)) # @show unclassified_polyindices @@ -183,7 +180,7 @@ function _group_polys(points, ids) groups = Vector{Vector{Point2f}}[] # a dict that maps index in `polys` to index in `groups` for outer polys - outerindex_groupdict = Dict{Int, Int}() + outerindex_groupdict = Dict{Int,Int}() # all polys have to be classified while !isempty(unclassified_polyindices) @@ -222,5 +219,5 @@ function _group_polys(points, ids) unclassified_polyindices = unclassified_polyindices[to_keep] containment_matrix = containment_matrix[to_keep, to_keep] end - groups + return groups end diff --git a/src/basic_recipes/contours.jl b/src/basic_recipes/contours.jl index 5094b86eaf7..931bccd0d41 100644 --- a/src/basic_recipes/contours.jl +++ b/src/basic_recipes/contours.jl @@ -18,17 +18,17 @@ $(ATTRIBUTES) @recipe(Contour) do scene default = default_theme(scene) # pop!(default, :color) - Attributes(; + return Attributes(; default..., - color = nothing, - colormap = theme(scene, :colormap), - colorrange = Makie.automatic, - levels = 5, - linewidth = 1.0, - linestyle = nothing, - alpha = 1.0, - enable_depth = true, - transparency = false + color=nothing, + colormap=theme(scene, :colormap), + colorrange=Makie.automatic, + levels=5, + linewidth=1.0, + linestyle=nothing, + alpha=1.0, + enable_depth=true, + transparency=false, ) end @@ -42,10 +42,10 @@ with z-elevation for each level. $(ATTRIBUTES) """ @recipe(Contour3d) do scene - default_theme(scene, Contour) + return default_theme(scene, Contour) end -function contourlines(::Type{<: Contour}, contours, cols) +function contourlines(::Type{<:Contour}, contours, cols) result = Point2f[] colors = RGBA{Float32}[] for (color, c) in zip(cols, Contours.levels(contours)) @@ -55,10 +55,10 @@ function contourlines(::Type{<: Contour}, contours, cols) append!(colors, fill(color, length(elem.vertices) + 1)) end end - result, colors + return result, colors end -function contourlines(::Type{<: Contour3d}, contours, cols) +function contourlines(::Type{<:Contour3d}, contours, cols) result = Point3f[] colors = RGBA{Float32}[] for (color, c) in zip(cols, Contours.levels(contours)) @@ -70,28 +70,28 @@ function contourlines(::Type{<: Contour3d}, contours, cols) append!(colors, fill(color, length(elem.vertices) + 1)) end end - result, colors + return result, colors end -to_levels(x::AbstractVector{<: Number}, cnorm) = x +to_levels(x::AbstractVector{<:Number}, cnorm) = x function to_levels(n::Integer, cnorm) zmin, zmax = cnorm dz = (zmax - zmin) / (n + 1) - range(zmin + dz; step = dz, length = n) + return range(zmin + dz; step=dz, length=n) end -conversion_trait(::Type{<: Contour3d}) = ContinuousSurface() -conversion_trait(::Type{<: Contour}) = ContinuousSurface() -conversion_trait(::Type{<: Contour{<: Tuple{X, Y, Z, Vol}}}) where {X, Y, Z, Vol} = VolumeLike() -conversion_trait(::Type{<: Contour{<: Tuple{<: AbstractArray{T, 3}}}}) where T = VolumeLike() +conversion_trait(::Type{<:Contour3d}) = ContinuousSurface() +conversion_trait(::Type{<:Contour}) = ContinuousSurface() +conversion_trait(::Type{<:Contour{<:Tuple{X,Y,Z,Vol}}}) where {X,Y,Z,Vol} = VolumeLike() +conversion_trait(::Type{<:Contour{<:Tuple{<:AbstractArray{T,3}}}}) where {T} = VolumeLike() -function plot!(plot::Contour{<: Tuple{X, Y, Z, Vol}}) where {X, Y, Z, Vol} +function plot!(plot::Contour{<:Tuple{X,Y,Z,Vol}}) where {X,Y,Z,Vol} x, y, z, volume = plot[1:4] @extract plot (colormap, levels, linewidth, alpha) valuerange = lift(nan_extrema, volume) cliprange = replace_automatic!(plot, :colorrange) do - valuerange + return valuerange end cmap = lift(colormap, levels, alpha, cliprange, valuerange) do _cmap, l, alpha, cliprange, vrange levels = to_levels(l, vrange) @@ -107,12 +107,12 @@ function plot!(plot::Contour{<: Tuple{X, Y, Z, Vol}}) where {X, Y, Z, Vol} v_interval = cliprange[1] .. cliprange[2] # resample colormap and make the empty area between iso surfaces transparent return map(1:N) do i - i01 = (i-1) / (N - 1) + i01 = (i - 1) / (N - 1) c = Makie.interpolated_getindex(cmap, i01) isoval = vrange[1] + (i01 * (vrange[2] - vrange[1])) - line = reduce(levels, init = false) do v0, level + line = reduce(levels, init=false) do v0, level (isoval in v_interval) || return false - v0 || (abs(level - isoval) <= iso_eps) + return v0 || (abs(level - isoval) <= iso_eps) end return RGBAf(Colors.color(c), line ? alpha : 0.0) end @@ -123,22 +123,20 @@ function plot!(plot::Contour{<: Tuple{X, Y, Z, Vol}}) where {X, Y, Z, Vol} attr[:colormap] = cmap attr[:algorithm] = 7 pop!(attr, :levels) - volume!(plot, attr, x, y, z, volume) + return volume!(plot, attr, x, y, z, volume) end function color_per_level(color, colormap, colorrange, alpha, levels) - color_per_level(to_color(color), colormap, colorrange, alpha, levels) + return color_per_level(to_color(color), colormap, colorrange, alpha, levels) end -function color_per_level(color::Colorant, colormap, colorrange, alpha, levels) - fill(color, length(levels)) -end +color_per_level(color::Colorant, colormap, colorrange, alpha, levels) = fill(color, length(levels)) function color_per_level(colors::AbstractVector, colormap, colorrange, alpha, levels) - color_per_level(to_colormap(colors), colormap, colorrange, alpha, levels) + return color_per_level(to_colormap(colors), colormap, colorrange, alpha, levels) end -function color_per_level(colors::AbstractVector{<: Colorant}, colormap, colorrange, alpha, levels) +function color_per_level(colors::AbstractVector{<:Colorant}, colormap, colorrange, alpha, levels) if length(levels) == length(colors) return colors else @@ -153,48 +151,51 @@ function color_per_level(::Nothing, colormap, colorrange, a, levels) cmap = to_colormap(colormap) map(levels) do level c = interpolated_getindex(cmap, level, colorrange) - RGBAf(color(c), alpha(c) * a) + return RGBAf(color(c), alpha(c) * a) end end -function plot!(plot::T) where T <: Union{Contour, Contour3d} +function plot!(plot::T) where {T<:Union{Contour,Contour3d}} x, y, z = plot[1:3] zrange = lift(nan_extrema, z) levels = lift(plot.levels, zrange) do levels, zrange - if levels isa AbstractVector{<: Number} + if levels isa AbstractVector{<:Number} return levels elseif levels isa Integer to_levels(levels, zrange) else - error("Level needs to be Vector of iso values, or a single integer to for a number of automatic levels") + error( + "Level needs to be Vector of iso values, or a single integer to for a number of automatic levels", + ) end end - replace_automatic!(()-> zrange, plot, :colorrange) + replace_automatic!(() -> zrange, plot, :colorrange) args = @extract plot (color, colormap, colorrange, alpha) level_colors = lift(color_per_level, args..., levels) result = lift(x, y, z, levels, level_colors) do x, y, z, levels, level_colors t = eltype(z) # Compute contours - xv, yv = to_vector(x, size(z,1), t), to_vector(y, size(z,2), t) - contours = Contours.contours(xv, yv, z, convert(Vector{eltype(z)}, levels)) - contourlines(T, contours, level_colors) + xv, yv = to_vector(x, size(z, 1), t), to_vector(y, size(z, 2), t) + contours = Contours.contours(xv, yv, z, convert(Vector{eltype(z)}, levels)) + return contourlines(T, contours, level_colors) end lines!( - plot, lift(first, result); - color = lift(last, result), - linewidth = plot.linewidth, - inspectable = plot.inspectable, - transparency = plot.transparency, - linestyle = plot.linestyle + plot, + lift(first, result); + color=lift(last, result), + linewidth=plot.linewidth, + inspectable=plot.inspectable, + transparency=plot.transparency, + linestyle=plot.linestyle, ) - plot + return plot end -function point_iterator(x::Contour{<: Tuple{X, Y, Z}}) where {X, Y, Z} +function point_iterator(x::Contour{<:Tuple{X,Y,Z}}) where {X,Y,Z} axes = (x[1], x[2]) - extremata = map(extrema∘to_value, axes) + extremata = map(extrema ∘ to_value, axes) minpoint = Point2f(first.(extremata)...) widths = last.(extremata) .- first.(extremata) rect = Rect2f(minpoint, Vec2f(widths)) diff --git a/src/basic_recipes/convenience_functions.jl b/src/basic_recipes/convenience_functions.jl index b9086b27cbd..a467b2f564e 100644 --- a/src/basic_recipes/convenience_functions.jl +++ b/src/basic_recipes/convenience_functions.jl @@ -1,9 +1,8 @@ -function Makie.plot!(plot::Plot(AbstractVector{<: Complex})) +function Makie.plot!(plot::Plot(AbstractVector{<:Complex})) plot[:axis, :labels] = ("Re(x)", "Im(x)") - lines!(plot, lift(im-> Point2f.(real.(im), imag.(im)), x[1])) + return lines!(plot, lift(im -> Point2f.(real.(im), imag.(im)), x[1])) end - """ showlibrary(lib::Symbol)::Scene @@ -12,16 +11,13 @@ Returns a Scene with these colour gradients arranged as horizontal colourbars. """ function showlibrary(lib::Symbol)::Scene - cgrads = sort(PlotUtils.cgradients(lib)) PlotUtils.clibrary(lib) - showgradients(cgrads) - + return showgradients(cgrads) end - """ showgradients( cgrads::AbstractVector{Symbol}; @@ -33,41 +29,33 @@ Plots the given colour gradients arranged as horizontal colourbars. If you change the offsets or the font size, you may need to change the resolution. """ function showgradients( - cgrads::AbstractVector{Symbol}; - h = 0.0, - offset = 0.4, - fontsize = 0.7, - resolution = (800, length(cgrads) * 84), - monospace = true - )::Scene - - scene = Scene(resolution = resolution) + cgrads::AbstractVector{Symbol}; + h=0.0, + offset=0.4, + fontsize=0.7, + resolution=(800, length(cgrads) * 84), + monospace=true, +)::Scene + scene = Scene(resolution=resolution) map(collect(cgrads)) do cmap c = to_colormap(cmap) cbar = image!( scene, - range(0, stop = 10, length = length(c)), - range(0, stop = 1, length = length(c)), - reshape(c, (length(c),1)) + range(0, stop=10, length=length(c)), + range(0, stop=1, length=length(c)), + reshape(c, (length(c), 1)), )[end] cmapstr = monospace ? UnicodeFun.to_latex("\\mono{$cmap}") : string(cmap, ":") - text!( - scene, - cmapstr, - position = Point2f(-0.1, 0.5 + h), - align = (:right, :center), - fontsize = fontsize - ) + text!(scene, cmapstr, position=Point2f(-0.1, 0.5 + h), align=(:right, :center), fontsize=fontsize) translate!(cbar, 0, h, 0) - h -= (1 + offset) + return h -= (1 + offset) end - scene - + return scene end diff --git a/src/basic_recipes/error_and_rangebars.jl b/src/basic_recipes/error_and_rangebars.jl index 69a35f65e4a..0a7ae005e13 100644 --- a/src/basic_recipes/error_and_rangebars.jl +++ b/src/basic_recipes/error_and_rangebars.jl @@ -18,20 +18,19 @@ If you want to plot intervals from low to high values instead of relative errors $(ATTRIBUTES) """ @recipe(Errorbars) do scene - Theme( - whiskerwidth = 0, - color = theme(scene, :linecolor), - linewidth = theme(scene, :linewidth), - direction = :y, - visible = theme(scene, :visible), - colormap = theme(scene, :colormap), - colorrange = automatic, - inspectable = theme(scene, :inspectable), - transparency = false + return Theme( + whiskerwidth=0, + color=theme(scene, :linecolor), + linewidth=theme(scene, :linewidth), + direction=:y, + visible=theme(scene, :visible), + colormap=theme(scene, :colormap), + colorrange=automatic, + inspectable=theme(scene, :inspectable), + transparency=false, ) end - """ rangebars(val, low, high; kwargs...) rangebars(val, low_high; kwargs...) @@ -46,16 +45,16 @@ If you want to plot errors relative to a reference value, use `errorbars`. $(ATTRIBUTES) """ @recipe(Rangebars) do scene - Theme( - whiskerwidth = 0, - color = theme(scene, :linecolor), - linewidth = theme(scene, :linewidth), - direction = :y, - visible = theme(scene, :visible), - colormap = theme(scene, :colormap), - colorrange = automatic, - inspectable = theme(scene, :inspectable), - transparency = false + return Theme( + whiskerwidth=0, + color=theme(scene, :linecolor), + linewidth=theme(scene, :linewidth), + direction=:y, + visible=theme(scene, :visible), + colormap=theme(scene, :colormap), + colorrange=automatic, + inspectable=theme(scene, :inspectable), + transparency=false, ) end @@ -63,71 +62,78 @@ end function Makie.convert_arguments(::Type{<:Errorbars}, x, y, error_both) xyerr = broadcast(x, y, error_both) do x, y, e - Vec4f(x, y, e, e) + return Vec4f(x, y, e, e) end - (xyerr,) + return (xyerr,) end function Makie.convert_arguments(::Type{<:Errorbars}, x, y, error_low, error_high) xyerr = broadcast(Vec4f, x, y, error_low, error_high) - (xyerr,) + return (xyerr,) end - function Makie.convert_arguments(::Type{<:Errorbars}, x, y, error_low_high::AbstractVector{<:VecTypes{2}}) xyerr = broadcast(x, y, error_low_high) do x, y, (el, eh) - Vec4f(x, y, el, eh) + return Vec4f(x, y, el, eh) end - (xyerr,) + return (xyerr,) end function Makie.convert_arguments(::Type{<:Errorbars}, xy::AbstractVector{<:VecTypes{2}}, error_both) xyerr = broadcast(xy, error_both) do (x, y), e - Vec4f(x, y, e, e) + return Vec4f(x, y, e, e) end - (xyerr,) + return (xyerr,) end -function Makie.convert_arguments(::Type{<:Errorbars}, xy::AbstractVector{<:VecTypes{2}}, error_low, error_high) +function Makie.convert_arguments( + ::Type{<:Errorbars}, + xy::AbstractVector{<:VecTypes{2}}, + error_low, + error_high, +) xyerr = broadcast(xy, error_low, error_high) do (x, y), el, eh - Vec4f(x, y, el, eh) + return Vec4f(x, y, el, eh) end - (xyerr,) + return (xyerr,) end -function Makie.convert_arguments(::Type{<:Errorbars}, xy::AbstractVector{<:VecTypes{2}}, error_low_high::AbstractVector{<:VecTypes{2}}) +function Makie.convert_arguments( + ::Type{<:Errorbars}, + xy::AbstractVector{<:VecTypes{2}}, + error_low_high::AbstractVector{<:VecTypes{2}}, +) xyerr = broadcast(xy, error_low_high) do (x, y), (el, eh) - Vec4f(x, y, el, eh) + return Vec4f(x, y, el, eh) end - (xyerr,) + return (xyerr,) end function Makie.convert_arguments(::Type{<:Errorbars}, xy_error_both::AbstractVector{<:VecTypes{3}}) xyerr = broadcast(xy_error_both) do (x, y, e) - Vec4f(x, y, e, e) + return Vec4f(x, y, e, e) end - (xyerr,) + return (xyerr,) end ### conversions for rangebars function Makie.convert_arguments(::Type{<:Rangebars}, val, low, high) val_low_high = broadcast(Vec3f, val, low, high) - (val_low_high,) + return (val_low_high,) end function Makie.convert_arguments(::Type{<:Rangebars}, val, low_high) val_low_high = broadcast(val, low_high) do val, (low, high) - Vec3f(val, low, high) + return Vec3f(val, low, high) end - (val_low_high,) + return (val_low_high,) end ### the two plotting functions create linesegpairs in two different ways ### and then hit the same underlying implementation in `_plot_bars!` -function Makie.plot!(plot::Errorbars{T}) where T <: Tuple{AbstractVector{<:VecTypes{4}}} - +function Makie.plot!(plot::Errorbars{T}) where {T<:Tuple{AbstractVector{<:VecTypes{4}}}} x_y_low_high = plot[1] is_in_y_direction = lift(plot.direction) do dir @@ -141,20 +147,15 @@ function Makie.plot!(plot::Errorbars{T}) where T <: Tuple{AbstractVector{<:VecTy end linesegpairs = lift(x_y_low_high, is_in_y_direction) do x_y_low_high, in_y - map(x_y_low_high) do (x, y, l, h) - in_y ? - (Point2f(x, y - l), Point2f(x, y + h)) : - (Point2f(x - l, y), Point2f(x + h, y)) + return in_y ? (Point2f(x, y - l), Point2f(x, y + h)) : (Point2f(x - l, y), Point2f(x + h, y)) end end - _plot_bars!(plot, linesegpairs, is_in_y_direction) + return _plot_bars!(plot, linesegpairs, is_in_y_direction) end - -function Makie.plot!(plot::Rangebars{T}) where T <: Tuple{AbstractVector{<:VecTypes{3}}} - +function Makie.plot!(plot::Rangebars{T}) where {T<:Tuple{AbstractVector{<:VecTypes{3}}}} val_low_high = plot[1] is_in_y_direction = lift(plot.direction) do dir @@ -168,104 +169,112 @@ function Makie.plot!(plot::Rangebars{T}) where T <: Tuple{AbstractVector{<:VecTy end linesegpairs = lift(val_low_high, is_in_y_direction) do vlh, in_y - map(vlh) do (v, l, h) - in_y ? - (Point2f(v, l), Point2f(v, h)) : - (Point2f(l, v), Point2f(h, v)) + return in_y ? (Point2f(v, l), Point2f(v, h)) : (Point2f(l, v), Point2f(h, v)) end end - _plot_bars!(plot, linesegpairs, is_in_y_direction) + return _plot_bars!(plot, linesegpairs, is_in_y_direction) end - - function _plot_bars!(plot, linesegpairs, is_in_y_direction) - f_if(condition, f, arg) = condition ? f(arg) : arg @extract plot (whiskerwidth, color, linewidth, visible, colormap, colorrange, inspectable, transparency) scene = parent_scene(plot) - whiskers = lift(linesegpairs, scene.camera.projectionview, - scene.camera.pixel_space, whiskerwidth) do pairs, _, _, whiskerwidth - + whiskers = lift( + linesegpairs, + scene.camera.projectionview, + scene.camera.pixel_space, + whiskerwidth, + ) do pairs, _, _, whiskerwidth endpoints = [p for pair in pairs for p in pair] screenendpoints = scene_to_screen(endpoints, scene) screenendpoints_shifted_pairs = map(screenendpoints) do sep - (sep .+ f_if(is_in_y_direction[], reverse, Point(0, -whiskerwidth/2)), - sep .+ f_if(is_in_y_direction[], reverse, Point(0, whiskerwidth/2))) + return ( + sep .+ f_if(is_in_y_direction[], reverse, Point(0, -whiskerwidth / 2)), + sep .+ f_if(is_in_y_direction[], reverse, Point(0, whiskerwidth / 2)), + ) end - screen_to_scene([p for pair in screenendpoints_shifted_pairs for p in pair], scene) + return screen_to_scene([p for pair in screenendpoints_shifted_pairs for p in pair], scene) end whiskercolors = Observable{RGBColors}() map!(whiskercolors, color) do color # we have twice as many linesegments for whiskers as we have errorbars, so we # need to duplicate colors if a vector of colors is given if color isa AbstractVector - return repeat(to_color(color), inner = 2)::RGBColors + return repeat(to_color(color), inner=2)::RGBColors else return to_color(color)::RGBAf end end - whiskerlinewidths = Observable{Union{Float32, Vector{Float32}}}() + whiskerlinewidths = Observable{Union{Float32,Vector{Float32}}}() map!(whiskerlinewidths, linewidth) do linewidth # same for linewidth if linewidth isa AbstractVector - return repeat(convert(Vector{Float32}, linewidth), inner = 2)::Vector{Float32} + return repeat(convert(Vector{Float32}, linewidth), inner=2)::Vector{Float32} else return convert(Float32, linewidth) end end linesegments!( - plot, linesegpairs, color = color, linewidth = linewidth, visible = visible, - colormap = colormap, colorrange = colorrange, inspectable = inspectable, - transparency = transparency + plot, + linesegpairs, + color=color, + linewidth=linewidth, + visible=visible, + colormap=colormap, + colorrange=colorrange, + inspectable=inspectable, + transparency=transparency, ) linesegments!( - plot, whiskers, color = whiskercolors, linewidth = whiskerlinewidths, - visible = visible, colormap = colormap, colorrange = colorrange, - inspectable = inspectable, transparency = transparency + plot, + whiskers, + color=whiskercolors, + linewidth=whiskerlinewidths, + visible=visible, + colormap=colormap, + colorrange=colorrange, + inspectable=inspectable, + transparency=transparency, ) - plot + return plot end function scene_to_screen(pts, scene) p4 = to_ndim.(Vec4f, to_ndim.(Vec3f, pts, 0.0), 1.0) p1m1 = Ref(scene.camera.projectionview[]) .* p4 projected = Ref(inv(scene.camera.pixel_space[])) .* p1m1 - [Point2.(p[Vec(1, 2)]...) for p in projected] + return [Point2.(p[Vec(1, 2)]...) for p in projected] end function screen_to_scene(pts, scene) p4 = to_ndim.(Vec4f, to_ndim.(Vec3f, pts, 0.0), 1.0) p1m1 = Ref(scene.camera.pixel_space[]) .* p4 projected = Ref(inv(scene.camera.projectionview[])) .* p1m1 - [Point2.(p[Vec(1, 2)]...) for p in projected] + return [Point2.(p[Vec(1, 2)]...) for p in projected] end -function scene_to_screen(p::T, scene) where T <: Point +function scene_to_screen(p::T, scene) where {T<:Point} p4 = to_ndim(Vec4f, to_ndim(Vec3f, p, 0.0), 1.0) p1m1 = scene.camera.projectionview[] * p4 projected = inv(scene.camera.pixel_space[]) * p1m1 - T(projected[Vec(1, 2)]...) + return T(projected[Vec(1, 2)]...) end -function screen_to_scene(p::T, scene) where T <: Point +function screen_to_scene(p::T, scene) where {T<:Point} p4 = to_ndim(Vec4f, to_ndim(Vec3f, p, 0.0), 1.0) p1m1 = scene.camera.pixel_space[] * p4 projected = inv(scene.camera.projectionview[]) * p1m1 - T(projected[Vec(1, 2)]...) + return T(projected[Vec(1, 2)]...) end - # ignore whiskers when determining data limits -function data_limits(bars::Union{Errorbars, Rangebars}) - data_limits(bars.plots[1]) -end +data_limits(bars::Union{Errorbars,Rangebars}) = data_limits(bars.plots[1]) diff --git a/src/basic_recipes/hvlines.jl b/src/basic_recipes/hvlines.jl index 7df939bfedb..5135ca80e3f 100644 --- a/src/basic_recipes/hvlines.jl +++ b/src/basic_recipes/hvlines.jl @@ -9,13 +9,7 @@ they are broadcast to calculate the final line segments. All style attributes are the same as for `LineSegments`. """ @recipe(HLines) do scene - Theme(; - xautolimits = false, - xmin = 0, - xmax = 1, - default_theme(scene, LineSegments)..., - cycle = :color, - ) + return Theme(; xautolimits=false, xmin=0, xmax=1, default_theme(scene, LineSegments)..., cycle=:color) end """ @@ -29,13 +23,7 @@ they are broadcast to calculate the final line segments. All style attributes are the same as for `LineSegments`. """ @recipe(VLines) do scene - Theme(; - yautolimits = false, - ymin = 0, - ymax = 1, - default_theme(scene, LineSegments)..., - cycle = :color, - ) + return Theme(; yautolimits=false, ymin=0, ymax=1, default_theme(scene, LineSegments)..., cycle=:color) end function projview_to_2d_limits(pv) @@ -45,7 +33,7 @@ function projview_to_2d_limits(pv) return Rect2f(origin, Vec2f(xmax, ymax) - origin) end -function Makie.plot!(p::Union{HLines, VLines}) +function Makie.plot!(p::Union{HLines,VLines}) scene = parent_scene(p) transf = transform_func_obs(scene) @@ -78,22 +66,16 @@ function Makie.plot!(p::Union{HLines, VLines}) push!(points[], Point2f(val, y_ma)) end end - notify(points) + return notify(points) end notify(p[1]) - line_attributes = extract_keys(p.attributes, [ - :linewidth, - :color, - :colormap, - :colorrange, - :linestyle, - :fxaa, - :cycle, - :transparency, - :inspectable]) + line_attributes = extract_keys( + p.attributes, + [:linewidth, :color, :colormap, :colorrange, :linestyle, :fxaa, :cycle, :transparency, :inspectable], + ) linesegments!(p, line_attributes, points) - p + return p end diff --git a/src/basic_recipes/hvspan.jl b/src/basic_recipes/hvspan.jl index 18ac06bdae4..7aa4944e339 100644 --- a/src/basic_recipes/hvspan.jl +++ b/src/basic_recipes/hvspan.jl @@ -9,14 +9,14 @@ they are broadcast to calculate the final spans. All style attributes are the same as for `Poly`. """ @recipe(HSpan) do scene - Theme(; - xautolimits = false, - xmin = 0, - xmax = 1, + return Theme(; + xautolimits=false, + xmin=0, + xmax=1, default_theme(Poly, scene)..., - cycle = [:color => :patchcolor], + cycle=[:color => :patchcolor], ) - end +end """ vspan(xs_low, xs_high; ymin = 0.0, ymax = 1.0, attrs...) @@ -29,16 +29,16 @@ they are broadcast to calculate the final spans. All style attributes are the same as for `Poly`. """ @recipe(VSpan) do scene - Theme(; - yautolimits = false, - ymin = 0, - ymax = 1, + return Theme(; + yautolimits=false, + ymin=0, + ymax=1, default_theme(Poly, scene)..., - cycle = [:color => :patchcolor], + cycle=[:color => :patchcolor], ) end -function Makie.plot!(p::Union{HSpan, VSpan}) +function Makie.plot!(p::Union{HSpan,VSpan}) scene = Makie.parent_scene(p) transf = transform_func_obs(scene) @@ -48,7 +48,7 @@ function Makie.plot!(p::Union{HSpan, VSpan}) mi = p isa HSpan ? p.xmin : p.ymin ma = p isa HSpan ? p.xmax : p.ymax - + onany(limits, p[1], p[2], mi, ma, transf) do lims, lows, highs, mi, ma, transf inv = inverse_transform(transf) empty!(rects[]) @@ -69,13 +69,13 @@ function Makie.plot!(p::Union{HSpan, VSpan}) push!(rects[], Rect2f(Point2f(low, y_mi), Vec2f(high - low, y_ma - y_mi))) end end - notify(rects) + return notify(rects) end notify(p[1]) poly!(p, rects; p.attributes...) - p + return p end _apply_x_transform(t::Tuple, v) = apply_transform(t[1], v) diff --git a/src/basic_recipes/pie.jl b/src/basic_recipes/pie.jl index 206bf6ae633..d2da8dd5ff6 100644 --- a/src/basic_recipes/pie.jl +++ b/src/basic_recipes/pie.jl @@ -7,27 +7,32 @@ Creates a pie chart with the given `fractions`. $(ATTRIBUTES) """ @recipe(Pie, values) do scene - Theme( - normalize = true, - color = :gray, - strokecolor = :black, - strokewidth = 1, - vertex_per_deg = 1, - radius = 1, - inner_radius = 0, - offset = 0, - inspectable = theme(scene, :inspectable), - visible = true, - transparency = false + return Theme( + normalize=true, + color=:gray, + strokecolor=:black, + strokewidth=1, + vertex_per_deg=1, + radius=1, + inner_radius=0, + offset=0, + inspectable=theme(scene, :inspectable), + visible=true, + transparency=false, ) end function plot!(plot::Pie) - values = plot[1] - polys = lift(values, plot.vertex_per_deg, plot.radius, plot.inner_radius, plot.offset, plot.normalize) do vals, vertex_per_deg, radius, inner_radius, offset, normalize - + polys = lift( + values, + plot.vertex_per_deg, + plot.radius, + plot.inner_radius, + plot.offset, + plot.normalize, + ) do vals, vertex_per_deg, radius, inner_radius, offset, normalize T = eltype(vals) # find start and end angles of all pie pieces @@ -39,20 +44,20 @@ function plot!(plot::Pie) end # create vector of a vector of points for each piece - vertex_arrays = map(boundaries[1:end-1], boundaries[2:end]) do sta, en + vertex_arrays = map(boundaries[1:(end - 1)], boundaries[2:end]) do sta, en distance = en - sta # how many vertices are needed for the curve? nvertices = max(2, ceil(Int, rad2deg(distance) * vertex_per_deg)) # curve points points = map(LinRange(sta, en, nvertices)) do rad - Point2f(cos(rad + offset), sin(rad + offset)) .* radius + return Point2f(cos(rad + offset), sin(rad + offset)) .* radius end # add inner points (either curve or one point) if inner_radius != 0 inner_points = map(LinRange(en, sta, nvertices)) do rad - Point2f(cos(rad + offset), sin(rad + offset)) .* inner_radius + return Point2f(cos(rad + offset), sin(rad + offset)) .* inner_radius end append!(points, inner_points) @@ -60,17 +65,21 @@ function plot!(plot::Pie) push!(points, Point2f(0, 0)) end - points + return points end end # plot pieces as polys poly!( - plot, polys, - color = plot.color, strokewidth = plot.strokewidth, - strokecolor = plot.strokecolor, inspectable = plot.inspectable, - visible = plot.visible, transparency = plot.transparency + plot, + polys, + color=plot.color, + strokewidth=plot.strokewidth, + strokecolor=plot.strokecolor, + inspectable=plot.inspectable, + visible=plot.visible, + transparency=plot.transparency, ) - plot + return plot end diff --git a/src/basic_recipes/poly.jl b/src/basic_recipes/poly.jl index e8d4a7ee57a..8c273852aee 100644 --- a/src/basic_recipes/poly.jl +++ b/src/basic_recipes/poly.jl @@ -1,34 +1,43 @@ -const PolyElements = Union{Polygon, MultiPolygon, Circle, Rect, AbstractMesh, VecTypes, AbstractVector{<:VecTypes}} +const PolyElements = Union{Polygon,MultiPolygon,Circle,Rect,AbstractMesh,VecTypes,AbstractVector{<:VecTypes}} -convert_arguments(::Type{<: Poly}, v::AbstractVector{<: PolyElements}) = (v,) -convert_arguments(::Type{<: Poly}, v::Union{Polygon, MultiPolygon}) = (v,) +convert_arguments(::Type{<:Poly}, v::AbstractVector{<:PolyElements}) = (v,) +convert_arguments(::Type{<:Poly}, v::Union{Polygon,MultiPolygon}) = (v,) -convert_arguments(::Type{<: Poly}, args...) = ([convert_arguments(Scatter, args...)[1]],) -convert_arguments(::Type{<: Poly}, vertices::AbstractArray, indices::AbstractArray) = convert_arguments(Mesh, vertices, indices) -convert_arguments(::Type{<: Poly}, m::GeometryBasics.Mesh) = (m,) -convert_arguments(::Type{<: Poly}, m::GeometryBasics.GeometryPrimitive) = (m,) +convert_arguments(::Type{<:Poly}, args...) = ([convert_arguments(Scatter, args...)[1]],) +function convert_arguments(::Type{<:Poly}, vertices::AbstractArray, indices::AbstractArray) + return convert_arguments(Mesh, vertices, indices) +end +convert_arguments(::Type{<:Poly}, m::GeometryBasics.Mesh) = (m,) +convert_arguments(::Type{<:Poly}, m::GeometryBasics.GeometryPrimitive) = (m,) -function plot!(plot::Poly{<: Tuple{Union{GeometryBasics.Mesh, GeometryPrimitive}}}) +function plot!(plot::Poly{<:Tuple{Union{GeometryBasics.Mesh,GeometryPrimitive}}}) mesh!( - plot, lift(triangle_mesh, plot[1]), - color = plot[:color], - colormap = plot[:colormap], - colorrange = plot[:colorrange], - lowclip = plot[:lowclip], - highclip = plot[:highclip], - nan_color = plot[:nan_color], - shading = plot[:shading], - visible = plot[:visible], - overdraw = plot[:overdraw], - inspectable = plot[:inspectable], - transparency = plot[:transparency], - space = plot[:space] + plot, + lift(triangle_mesh, plot[1]), + color=plot[:color], + colormap=plot[:colormap], + colorrange=plot[:colorrange], + lowclip=plot[:lowclip], + highclip=plot[:highclip], + nan_color=plot[:nan_color], + shading=plot[:shading], + visible=plot[:visible], + overdraw=plot[:overdraw], + inspectable=plot[:inspectable], + transparency=plot[:transparency], + space=plot[:space], ) - wireframe!( - plot, plot[1], - color = plot[:strokecolor], linestyle = plot[:linestyle], space = plot[:space], - linewidth = plot[:strokewidth], visible = plot[:visible], overdraw = plot[:overdraw], - inspectable = plot[:inspectable], transparency = plot[:transparency] + return wireframe!( + plot, + plot[1], + color=plot[:strokecolor], + linestyle=plot[:linestyle], + space=plot[:space], + linewidth=plot[:strokewidth], + visible=plot[:visible], + overdraw=plot[:overdraw], + inspectable=plot[:inspectable], + transparency=plot[:transparency], ) end @@ -47,11 +56,9 @@ poly_convert(mesh::GeometryBasics.Mesh) = mesh poly_convert(polygon::Polygon) = triangle_mesh(polygon) -function poly_convert(polygon::AbstractVector{<: VecTypes}) - return poly_convert([convert_arguments(Scatter, polygon)[1]]) -end +poly_convert(polygon::AbstractVector{<:VecTypes}) = poly_convert([convert_arguments(Scatter, polygon)[1]]) -function poly_convert(polygons::AbstractVector{<: AbstractVector{<: VecTypes}}) +function poly_convert(polygons::AbstractVector{<:AbstractVector{<:VecTypes}}) return map(polygons) do poly point2f = convert(Vector{Point2f}, poly) faces = GeometryBasics.earcut_triangulate([point2f]) @@ -77,33 +84,38 @@ function to_line_segments(meshes::AbstractVector) return line end -function to_line_segments(polygon::AbstractVector{<: VecTypes}) +function to_line_segments(polygon::AbstractVector{<:VecTypes}) result = Point2f.(polygon) push!(result, polygon[1]) return result end -function plot!(plot::Poly{<: Tuple{<: Union{Polygon, AbstractVector{<: PolyElements}}}}) +function plot!(plot::Poly{<:Tuple{<:Union{Polygon,AbstractVector{<:PolyElements}}}}) geometries = plot[1] meshes = lift(poly_convert, geometries) - mesh!(plot, meshes; - visible = plot.visible, - shading = plot.shading, - color = plot.color, - colormap = plot.colormap, - colorrange = plot.colorrange, - lowclip = plot.lowclip, - highclip = plot.highclip, - nan_color = plot.nan_color, - overdraw = plot.overdraw, - fxaa = plot.fxaa, - transparency = plot.transparency, - inspectable = plot.inspectable, - space = plot.space + mesh!( + plot, + meshes; + visible=plot.visible, + shading=plot.shading, + color=plot.color, + colormap=plot.colormap, + colorrange=plot.colorrange, + lowclip=plot.lowclip, + highclip=plot.highclip, + nan_color=plot.nan_color, + overdraw=plot.overdraw, + fxaa=plot.fxaa, + transparency=plot.transparency, + inspectable=plot.inspectable, + space=plot.space, ) outline = lift(to_line_segments, geometries) stroke = lift(outline, plot.strokecolor) do outline, sc - if !(meshes[] isa Mesh) && meshes[] isa AbstractVector && sc isa AbstractVector && length(sc) == length(meshes[]) + if !(meshes[] isa Mesh) && + meshes[] isa AbstractVector && + sc isa AbstractVector && + length(sc) == length(meshes[]) idx = 1 return map(outline) do point if isnan(point) @@ -116,34 +128,44 @@ function plot!(plot::Poly{<: Tuple{<: Union{Polygon, AbstractVector{<: PolyEleme end end - lines!( - plot, outline, visible = plot.visible, - color = stroke, linestyle = plot.linestyle, - linewidth = plot.strokewidth, space = plot.space, - overdraw = plot.overdraw, transparency = plot.transparency, - inspectable = plot.inspectable, depth_shift = -1f-5 + return lines!( + plot, + outline, + visible=plot.visible, + color=stroke, + linestyle=plot.linestyle, + linewidth=plot.strokewidth, + space=plot.space, + overdraw=plot.overdraw, + transparency=plot.transparency, + inspectable=plot.inspectable, + depth_shift=-1.0f-5, ) end -function plot!(plot::Mesh{<: Tuple{<: AbstractVector{P}}}) where P <: Union{AbstractMesh, Polygon} +function plot!(plot::Mesh{<:Tuple{<:AbstractVector{P}}}) where {P<:Union{AbstractMesh,Polygon}} meshes = plot[1] color_node = plot.color attributes = Attributes( - visible = plot.visible, shading = plot.shading, fxaa = plot.fxaa, - inspectable = plot.inspectable, transparency = plot.transparency, - space = plot.space, ssao = plot.ssao, - lowclip = get(plot, :lowclip, automatic), - highclip = get(plot, :highclip, automatic), - nan_color = get(plot, :nan_color, :transparent), - colormap = get(plot, :colormap, nothing), - colorrange = get(plot, :colorrange, automatic) + visible=plot.visible, + shading=plot.shading, + fxaa=plot.fxaa, + inspectable=plot.inspectable, + transparency=plot.transparency, + space=plot.space, + ssao=plot.ssao, + lowclip=get(plot, :lowclip, automatic), + highclip=get(plot, :highclip, automatic), + nan_color=get(plot, :nan_color, :transparent), + colormap=get(plot, :colormap, nothing), + colorrange=get(plot, :colorrange, automatic), ) num_meshes = lift(meshes; ignore_equal_values=true) do meshes return Int[length(coordinates(m)) for m in meshes] end - mesh_colors = Observable{Union{AbstractPattern, Matrix{RGBAf}, RGBColors}}() + mesh_colors = Observable{Union{AbstractPattern,Matrix{RGBAf},RGBColors}}() map!(mesh_colors, plot.color, num_meshes) do colors, num_meshes # one mesh per color @@ -174,5 +196,5 @@ function plot!(plot::Mesh{<: Tuple{<: AbstractVector{P}}}) where P <: Union{Abst return merge(GeometryBasics.triangle_mesh.(meshes)) end end - mesh!(plot, attributes, bigmesh) + return mesh!(plot, attributes, bigmesh) end diff --git a/src/basic_recipes/raincloud.jl b/src/basic_recipes/raincloud.jl index 4c5fe446e74..190fb1f66c3 100644 --- a/src/basic_recipes/raincloud.jl +++ b/src/basic_recipes/raincloud.jl @@ -2,7 +2,8 @@ #### Helper functions to make the cloud plot! #### function cloud_plot_check_args(category_labels, data_array) - length(category_labels) == length(data_array) || DimensionMismatch("Length of category_labels must match with length of data_array") + length(category_labels) == length(data_array) || + DimensionMismatch("Length of category_labels must match with length of data_array") return nothing end @@ -77,39 +78,35 @@ paired with the scatter plot so the default is to not show them) """ @recipe(RainClouds, category_labels, data_array) do scene return Attributes( - side = :left, - orientation = :vertical, - center_boxplot = true, + side=:left, + orientation=:vertical, + center_boxplot=true, # Cloud plot - cloud_width = 0.75, - violin_limits = (-Inf, Inf), + cloud_width=0.75, + violin_limits=(-Inf, Inf), # Box Plot Settings - boxplot_width = 0.1, - whiskerwidth = 0.5, - strokewidth = 1.0, - show_median = true, - boxplot_nudge = 0.075, - - gap = 0.2, - - markersize = 2.0, - dodge = automatic, - n_dodge = automatic, - dodge_gap = 0.01, - - plot_boxplots = true, - show_boxplot_outliers = false, - clouds = violin, - hist_bins = 30, - - color = theme(scene, :patchcolor), - cycle = [:color => :patchcolor], + boxplot_width=0.1, + whiskerwidth=0.5, + strokewidth=1.0, + show_median=true, + boxplot_nudge=0.075, + gap=0.2, + markersize=2.0, + dodge=automatic, + n_dodge=automatic, + dodge_gap=0.01, + plot_boxplots=true, + show_boxplot_outliers=false, + clouds=violin, + hist_bins=30, + color=theme(scene, :patchcolor), + cycle=[:color => :patchcolor], ) end # create_jitter_array(length_data_array; jitter_width = 0.1, clamped_portion = 0.1) # Returns a array containing random values with a mean of 0, and a values from `-jitter_width/2.0` to `+jitter_width/2.0`, where a portion of a values are clamped right at the edges. -function create_jitter_array(length_data_array; jitter_width = 0.1, clamped_portion = 0.1) +function create_jitter_array(length_data_array; jitter_width=0.1, clamped_portion=0.1) jitter_width < 0 && ArgumentError("`jitter_width` should be positive.") !(0 <= clamped_portion <= 1) || ArgumentError("`clamped_portion` should be between 0.0 to 1.0") @@ -135,10 +132,7 @@ end #### #### Functions that make the cloud plot #### -function plot!( - ax::Makie.Axis, P::Type{<: RainClouds}, - allattrs::Attributes, category_labels, data_array) - +function plot!(ax::Makie.Axis, P::Type{<:RainClouds}, allattrs::Attributes, category_labels, data_array) plot = plot!(ax.scene, P, allattrs, category_labels, data_array) if any(x -> x isa AbstractString, category_labels) @@ -163,8 +157,8 @@ function plot!( end function group_labels(category_labels, data_array) - grouped = Dict{eltype(category_labels), Vector{Int}}() - for (label, data_ix) in zip(category_labels, axes(data_array,1)) + grouped = Dict{eltype(category_labels),Vector{Int}}() + for (label, data_ix) in zip(category_labels, axes(data_array, 1)) push!(get!(grouped, label, eltype(data_array)[]), data_ix) end @@ -186,7 +180,7 @@ function ungroup_labels(category_labels, data_array) return category_labels, data_array end -function convert_arguments(::Type{<: RainClouds}, category_labels, data_array) +function convert_arguments(::Type{<:RainClouds}, category_labels, data_array) cloud_plot_check_args(category_labels, data_array) return (category_labels, data_array) end @@ -213,7 +207,7 @@ function plot!(plot::RainClouds) side = plot.side[] center_boxplot_bool = plot.center_boxplot[] # Cloud plot - cloud_width = plot.cloud_width[] + cloud_width = plot.cloud_width[] cloud_width[] < 0 && ArgumentError("`cloud_width` should be positive.") # Box Plot Settings @@ -233,12 +227,12 @@ function plot!(plot::RainClouds) # Scatter Plot Settings side_scatter_nudge = to_value(get(plot, :side_nudge, side_scatter_nudge_default)) - side_scatter_nudge < 0 && ArgumentError("`side_nudge` should be positive. Change `side` to :left, :right if you wish.") + side_scatter_nudge < 0 && + ArgumentError("`side_nudge` should be positive. Change `side` to :left, :right if you wish.") jitter_width = abs(to_value(get(plot, :jitter_width, jitter_width_default))) jitter_width < 0 && ArgumentError("`jitter_width` should be positive.") markersize = plot.markersize[] - # Set-up if plot.orientation[] == :horizontal # flip side to when horizontal @@ -252,23 +246,39 @@ function plot!(plot::RainClouds) recenter_to_boxplot_nudge_value = center_boxplot_bool ? side_boxplot_nudge_with_direction : 0.0 plot_boxplots || (recenter_to_boxplot_nudge_value = 0.0) # Note: these cloud plots are horizontal - full_width = jitter_width + side_scatter_nudge + + full_width = + jitter_width + + side_scatter_nudge + (plot_boxplots ? boxplot_width : 0) + (!isnothing(clouds) ? 1 + abs(recenter_to_boxplot_nudge_value) : 0) - final_x_positions, width = compute_x_and_width(x_positions .+ recenter_to_boxplot_nudge_value/2, full_width, - plot.gap[], plot.dodge[], - plot.n_dodge[], plot.dodge_gap[]) + final_x_positions, width = compute_x_and_width( + x_positions .+ recenter_to_boxplot_nudge_value / 2, + full_width, + plot.gap[], + plot.dodge[], + plot.n_dodge[], + plot.dodge_gap[], + ) width_ratio = width / full_width - jitter = create_jitter_array(length(data_array); - jitter_width = jitter_width*width_ratio) + jitter = create_jitter_array(length(data_array); jitter_width=jitter_width * width_ratio) if !isnothing(clouds) if clouds === violin - violin!(plot, final_x_positions .- recenter_to_boxplot_nudge_value.*width_ratio, data_array; - show_median=show_median, side=side, width=width_ratio*cloud_width, plot.cycle, - datalimits=plot.violin_limits, plot.color, gap=0, orientation=plot.orientation[]) + violin!( + plot, + final_x_positions .- recenter_to_boxplot_nudge_value .* width_ratio, + data_array; + show_median=show_median, + side=side, + width=width_ratio * cloud_width, + plot.cycle, + datalimits=plot.violin_limits, + plot.color, + gap=0, + orientation=plot.orientation[], + ) elseif clouds === hist edges = pick_hist_edges(data_array, hist_bins) # dodge belongs below: it ensure that the histogram groups labels by both dodge @@ -281,20 +291,26 @@ function plot!(plot::RainClouds) for (_, ixs) in group_labels(groupings, data_array) isempty(ixs) && continue xoffset = final_x_positions[ixs[1]] - recenter_to_boxplot_nudge_value - hist!(plot, view(data_array, ixs); offset=xoffset, - scale_to=(side == :left ? -1 : 1)*cloud_width*width_ratio, bins=edges, - # yes, we really do want :x when orientation is :vertical - # an :x directed histogram has a vertical orientation - direction=plot.orientation[] == :vertical ? :x : :y, - color=getuniquevalue(plot.color[], ixs)) + hist!( + plot, + view(data_array, ixs); + offset=xoffset, + scale_to=(side == :left ? -1 : 1) * cloud_width * width_ratio, + bins=edges, + # yes, we really do want :x when orientation is :vertical + # an :x directed histogram has a vertical orientation + direction=plot.orientation[] == :vertical ? :x : :y, + color=getuniquevalue(plot.color[], ixs), + ) end else error("cloud attribute accepts (violin, hist, nothing), but not: $(clouds)") end end - scatter_x = final_x_positions .+ side_scatter_nudge_with_direction.*width_ratio .+ - jitter .- recenter_to_boxplot_nudge_value.*width_ratio + scatter_x = + final_x_positions .+ side_scatter_nudge_with_direction .* width_ratio .+ jitter .- + recenter_to_boxplot_nudge_value .* width_ratio if plot.orientation[] == :vertical scatter!(plot, scatter_x, data_array; markersize=markersize, plot.color, plot.cycle) else @@ -302,17 +318,20 @@ function plot!(plot::RainClouds) end if plot_boxplots - boxplot!(plot, final_x_positions .+ side_boxplot_nudge_with_direction.*width_ratio .- - recenter_to_boxplot_nudge_value.*width_ratio, - data_array; - plot.orientation, - strokewidth=strokewidth, - whiskerwidth=whiskerwidth*width_ratio, - width=boxplot_width*width_ratio, - markersize=markersize, - show_outliers=plot.show_boxplot_outliers[], - color=plot.color, - cycle=plot.cycle) + boxplot!( + plot, + final_x_positions .+ side_boxplot_nudge_with_direction .* width_ratio .- + recenter_to_boxplot_nudge_value .* width_ratio, + data_array; + plot.orientation, + strokewidth=strokewidth, + whiskerwidth=whiskerwidth * width_ratio, + width=boxplot_width * width_ratio, + markersize=markersize, + show_outliers=plot.show_boxplot_outliers[], + color=plot.color, + cycle=plot.cycle, + ) end return plot diff --git a/src/basic_recipes/scatterlines.jl b/src/basic_recipes/scatterlines.jl index d63b9446a4f..ac5e8930c60 100644 --- a/src/basic_recipes/scatterlines.jl +++ b/src/basic_recipes/scatterlines.jl @@ -9,29 +9,28 @@ $(ATTRIBUTES) @recipe(ScatterLines) do scene s_theme = default_theme(scene, Scatter) l_theme = default_theme(scene, Lines) - Attributes( - color = l_theme.color, - colormap = l_theme.colormap, - colorrange = get(l_theme.attributes, :colorrange, automatic), - linestyle = l_theme.linestyle, - linewidth = l_theme.linewidth, - markercolor = automatic, - markercolormap = s_theme.colormap, - markercolorrange = get(s_theme.attributes, :colorrange, automatic), - markersize = s_theme.markersize, - strokecolor = s_theme.strokecolor, - strokewidth = s_theme.strokewidth, - marker = s_theme.marker, - inspectable = theme(scene, :inspectable), - cycle = [:color], + return Attributes( + color=l_theme.color, + colormap=l_theme.colormap, + colorrange=get(l_theme.attributes, :colorrange, automatic), + linestyle=l_theme.linestyle, + linewidth=l_theme.linewidth, + markercolor=automatic, + markercolormap=s_theme.colormap, + markercolorrange=get(s_theme.attributes, :colorrange, automatic), + markersize=s_theme.markersize, + strokecolor=s_theme.strokecolor, + strokewidth=s_theme.strokewidth, + marker=s_theme.marker, + inspectable=theme(scene, :inspectable), + cycle=[:color], ) end - -function plot!(p::Combined{scatterlines, <:NTuple{N, Any}}) where N +function plot!(p::Combined{scatterlines,<:NTuple{N,Any}}) where {N} # markercolor is the same as linecolor if left automatic - real_markercolor = Observable{Union{Vector{RGBAf}, RGBAf}}() + real_markercolor = Observable{Union{Vector{RGBAf},RGBAf}}() map!(real_markercolor, p.color, p.markercolor) do col, mcol if mcol === automatic return to_color(col) @@ -40,22 +39,26 @@ function plot!(p::Combined{scatterlines, <:NTuple{N, Any}}) where N end end - lines!(p, p[1:N]...; - color = p.color, - linestyle = p.linestyle, - linewidth = p.linewidth, - colormap = p.colormap, - colorrange = p.colorrange, - inspectable = p.inspectable + lines!( + p, + p[1:N]...; + color=p.color, + linestyle=p.linestyle, + linewidth=p.linewidth, + colormap=p.colormap, + colorrange=p.colorrange, + inspectable=p.inspectable, ) - scatter!(p, p[1:N]...; - color = real_markercolor, - strokecolor = p.strokecolor, - strokewidth = p.strokewidth, - marker = p.marker, - markersize = p.markersize, - colormap = p.markercolormap, - colorrange = p.markercolorrange, - inspectable = p.inspectable + return scatter!( + p, + p[1:N]...; + color=real_markercolor, + strokecolor=p.strokecolor, + strokewidth=p.strokewidth, + marker=p.marker, + markersize=p.markersize, + colormap=p.markercolormap, + colorrange=p.markercolorrange, + inspectable=p.inspectable, ) end diff --git a/src/basic_recipes/series.jl b/src/basic_recipes/series.jl index c7bf498cb42..b071f8fe5bc 100644 --- a/src/basic_recipes/series.jl +++ b/src/basic_recipes/series.jl @@ -1,5 +1,4 @@ - """ series(curves; linewidth=2, @@ -21,12 +20,11 @@ Curves can be: """ @recipe(Series, curves) do scene - Attributes( + return Attributes( linewidth=2, color=:lighttest, solid_color=nothing, labels=nothing, - marker=nothing, markersize=nothing, markercolor=automatic, @@ -37,29 +35,27 @@ end replace_missing(x) = ismissing(x) ? NaN : x -function convert_arguments(T::Type{<: Series}, y::AbstractMatrix) - convert_arguments(T, 1:size(y, 2), y) -end +convert_arguments(T::Type{<:Series}, y::AbstractMatrix) = convert_arguments(T, 1:size(y, 2), y) -function convert_arguments(::Type{<: Series}, x::AbstractVector, ys::AbstractMatrix) +function convert_arguments(::Type{<:Series}, x::AbstractVector, ys::AbstractMatrix) return (map(1:size(ys, 1)) do i - Point2f.(replace_missing.(x), replace_missing.(view(ys, i, :))) + return Point2f.(replace_missing.(x), replace_missing.(view(ys, i, :))) end,) end -function convert_arguments(::Type{<: Series}, arg::AbstractVector{<: Tuple{X, Y}}) where {X, Y} +function convert_arguments(::Type{<:Series}, arg::AbstractVector{<:Tuple{X,Y}}) where {X,Y} return (map(arg) do (x, y) - Point2f.(replace_missing.(x), replace_missing.(y)) + return Point2f.(replace_missing.(x), replace_missing.(y)) end,) end -function convert_arguments(T::Type{<: Series}, arg::Tuple{<:AbstractVector, <:AbstractVector}) +function convert_arguments(T::Type{<:Series}, arg::Tuple{<:AbstractVector,<:AbstractVector}) return convert_arguments(T, [arg]) end -function convert_arguments(::Type{<: Series}, arg::AbstractVector{<: AbstractVector{<:Point2}}) +function convert_arguments(::Type{<:Series}, arg::AbstractVector{<:AbstractVector{<:Point2}}) return (map(arg) do points - Point2f.(replace_missing.(first.(points)), replace_missing.(last.(points))) + return Point2f.(replace_missing.(first.(points)), replace_missing.(last.(points))) end,) end @@ -83,15 +79,19 @@ function plot!(plot::Series) if !isempty(scatter) mcolor = plot.markercolor markercolor = @lift $mcolor == automatic ? $series_color : $mcolor - scatterlines!(plot, positions; - linewidth=linewidth, color=series_color, markercolor=series_color, - label=label[], scatter...) + scatterlines!( + plot, + positions; + linewidth=linewidth, + color=series_color, + markercolor=series_color, + label=label[], + scatter..., + ) else lines!(plot, positions; linewidth=linewidth, color=series_color, label=label) end end end -function Makie.get_plots(plot::Series) - return plot.plots -end +Makie.get_plots(plot::Series) = plot.plots diff --git a/src/basic_recipes/spy.jl b/src/basic_recipes/spy.jl index 2b3a0469722..ecabd3367c8 100644 --- a/src/basic_recipes/spy.jl +++ b/src/basic_recipes/spy.jl @@ -14,33 +14,28 @@ spy(0..1, 0..1, x) $(ATTRIBUTES) """ @recipe(Spy, x, y, z) do scene - Attributes( - marker = automatic, - markersize = automatic, - colormap = theme(scene, :colormap), - colorrange = automatic, - framecolor = :black, - framesize = 1, - inspectable = theme(scene, :inspectable), - visible = theme(scene, :visible) + return Attributes( + marker=automatic, + markersize=automatic, + colormap=theme(scene, :colormap), + colorrange=automatic, + framecolor=:black, + framesize=1, + inspectable=theme(scene, :inspectable), + visible=theme(scene, :visible), ) end -function convert_arguments(::Type{<: Spy}, x::SparseArrays.AbstractSparseArray) - (0..size(x, 1), 0..size(x, 2), x) -end -function convert_arguments(::Type{<: Spy}, x, y, z::SparseArrays.AbstractSparseArray) - (x, y, z) -end +convert_arguments(::Type{<:Spy}, x::SparseArrays.AbstractSparseArray) = (0 .. size(x, 1), 0 .. size(x, 2), x) +convert_arguments(::Type{<:Spy}, x, y, z::SparseArrays.AbstractSparseArray) = (x, y, z) -function calculated_attributes!(::Type{<: Spy}, plot) -end +function calculated_attributes!(::Type{<:Spy}, plot) end function plot!(p::Spy) rect = lift(p.x, p.y) do x, y xe = extrema(x) ye = extrema(y) - Rect2f((xe[1], ye[1]), (xe[2] - xe[1], ye[2] - ye[1])) + return Rect2f((xe[1], ye[1]), (xe[2] - xe[1], ye[2] - ye[1])) end # TODO FastPixel isn't accepting marker size in data coordinates # but instead in pixel - so we need to fix that in GLMakie for consistency @@ -56,15 +51,14 @@ function plot!(p::Spy) xycol = lift(rect, p.z, markersize) do rect, z, markersize x, y, color = SparseArrays.findnz(z) points = map(x, y) do x, y - (((Point2f(x, y) .- 1) ./ Point2f(size(z) .- 1)) .* - widths(rect) .+ minimum(rect)) + return (((Point2f(x, y) .- 1) ./ Point2f(size(z) .- 1)) .* widths(rect) .+ minimum(rect)) end - points, convert(Vector{Float32}, color) + return points, convert(Vector{Float32}, color) end replace_automatic!(p, :colorrange) do lift(xycol) do (xy, col) - extrema_nan(col) + return extrema_nan(col) end end @@ -74,11 +68,22 @@ function plot!(p::Spy) scatter!( p, - lift(first, xycol), color = lift(last, xycol), - marker = marker, markersize = markersize, colorrange = p.colorrange, - colormap = p.colormap, inspectable = p.inspectable, visible = p.visible + lift(first, xycol), + color=lift(last, xycol), + marker=marker, + markersize=markersize, + colorrange=p.colorrange, + colormap=p.colormap, + inspectable=p.inspectable, + visible=p.visible, ) - lines!(p, rect, color = p.framecolor, linewidth = p.framesize, inspectable = p.inspectable, - visible = p.visible) + return lines!( + p, + rect, + color=p.framecolor, + linewidth=p.framesize, + inspectable=p.inspectable, + visible=p.visible, + ) end diff --git a/src/basic_recipes/stairs.jl b/src/basic_recipes/stairs.jl index 10e7f27dec6..d2758769a9d 100644 --- a/src/basic_recipes/stairs.jl +++ b/src/basic_recipes/stairs.jl @@ -15,9 +15,9 @@ $(ATTRIBUTES) """ @recipe(Stairs) do scene a = Attributes( - step = :pre, # :center :post + step=:pre, # :center :post ) - merge(a, default_theme(scene, Lines)) + return merge(a, default_theme(scene, Lines)) end conversion_trait(::Type{<:Stairs}) = PointBased() @@ -29,7 +29,7 @@ function plot!(p::Stairs{<:Tuple{<:AbstractVector{<:Point2}}}) if step == :pre s_points = Vector{Point2f}(undef, length(points) * 2 - 1) s_points[1] = point = points[1] - for i in 1:length(points)-1 + for i in 1:(length(points) - 1) nextpoint = points[i + 1] s_points[2i] = Point2f(point[1], nextpoint[2]) s_points[2i + 1] = nextpoint @@ -39,8 +39,8 @@ function plot!(p::Stairs{<:Tuple{<:AbstractVector{<:Point2}}}) elseif step == :post s_points = Vector{Point2f}(undef, length(points) * 2 - 1) s_points[1] = point = points[1] - for i in 1:length(points)-1 - nextpoint = points[i+1] + for i in 1:(length(points) - 1) + nextpoint = points[i + 1] s_points[2i] = Point2f(nextpoint[1], point[2]) s_points[2i + 1] = nextpoint point = nextpoint @@ -49,8 +49,8 @@ function plot!(p::Stairs{<:Tuple{<:AbstractVector{<:Point2}}}) elseif step == :center s_points = Vector{Point2f}(undef, length(points) * 2) s_points[1] = point = points[1] - for i in 1:length(points)-1 - nextpoint = points[i+1] + for i in 1:(length(points) - 1) + nextpoint = points[i + 1] halfx = (point[1] + nextpoint[1]) / 2 s_points[2i] = Point2f(halfx, point[2]) s_points[2i + 1] = Point2f(halfx, nextpoint[2]) @@ -64,6 +64,5 @@ function plot!(p::Stairs{<:Tuple{<:AbstractVector{<:Point2}}}) end lines!(p, steppoints; [x for x in pairs(p.attributes) if x[1] != :step]...) - p + return p end - diff --git a/src/basic_recipes/stem.jl b/src/basic_recipes/stem.jl index d3737b8c31c..e3f4a004894 100644 --- a/src/basic_recipes/stem.jl +++ b/src/basic_recipes/stem.jl @@ -13,75 +13,81 @@ The conversion trait of stem is `PointBased`. $(ATTRIBUTES) """ @recipe(Stem) do scene - Attributes( - stemcolor = theme(scene, :linecolor), - stemcolormap = theme(scene, :colormap), - stemcolorrange = automatic, - stemwidth = theme(scene, :linewidth), - stemlinestyle = nothing, - trunkwidth = theme(scene, :linewidth), - trunklinestyle = nothing, - trunkcolor = theme(scene, :linecolor), - trunkcolormap = theme(scene, :colormap), - trunkcolorrange = automatic, - offset = 0, - marker = :circle, - markersize = theme(scene, :markersize), - color = theme(scene, :markercolor), - colormap = theme(scene, :colormap), - colorrange = automatic, - strokecolor = theme(scene, :markerstrokecolor), - strokewidth = theme(scene, :markerstrokewidth), - visible = true, - inspectable = theme(scene, :inspectable), - cycle = [[:stemcolor, :color, :trunkcolor] => :color], + return Attributes( + stemcolor=theme(scene, :linecolor), + stemcolormap=theme(scene, :colormap), + stemcolorrange=automatic, + stemwidth=theme(scene, :linewidth), + stemlinestyle=nothing, + trunkwidth=theme(scene, :linewidth), + trunklinestyle=nothing, + trunkcolor=theme(scene, :linecolor), + trunkcolormap=theme(scene, :colormap), + trunkcolorrange=automatic, + offset=0, + marker=:circle, + markersize=theme(scene, :markersize), + color=theme(scene, :markercolor), + colormap=theme(scene, :colormap), + colorrange=automatic, + strokecolor=theme(scene, :markerstrokecolor), + strokewidth=theme(scene, :markerstrokewidth), + visible=true, + inspectable=theme(scene, :inspectable), + cycle=[[:stemcolor, :color, :trunkcolor] => :color], ) end - conversion_trait(::Type{<:Stem}) = PointBased() - -trunkpoint(stempoint::P, offset::Number) where P <: Point2 = P(stempoint[1], offset) -trunkpoint(stempoint::P, offset::Point2) where P <: Point2 = P(offset...) -trunkpoint(stempoint::P, offset::Number) where P <: Point3 = P(stempoint[1], stempoint[2], offset) -trunkpoint(stempoint::P, offset::Point3) where P <: Point3 = P(offset...) - +trunkpoint(stempoint::P, offset::Number) where {P<:Point2} = P(stempoint[1], offset) +trunkpoint(stempoint::P, offset::Point2) where {P<:Point2} = P(offset...) +trunkpoint(stempoint::P, offset::Number) where {P<:Point3} = P(stempoint[1], stempoint[2], offset) +trunkpoint(stempoint::P, offset::Point3) where {P<:Point3} = P(offset...) function plot!(s::Stem{<:Tuple{<:AbstractVector{<:Point}}}) points = s[1] stemtuples = lift(points, s.offset) do ps, to - tuple.(ps, trunkpoint.(ps, to)) + return tuple.(ps, trunkpoint.(ps, to)) end trunkpoints = @lift(last.($stemtuples)) - lines!(s, trunkpoints, - linewidth = s.trunkwidth, - color = s.trunkcolor, - colormap = s.trunkcolormap, - colorrange = s.trunkcolorrange, - visible = s.visible, - linestyle = s.trunklinestyle, - inspectable = s.inspectable) - linesegments!(s, stemtuples, - linewidth = s.stemwidth, - color = s.stemcolor, - colormap = s.stemcolormap, - colorrange = s.stemcolorrange, - visible = s.visible, - linestyle = s.stemlinestyle, - inspectable = s.inspectable) - scatter!(s, s[1], - color = s.color, - colormap = s.colormap, - colorrange = s.colorrange, - markersize = s.markersize, - marker = s.marker, - strokecolor = s.strokecolor, - strokewidth = s.strokewidth, - visible = s.visible, - inspectable = s.inspectable) - s + lines!( + s, + trunkpoints, + linewidth=s.trunkwidth, + color=s.trunkcolor, + colormap=s.trunkcolormap, + colorrange=s.trunkcolorrange, + visible=s.visible, + linestyle=s.trunklinestyle, + inspectable=s.inspectable, + ) + linesegments!( + s, + stemtuples, + linewidth=s.stemwidth, + color=s.stemcolor, + colormap=s.stemcolormap, + colorrange=s.stemcolorrange, + visible=s.visible, + linestyle=s.stemlinestyle, + inspectable=s.inspectable, + ) + scatter!( + s, + s[1], + color=s.color, + colormap=s.colormap, + colorrange=s.colorrange, + markersize=s.markersize, + marker=s.marker, + strokecolor=s.strokecolor, + strokewidth=s.strokewidth, + visible=s.visible, + inspectable=s.inspectable, + ) + return s end diff --git a/src/basic_recipes/streamplot.jl b/src/basic_recipes/streamplot.jl index 63e12505192..683d333b9c7 100644 --- a/src/basic_recipes/streamplot.jl +++ b/src/basic_recipes/streamplot.jl @@ -17,29 +17,29 @@ $(ATTRIBUTES) See the function `Makie.streamplot_impl` for implementation details. """ @recipe(StreamPlot, f, limits) do scene - merge( + return merge( Attributes( - stepsize = 0.01, - gridsize = (32, 32, 32), - maxsteps = 500, - colormap = theme(scene, :colormap), - colorrange = Makie.automatic, - arrow_size = 15, - arrow_head = automatic, - density = 1.0, - quality = 16 + stepsize=0.01, + gridsize=(32, 32, 32), + maxsteps=500, + colormap=theme(scene, :colormap), + colorrange=Makie.automatic, + arrow_size=15, + arrow_head=automatic, + density=1.0, + quality=16, ), - default_theme(scene, Lines) # so that we can theme the lines as needed. + default_theme(scene, Lines), # so that we can theme the lines as needed. ) end -function convert_arguments(::Type{<: StreamPlot}, f::Function, xrange, yrange) +function convert_arguments(::Type{<:StreamPlot}, f::Function, xrange, yrange) xmin, xmax = extrema(xrange) ymin, ymax = extrema(yrange) return (f, Rect(xmin, ymin, xmax - xmin, ymax - ymin)) end -function convert_arguments(::Type{<: StreamPlot}, f::Function, xrange, yrange, zrange) +function convert_arguments(::Type{<:StreamPlot}, f::Function, xrange, yrange, zrange) xmin, xmax = extrema(xrange) ymin, ymax = extrema(yrange) zmin, zmax = extrema(zrange) @@ -48,9 +48,7 @@ function convert_arguments(::Type{<: StreamPlot}, f::Function, xrange, yrange, z return (f, Rect(mini, maxi .- mini)) end -function convert_arguments(::Type{<: StreamPlot}, f::Function, limits::Rect) - return (f, limits) -end +convert_arguments(::Type{<:StreamPlot}, f::Function, limits::Rect) = (f, limits) scatterfun(N) = N == 2 ? scatter! : meshscatter! @@ -73,39 +71,48 @@ Links: [Quasirandom sequences](http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/) """ -function streamplot_impl(CallType, f, limits::Rect{N, T}, resolutionND, stepsize, maxsteps=500, dens=1.0) where {N, T} - resolution = to_ndim(Vec{N, Int}, resolutionND, last(resolutionND)) +function streamplot_impl( + CallType, + f, + limits::Rect{N,T}, + resolutionND, + stepsize, + maxsteps=500, + dens=1.0, +) where {N,T} + resolution = to_ndim(Vec{N,Int}, resolutionND, last(resolutionND)) mask = trues(resolution...) # unvisited squares - arrow_pos = Point{N, Float32}[] - arrow_dir = Vec{N, Float32}[] - line_points = Point{N, Float32}[] + arrow_pos = Point{N,Float32}[] + arrow_dir = Vec{N,Float32}[] + line_points = Point{N,Float32}[] colors = Float64[] line_colors = Float64[] - dt = Point{N, Float32}(stepsize) + dt = Point{N,Float32}(stepsize) mini, maxi = minimum(limits), maximum(limits) r = ntuple(N) do i - LinRange(mini[i], maxi[i], resolution[i] + 1) - end - apply_f(x0, P) = if P <: Point - f(x0) - else - f(x0...) + return LinRange(mini[i], maxi[i], resolution[i] + 1) end + apply_f(x0, P) = + if P <: Point + f(x0) + else + f(x0...) + end # see http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/ ϕ = (MathConstants.φ, 1.324717957244746, 1.2207440846057596)[N] - acoeff = ϕ.^(-(1:N)) + acoeff = ϕ .^ (-(1:N)) n_points = 0 # count visited squares ind = 0 # index of low discrepancy sequence - while n_points < prod(resolution)*min(one(dens), dens) # fill up to 100*dens% of mask + while n_points < prod(resolution) * min(one(dens), dens) # fill up to 100*dens% of mask # next index from low discrepancy sequence c = CartesianIndex(ntuple(N) do i - j = ceil(Int, ((0.5 + acoeff[i]*ind) % 1)*resolution[i]) - clamp(j, 1, size(mask, i)) + j = ceil(Int, ((0.5 + acoeff[i] * ind) % 1) * resolution[i]) + return clamp(j, 1, size(mask, i)) end) ind += 1 if mask[c] x0 = Point{N}(ntuple(N) do i - first(r[i]) + (c[i] - 0.5) * step(r[i]) + return first(r[i]) + (c[i] - 0.5) * step(r[i]) end) point = apply_f(x0, CallType) if !(point isa Point2 || point isa Point3) @@ -121,7 +128,7 @@ function streamplot_impl(CallType, f, limits::Rect{N, T}, resolutionND, stepsize n_linepoints = 1 x = x0 ccur = c - push!(line_points, Point{N, Float32}(NaN), x) + push!(line_points, Point{N,Float32}(NaN), x) push!(line_colors, 0.0, pnorm) while x in limits && n_linepoints < maxsteps point = apply_f(x, CallType) @@ -149,31 +156,35 @@ function streamplot_impl(CallType, f, limits::Rect{N, T}, resolutionND, stepsize end end - return ( - arrow_pos, - arrow_dir, - line_points, - colors, - line_colors, - ) + return (arrow_pos, arrow_dir, line_points, colors, line_colors) end function plot!(p::StreamPlot) - data = lift(p.f, p.limits, p.gridsize, p.stepsize, p.maxsteps, p.density) do f, limits, resolution, stepsize, maxsteps, density + data = lift( + p.f, + p.limits, + p.gridsize, + p.stepsize, + p.maxsteps, + p.density, + ) do f, limits, resolution, stepsize, maxsteps, density P = if applicable(f, Point2f(0)) || applicable(f, Point3f(0)) Point else Number end - streamplot_impl(P, f, limits, resolution, stepsize, maxsteps, density) + return streamplot_impl(P, f, limits, resolution, stepsize, maxsteps, density) end lines!( p, - lift(x->x[3], data), color = lift(last, data), colormap = p.colormap, colorrange = p.colorrange, - linestyle = p.linestyle, - linewidth = p.linewidth, - inspectable = p.inspectable, - transparency = p.transparency + lift(x -> x[3], data), + color=lift(last, data), + colormap=p.colormap, + colorrange=p.colorrange, + linestyle=p.linestyle, + linewidth=p.linewidth, + inspectable=p.inspectable, + transparency=p.transparency, ) N = ndims(p.limits[]) @@ -194,18 +205,22 @@ function plot!(p::StreamPlot) angle = ifelse(pdir[1] > 0, 2pi - angle, angle) end end - Billboard(angles) + return Billboard(angles) end else rotations = map(x -> x[2], data) end - scatterfun(N)( + return scatterfun(N)( p, - lift(first, data), markersize = p.arrow_size, - marker = @lift(arrow_head(N, $(p.arrow_head), $(p.quality))), - color = lift(x-> x[4], data), rotations = rotations, - colormap = p.colormap, colorrange = p.colorrange, - inspectable = p.inspectable, transparency = p.transparency + lift(first, data), + markersize=p.arrow_size, + marker=@lift(arrow_head(N, $(p.arrow_head), $(p.quality))), + color=lift(x -> x[4], data), + rotations=rotations, + colormap=p.colormap, + colorrange=p.colorrange, + inspectable=p.inspectable, + transparency=p.transparency, ) end diff --git a/src/basic_recipes/text.jl b/src/basic_recipes/text.jl index b22f31c674d..487c9f1fae5 100644 --- a/src/basic_recipes/text.jl +++ b/src/basic_recipes/text.jl @@ -6,11 +6,21 @@ function plot!(plot::Text) linewidths = Observable(Float32[]) linecolors = Observable(RGBAf[]) lineindices = Ref(Int[]) - - onany(plot.text, plot.fontsize, plot.font, plot.fonts, plot.align, - plot.rotation, plot.justification, plot.lineheight, plot.color, - plot.strokecolor, plot.strokewidth, plot.word_wrap_width) do str, - ts, f, fs, al, rot, jus, lh, col, scol, swi, www + + onany( + plot.text, + plot.fontsize, + plot.font, + plot.fonts, + plot.align, + plot.rotation, + plot.justification, + plot.lineheight, + plot.color, + plot.strokecolor, + plot.strokewidth, + plot.word_wrap_width, + ) do str, ts, f, fs, al, rot, jus, lh, col, scol, swi, www ts = to_fontsize(ts) f = to_font(fs, f) rot = to_rotation(rot) @@ -35,8 +45,20 @@ function plot!(plot::Text) # If we have a Vector of strings, Vector arguments are interpreted # as per string. broadcast_foreach( - func, - str, 1:attr_broadcast_length(str), ts, f, fs, al, rot, jus, lh, col, scol, swi, www + func, + str, + 1:attr_broadcast_length(str), + ts, + f, + fs, + al, + rot, + jus, + lh, + col, + scol, + swi, + www, ) else # Otherwise Vector arguments are interpreted by layout_text/ @@ -47,18 +69,24 @@ function plot!(plot::Text) linewidths[] = lwidths linecolors[] = lcolors lineindices[] = lindices - linesegs[] = lsegs + return linesegs[] = lsegs end linesegs_shifted = Observable(Point2f[]) sc = parent_scene(plot) - onany(linesegs, positions, sc.camera.projectionview, sc.px_area, - transform_func_obs(sc), get(plot, :space, :data)) do segs, pos, _, _, transf, space + onany( + linesegs, + positions, + sc.camera.projectionview, + sc.px_area, + transform_func_obs(sc), + get(plot, :space, :data), + ) do segs, pos, _, _, transf, space pos_transf = scene_to_screen(apply_transform(transf, pos, space), sc) linesegs_shifted[] = map(segs, lineindices[]) do seg, index - seg + attr_broadcast_getindex(pos_transf, index) + return seg + attr_broadcast_getindex(pos_transf, index) end end @@ -71,22 +99,50 @@ function plot!(plot::Text) pop!(attrs, :align) pop!(attrs, :color) - t = text!(plot, glyphcollections; attrs..., position = positions) + t = text!(plot, glyphcollections; attrs..., position=positions) # remove attributes that the backends will choke on pop!(t.attributes, :font) pop!(t.attributes, :fonts) - linesegments!(plot, linesegs_shifted; linewidth = linewidths, color = linecolors, space = :pixel) + linesegments!(plot, linesegs_shifted; linewidth=linewidths, color=linecolors, space=:pixel) - plot + return plot end -function _get_glyphcollection_and_linesegments(str::AbstractString, index, ts, f, fs, al, rot, jus, lh, col, scol, swi, www) +function _get_glyphcollection_and_linesegments( + str::AbstractString, + index, + ts, + f, + fs, + al, + rot, + jus, + lh, + col, + scol, + swi, + www, +) gc = layout_text(string(str), ts, f, fs, al, rot, jus, lh, col, scol, swi, www) - gc, Point2f[], Float32[], RGBAf[], Int[] + return gc, Point2f[], Float32[], RGBAf[], Int[] end -function _get_glyphcollection_and_linesegments(latexstring::LaTeXString, index, ts, f, fs, al, rot, jus, lh, col, scol, swi, www) - tex_elements, glyphcollections, offset = texelems_and_glyph_collection(latexstring, ts, - al[1], al[2], rot, col, scol, swi, www) +function _get_glyphcollection_and_linesegments( + latexstring::LaTeXString, + index, + ts, + f, + fs, + al, + rot, + jus, + lh, + col, + scol, + swi, + www, +) + tex_elements, glyphcollections, offset = + texelems_and_glyph_collection(latexstring, ts, al[1], al[2], rot, col, scol, swi, www) linesegs = Point2f[] linewidths = Float32[] @@ -110,20 +166,20 @@ function _get_glyphcollection_and_linesegments(latexstring::LaTeXString, index, end end - glyphcollections, linesegs, linewidths, linecolors, lineindices + return glyphcollections, linesegs, linewidths, linecolors, lineindices end function plot!(plot::Text{<:Tuple{<:AbstractString}}) - text!(plot, plot.position; text = plot[1], plot.attributes...) - plot + text!(plot, plot.position; text=plot[1], plot.attributes...) + return plot end # conversion stopper for previous methods -convert_arguments(::Type{<: Text}, gcs::AbstractVector{<:GlyphCollection}) = (gcs,) -convert_arguments(::Type{<: Text}, gc::GlyphCollection) = (gc,) -convert_arguments(::Type{<: Text}, vec::AbstractVector{<:Tuple{<:AbstractString, <:Point}}) = (vec,) -convert_arguments(::Type{<: Text}, strings::AbstractVector{<:AbstractString}) = (strings,) -convert_arguments(::Type{<: Text}, string::AbstractString) = (string,) +convert_arguments(::Type{<:Text}, gcs::AbstractVector{<:GlyphCollection}) = (gcs,) +convert_arguments(::Type{<:Text}, gc::GlyphCollection) = (gc,) +convert_arguments(::Type{<:Text}, vec::AbstractVector{<:Tuple{<:AbstractString,<:Point}}) = (vec,) +convert_arguments(::Type{<:Text}, strings::AbstractVector{<:AbstractString}) = (strings,) +convert_arguments(::Type{<:Text}, string::AbstractString) = (string,) # TODO: is this necessary? there seems to be a recursive loop with the above # function without these two interceptions, but I didn't need it before merging @@ -132,24 +188,24 @@ plot!(plot::Text{<:Tuple{<:GlyphCollection}}) = plot plot!(plot::Text{<:Tuple{<:AbstractArray{<:GlyphCollection}}}) = plot function plot!(plot::Text{<:Tuple{<:AbstractArray{<:AbstractString}}}) - text!(plot, plot.position; text = plot[1], plot.attributes...) - plot + text!(plot, plot.position; text=plot[1], plot.attributes...) + return plot end # overload text plotting for a vector of tuples of a string and a point each -function plot!(plot::Text{<:Tuple{<:AbstractArray{<:Tuple{<:AbstractString, <:Point}}}}) +function plot!(plot::Text{<:Tuple{<:AbstractArray{<:Tuple{<:AbstractString,<:Point}}}}) strings_and_positions = plot[1] strings = Observable{Vector{AbstractString}}(first.(strings_and_positions[])) positions = Observable( - Point3f[to_ndim(Point3f, last(x), 0) for x in strings_and_positions[]] # avoid Any for zero elements + Point3f[to_ndim(Point3f, last(x), 0) for x in strings_and_positions[]], # avoid Any for zero elements ) attrs = plot.attributes pop!(attrs, :position) - text!(plot, positions; text = strings, attrs...) + text!(plot, positions; text=strings, attrs...) # update both text and positions together on(strings_and_positions) do str_pos @@ -161,12 +217,20 @@ function plot!(plot::Text{<:Tuple{<:AbstractArray{<:Tuple{<:AbstractString, <:Po return end - plot + return plot end -function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, valign, - rotation, color, strokecolor, strokewidth, word_wrap_width) - +function texelems_and_glyph_collection( + str::LaTeXString, + fontscale_px, + halign, + valign, + rotation, + color, + strokecolor, + strokewidth, + word_wrap_width, +) rot = convert_attribute(rotation, key"rotation"()) all_els = generate_tex_elements(str) @@ -184,10 +248,7 @@ function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, v bboxes = map(extents, scales_2d) do ext, scale unscaled_hi_bb = height_insensitive_boundingbox_with_advance(ext) - return Rect2f( - origin(unscaled_hi_bb) * scale, - widths(unscaled_hi_bb) * scale - ) + return Rect2f(origin(unscaled_hi_bb) * scale, widths(unscaled_hi_bb) * scale) end basepositions = [to_ndim(Vec3f, fs, 0) .* to_ndim(Point3f, x[2], 0) for x in els] @@ -195,7 +256,7 @@ function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, v if word_wrap_width > 0 last_space_idx = 0 last_newline_idx = 1 - newline_offset = Point3f(basepositions[1][1], 0f0, 0) + newline_offset = Point3f(basepositions[1][1], 0.0f0, 0) for i in eachindex(texchars) basepositions[i] -= newline_offset @@ -204,12 +265,12 @@ function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, v if last_space_idx != 0 && right_pos > word_wrap_width section_offset = basepositions[last_space_idx + 1][1] lineheight = maximum((height(bb) for bb in bboxes[last_newline_idx:last_space_idx])) - last_newline_idx = last_space_idx+1 + last_newline_idx = last_space_idx + 1 newline_offset += Point3f(section_offset, lineheight, 0) # TODO: newlines don't really need to represented at all? # chars[last_space_idx] = '\n' - for j in last_space_idx+1:i + for j in (last_space_idx + 1):i basepositions[j] -= Point3f(section_offset, lineheight, 0) end end @@ -222,7 +283,7 @@ function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, v bb = isempty(bboxes) ? BBox(0, 0, 0, 0) : begin mapreduce(union, zip(bboxes, basepositions)) do (b, pos) - Rect2f(Rect3f(b) + pos) + return Rect2f(Rect3f(b) + pos) end end @@ -255,10 +316,10 @@ function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, v rot, color, strokecolor, - strokewidth + strokewidth, ) - all_els, pre_align_gl, Point2f(xshift, yshift) + return all_els, pre_align_gl, Point2f(xshift, yshift) end iswhitespace(l::LaTeXString) = iswhitespace(replace(l.s, '$' => "")) @@ -266,11 +327,11 @@ iswhitespace(l::LaTeXString) = iswhitespace(replace(l.s, '$' => "")) struct RichText <: AbstractString type::Symbol children::Vector{Union{RichText,String}} - attributes::Dict{Symbol, Any} + attributes::Dict{Symbol,Any} function RichText(type::Symbol, children...; kwargs...) cs = Union{RichText,String}[children...] typeof(cs) - new(type, cs, Dict(kwargs)) + return new(type, cs, Dict(kwargs)) end end @@ -278,18 +339,16 @@ function Base.String(r::RichText) fn(io, x::RichText) = foreach(x -> fn(io, x), x.children) fn(io, s::String) = print(io, s) sprint() do io - fn(io, r) + return fn(io, r) end end Base.ncodeunits(r::RichText) = ncodeunits(String(r)) # needed for isempty -function Base.show(io::IO, ::MIME"text/plain", r::RichText) - print(io, "RichText: \"$(String(r))\"") -end +Base.show(io::IO, ::MIME"text/plain", r::RichText) = print(io, "RichText: \"$(String(r))\"") function Base.:(==)(r1::RichText, r2::RichText) - r1.type == r2.type && r1.children == r2.children && r1.attributes == r2.attributes + return r1.type == r2.type && r1.children == r2.children && r1.attributes == r2.attributes end rich(args...; kwargs...) = RichText(:span, args...; kwargs...) @@ -298,9 +357,23 @@ superscript(args...; kwargs...) = RichText(:sup, args...; kwargs...) export rich, subscript, superscript -function _get_glyphcollection_and_linesegments(rt::RichText, index, ts, f, fset, al, rot, jus, lh, col, scol, swi, www) +function _get_glyphcollection_and_linesegments( + rt::RichText, + index, + ts, + f, + fset, + al, + rot, + jus, + lh, + col, + scol, + swi, + www, +) gc = layout_text(rt, ts, f, fset, al, rot, jus, lh, col) - gc, Point2f[], Float32[], RGBAf[], Int[] + return gc, Point2f[], Float32[], RGBAf[], Int[] end struct GlyphState @@ -324,7 +397,7 @@ struct GlyphInfo end function GlyphCollection(v::Vector{GlyphInfo}) - GlyphCollection( + return GlyphCollection( [i.glyph for i in v], [i.font for i in v], [Point3f(i.origin..., 0) for i in v], @@ -337,15 +410,13 @@ function GlyphCollection(v::Vector{GlyphInfo}) ) end - function layout_text(rt::RichText, ts, f, fset, al, rot, jus, lh, col) - _f = to_font(fset, f) stack = [GlyphState(0, 0, Vec2f(ts), _f, to_color(col))] lines = [GlyphInfo[]] - + process_rt_node!(stack, lines, rt, fset) apply_lineheight!(lines, lh) @@ -356,14 +427,14 @@ function layout_text(rt::RichText, ts, f, fset, al, rot, jus, lh, col) gc.origins .= Ref(quat) .* gc.origins @assert gc.rotations.sv isa Vector # should always be a vector because that's how the glyphcollection is created gc.rotations.sv .= Ref(quat) .* gc.rotations.sv - gc + return gc end function apply_lineheight!(lines, lh) for (i, line) in enumerate(lines) for j in eachindex(line) l = line[j] - l = Setfield.@set l.origin[2] -= (i-1) * 20 # TODO: Lineheight + l = Setfield.@set l.origin[2] -= (i - 1) * 20 # TODO: Lineheight line[j] = l end end @@ -372,27 +443,27 @@ end function apply_alignment_and_justification!(lines, ju, al) max_xs = map(lines) do line - maximum(line, init = 0f0) do ginfo - ginfo.origin[1] + ginfo.extent.hadvance * ginfo.size[1] + maximum(line, init=0.0f0) do ginfo + return ginfo.origin[1] + ginfo.extent.hadvance * ginfo.size[1] end end max_x = maximum(max_xs) top_y = maximum(lines[1]) do ginfo - ginfo.origin[2] + ginfo.extent.ascender * ginfo.size[2] + return ginfo.origin[2] + ginfo.extent.ascender * ginfo.size[2] end bottom_y = minimum(lines[end]) do ginfo - ginfo.origin[2] + ginfo.extent.descender * ginfo.size[2] + return ginfo.origin[2] + ginfo.extent.descender * ginfo.size[2] end al_offset_x = if al[1] == :center max_x / 2 elseif al[1] == :left - 0f0 + 0.0f0 elseif al[1] == :right max_x else - 0f0 + 0.0f0 end al_offset_y = if al[2] == :center @@ -402,11 +473,11 @@ function apply_alignment_and_justification!(lines, ju, al) elseif al[2] == :top top_y else - 0f0 + 0.0f0 end fju = float_justification(ju, al) - + for (i, line) in enumerate(lines) ju_offset = fju * (max_x - max_xs[i]) for j in eachindex(line) @@ -420,7 +491,7 @@ end function float_justification(ju, al)::Float32 halign = al[1] - float_justification = if ju === automatic + return float_justification = if ju === automatic if halign == :left || halign == 0 0.0f0 elseif halign == :right || halign == 1 @@ -468,17 +539,20 @@ function process_rt_node!(stack, lines, s::String, _) gi = FreeTypeAbstraction.glyph_index(gs.font, char) gext = GlyphExtent(gs.font, char) ori = Point2f(x, y) - push!(lines[end], GlyphInfo( - gi, - gs.font, - ori, - gext, - gs.size, - to_rotation(0), - gs.color, - RGBAf(0, 0, 0, 0), - 0f0, - )) + push!( + lines[end], + GlyphInfo( + gi, + gs.font, + ori, + gext, + gs.size, + to_rotation(0), + gs.color, + RGBAf(0, 0, 0, 0), + 0.0f0, + ), + ) x = x + gext.hadvance * gs.size[1] end end @@ -486,20 +560,20 @@ function process_rt_node!(stack, lines, s::String, _) return end -function new_glyphstate(gs::GlyphState, rt::RichText, val::Val, fonts) - gs -end +new_glyphstate(gs::GlyphState, rt::RichText, val::Val, fonts) = gs _get_color(attributes, default)::RGBAf = haskey(attributes, :color) ? to_color(attributes[:color]) : default -_get_font(attributes, default::NativeFont, fonts)::NativeFont = haskey(attributes, :font) ? to_font(fonts, attributes[:font]) : default -_get_fontsize(attributes, default)::Vec2f = haskey(attributes, :fontsize) ? Vec2f(to_fontsize(attributes[:fontsize])) : default +_get_font(attributes, default::NativeFont, fonts)::NativeFont = + haskey(attributes, :font) ? to_font(fonts, attributes[:font]) : default +_get_fontsize(attributes, default)::Vec2f = + haskey(attributes, :fontsize) ? Vec2f(to_fontsize(attributes[:fontsize])) : default _get_offset(attributes, default)::Vec2f = haskey(attributes, :offset) ? Vec2f(attributes[:offset]) : default function new_glyphstate(gs::GlyphState, rt::RichText, val::Val{:sup}, fonts) att = rt.attributes fontsize = _get_fontsize(att, gs.size * 0.66) offset = _get_offset(att, Vec2f(0)) .* fontsize - GlyphState( + return GlyphState( gs.x + offset[1], gs.baseline + 0.4 * gs.size[2] + offset[2], fontsize, @@ -512,7 +586,7 @@ function new_glyphstate(gs::GlyphState, rt::RichText, val::Val{:span}, fonts) att = rt.attributes fontsize = _get_fontsize(att, gs.size) offset = _get_offset(att, Vec2f(0)) .* fontsize - GlyphState( + return GlyphState( gs.x + offset[1], gs.baseline + offset[2], fontsize, @@ -525,7 +599,7 @@ function new_glyphstate(gs::GlyphState, rt::RichText, val::Val{:sub}, fonts) att = rt.attributes fontsize = _get_fontsize(att, gs.size * 0.66) offset = _get_offset(att, Vec2f(0)) .* fontsize - GlyphState( + return GlyphState( gs.x + offset[1], gs.baseline - 0.15 * gs.size[2] + offset[2], fontsize, diff --git a/src/basic_recipes/timeseries.jl b/src/basic_recipes/timeseries.jl index 7e7fc9ca8ed..6449e6abb99 100644 --- a/src/basic_recipes/timeseries.jl +++ b/src/basic_recipes/timeseries.jl @@ -21,10 +21,7 @@ end ``` """ @recipe(TimeSeries, signal) do scene - Attributes( - history = 100; - default_theme(scene, Lines)... - ) + return Attributes(history=100; default_theme(scene, Lines)...) end signal2point(signal::Number, start) = Point2f(time() - start, signal) @@ -33,7 +30,6 @@ signal2point(signal, start) = error(""" Signal needs to be of type Number or Poi Found: $(typeof(signal)) """) - function Makie.plot!(plot::TimeSeries) # normal plotting code, building on any previously defined recipes # or atomic plotting operations, and adding to the combined `plot`: @@ -46,7 +42,7 @@ function Makie.plot!(plot::TimeSeries) circshift!(buffer, points[], 1) buff_ref = buffer buffer = points[] - points[] = buff_ref + return points[] = buff_ref end - plot + return plot end diff --git a/src/basic_recipes/tooltip.jl b/src/basic_recipes/tooltip.jl index 01b88fbe9fd..751637c8b3c 100644 --- a/src/basic_recipes/tooltip.jl +++ b/src/basic_recipes/tooltip.jl @@ -35,56 +35,55 @@ Creates a tooltip pointing at `position` displaying the given `string` - `justification = :left` sets whether text is aligned to the `:left`, `:center` or `:right` within its bounding box. """ @recipe(Tooltip, position) do scene - Attributes(; + return Attributes(; # General - text = "", - offset = 10, - placement = :above, - align = 0.5, - xautolimits = false, - yautolimits = false, - zautolimits = false, - overdraw = false, - depth_shift = 0f0, - transparency = false, - visible = true, - inspectable = false, + text="", + offset=10, + placement=:above, + align=0.5, + xautolimits=false, + yautolimits=false, + zautolimits=false, + overdraw=false, + depth_shift=0.0f0, + transparency=false, + visible=true, + inspectable=false, # Text - textpadding = (4, 4, 4, 4), # LRBT - textcolor = theme(scene, :textcolor), - fontsize = 16, - font = theme(scene, :font), - strokewidth = 0, - strokecolor = :white, - justification = :left, + textpadding=(4, 4, 4, 4), # LRBT + textcolor=theme(scene, :textcolor), + fontsize=16, + font=theme(scene, :font), + strokewidth=0, + strokecolor=:white, + justification=:left, # Background - backgroundcolor = :white, - triangle_size = 10, - + backgroundcolor=:white, + triangle_size=10, + # Outline - outline_color = :black, - outline_linewidth = 2f0, - outline_linestyle = nothing, + outline_color=:black, + outline_linewidth=2.0f0, + outline_linestyle=nothing, ) end -convert_arguments(::Type{<: Tooltip}, x::Real, y::Real, str::AbstractString) = (Point2f(x, y), str) -convert_arguments(::Type{<: Tooltip}, x::Real, y::Real) = (Point2f(x, y),) -function plot!(plot::Tooltip{<:Tuple{<:VecTypes, <:AbstractString}}) - plot.attributes[:text] = plot[2] +convert_arguments(::Type{<:Tooltip}, x::Real, y::Real, str::AbstractString) = (Point2f(x, y), str) +convert_arguments(::Type{<:Tooltip}, x::Real, y::Real) = (Point2f(x, y),) +function plot!(plot::Tooltip{<:Tuple{<:VecTypes,<:AbstractString}}) + plot.attributes[:text] = plot[2] tooltip!(plot, plot[1]; plot.attributes...) - plot + return plot end - function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) # TODO align scene = parent_scene(p) px_pos = map(scene.camera.projectionview, scene.camera.resolution, p[1]) do _, _, p - project(scene, p) + return project(scene, p) end # Text @@ -100,25 +99,26 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) end end - text_offset = map(p.offset, textpadding, p.triangle_size, p.placement, p.align) do o, pad, ts, placement, align - l, r, b, t = pad - - if placement == :left - return Vec2f(-o - r - ts, b - align * (b + t)) - elseif placement == :right - return Vec2f( o + l + ts, b - align * (b + t)) - elseif placement in (:below, :down, :bottom) - return Vec2f(l - align * (l + r), -o - t - ts) - elseif placement in (:above, :up, :top) - return Vec2f(l - align * (l + r), o + b + ts) - else - @error "Tooltip placement $placement invalid. Assuming :above" - return Vec2f(0, o + b + ts) + text_offset = + map(p.offset, textpadding, p.triangle_size, p.placement, p.align) do o, pad, ts, placement, align + l, r, b, t = pad + + if placement == :left + return Vec2f(-o - r - ts, b - align * (b + t)) + elseif placement == :right + return Vec2f(o + l + ts, b - align * (b + t)) + elseif placement in (:below, :down, :bottom) + return Vec2f(l - align * (l + r), -o - t - ts) + elseif placement in (:above, :up, :top) + return Vec2f(l - align * (l + r), o + b + ts) + else + @error "Tooltip placement $placement invalid. Assuming :above" + return Vec2f(0, o + b + ts) + end end - end text_align = map(p.placement, p.align) do placement, align - if placement == :left + if placement == :left return (1.0, align) elseif placement == :right return (0.0, align) @@ -133,69 +133,87 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) end tp = text!( - p, px_pos, text = p.text, justification = p.justification, - align = text_align, offset = text_offset, fontsize = p.fontsize, - color = p.textcolor, font = p.font, fxaa = false, - strokewidth = p.strokewidth, strokecolor = p.strokecolor, - transparency = p.transparency, visible = p.visible, - overdraw = p.overdraw, depth_shift = p.depth_shift, - inspectable = p.inspectable, space = :pixel + p, + px_pos, + text=p.text, + justification=p.justification, + align=text_align, + offset=text_offset, + fontsize=p.fontsize, + color=p.textcolor, + font=p.font, + fxaa=false, + strokewidth=p.strokewidth, + strokecolor=p.strokecolor, + transparency=p.transparency, + visible=p.visible, + overdraw=p.overdraw, + depth_shift=p.depth_shift, + inspectable=p.inspectable, + space=:pixel, ) translate!(tp, 0, 0, 1) # TODO react to glyphcollection instead - bbox = map( - px_pos, p.text, text_align, text_offset, textpadding, p.align - ) do p, s, _, o, pad, align + bbox = map(px_pos, p.text, text_align, text_offset, textpadding, p.align) do p, s, _, o, pad, align bb = Rect2f(boundingbox(tp)) + o l, r, b, t = pad - return Rect2f(origin(bb) .- (l, b), widths(bb) .+ (l+r, b+t)) + return Rect2f(origin(bb) .- (l, b), widths(bb) .+ (l + r, b + t)) end # Text background mesh mesh!( - p, bbox, shading = false, space = :pixel, - color = p.backgroundcolor, fxaa = false, - transparency = p.transparency, visible = p.visible, - overdraw = p.overdraw, depth_shift = p.depth_shift, - inspectable = p.inspectable + p, + bbox, + shading=false, + space=:pixel, + color=p.backgroundcolor, + fxaa=false, + transparency=p.transparency, + visible=p.visible, + overdraw=p.overdraw, + depth_shift=p.depth_shift, + inspectable=p.inspectable, ) # Triangle mesh - triangle = GeometryBasics.Mesh( - Point2f[(-0.5, 0), (0.5, 0), (0, -1)], - GLTriangleFace[(1,2,3)] - ) + triangle = GeometryBasics.Mesh(Point2f[(-0.5, 0), (0.5, 0), (0, -1)], GLTriangleFace[(1, 2, 3)]) mp = mesh!( - p, triangle, shading = false, space = :pixel, - color = p.backgroundcolor, - transparency = p.transparency, visible = p.visible, - overdraw = p.overdraw, depth_shift = p.depth_shift, - inspectable = p.inspectable + p, + triangle, + shading=false, + space=:pixel, + color=p.backgroundcolor, + transparency=p.transparency, + visible=p.visible, + overdraw=p.overdraw, + depth_shift=p.depth_shift, + inspectable=p.inspectable, ) onany(bbox, p.triangle_size, p.placement, p.align) do bb, s, placement, align - o = origin(bb); w = widths(bb) + o = origin(bb) + w = widths(bb) scale!(mp, s, s, s) - - if placement == :left + + if placement == :left translate!(mp, Vec3f(o[1] + w[1], o[2] + align * w[2], 0)) - rotate!(mp, qrotation(Vec3f(0,0,1), 0.5pi)) + rotate!(mp, qrotation(Vec3f(0, 0, 1), 0.5pi)) elseif placement == :right translate!(mp, Vec3f(o[1], o[2] + align * w[2], 0)) - rotate!(mp, qrotation(Vec3f(0,0,1), -0.5pi)) + rotate!(mp, qrotation(Vec3f(0, 0, 1), -0.5pi)) elseif placement in (:below, :down, :bottom) translate!(mp, Vec3f(o[1] + align * w[1], o[2] + w[2], 0)) - rotate!(mp, Quaternionf(0,0,1,0)) # pi + rotate!(mp, Quaternionf(0, 0, 1, 0)) # pi elseif placement in (:above, :up, :top) translate!(mp, Vec3f(o[1] + align * w[1], o[2], 0)) - rotate!(mp, Quaternionf(0,0,0,1)) # 0 + rotate!(mp, Quaternionf(0, 0, 0, 1)) # 0 else @error "Tooltip placement $placement invalid. Assuming :above" translate!(mp, Vec3f(o[1] + align * w[1], o[2], 0)) - rotate!(mp, Quaternionf(0,0,0,1)) + rotate!(mp, Quaternionf(0, 0, 0, 1)) end return end @@ -203,7 +221,8 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) # Outline outline = map(bbox, p.triangle_size, p.placement, p.align) do bb, s, placement, align - l, b = origin(bb); w, h = widths(bb) + l, b = origin(bb) + w, h = widths(bb) r, t = (l, b) .+ (w, h) # We start/end at half width/height here to avoid corners like this: @@ -212,46 +231,66 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) # | ____ # | | - shift = if placement == :left + shift = if placement == :left Vec2f[ - (l, b + 0.5h), (l, t), (r, t), - (r, b + align * h + 0.5s), - (r + s, b + align * h), - (r, b + align * h - 0.5s), - (r, b), (l, b), (l, b + 0.5h) + (l, b + 0.5h), + (l, t), + (r, t), + (r, b + align * h + 0.5s), + (r + s, b + align * h), + (r, b + align * h - 0.5s), + (r, b), + (l, b), + (l, b + 0.5h), ] elseif placement == :right Vec2f[ - (l + 0.5w, b), (l, b), - (l, b + align * h - 0.5s), - (l-s, b + align * h), - (l, b + align * h + 0.5s), - (l, t), (r, t), (r, b), (l + 0.5w, b) + (l + 0.5w, b), + (l, b), + (l, b + align * h - 0.5s), + (l - s, b + align * h), + (l, b + align * h + 0.5s), + (l, t), + (r, t), + (r, b), + (l + 0.5w, b), ] elseif placement in (:below, :down, :bottom) Vec2f[ - (l, b + 0.5h), (l, t), - (l + align * w - 0.5s, t), - (l + align * w, t+s), - (l + align * w + 0.5s, t), - (r, t), (r, b), (l, b), (l, b + 0.5h) + (l, b + 0.5h), + (l, t), + (l + align * w - 0.5s, t), + (l + align * w, t + s), + (l + align * w + 0.5s, t), + (r, t), + (r, b), + (l, b), + (l, b + 0.5h), ] elseif placement in (:above, :up, :top) Vec2f[ - (l, b + 0.5h), (l, t), (r, t), (r, b), - (l + align * w + 0.5s, b), - (l + align * w, b-s), - (l + align * w - 0.5s, b), - (l, b), (l, b + 0.5h) + (l, b + 0.5h), + (l, t), + (r, t), + (r, b), + (l + align * w + 0.5s, b), + (l + align * w, b - s), + (l + align * w - 0.5s, b), + (l, b), + (l, b + 0.5h), ] else @error "Tooltip placement $placement invalid. Assuming :above" Vec2f[ - (l, b + 0.5h), (l, t), (r, t), (r, b), - (l + align * w + 0.5s, b), - (l + align * w, b-s), - (l + align * w - 0.5s, b), - (l, b), (l, b + 0.5h) + (l, b + 0.5h), + (l, t), + (r, t), + (r, b), + (l + align * w + 0.5s, b), + (l + align * w, b - s), + (l + align * w - 0.5s, b), + (l, b), + (l, b + 0.5h), ] end @@ -259,15 +298,20 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}}) end lines!( - p, outline, - color = p.outline_color, space = :pixel, - linewidth = p.outline_linewidth, linestyle = p.outline_linestyle, - transparency = p.transparency, visible = p.visible, - overdraw = p.overdraw, depth_shift = p.depth_shift, - inspectable = p.inspectable + p, + outline, + color=p.outline_color, + space=:pixel, + linewidth=p.outline_linewidth, + linestyle=p.outline_linestyle, + transparency=p.transparency, + visible=p.visible, + overdraw=p.overdraw, + depth_shift=p.depth_shift, + inspectable=p.inspectable, ) notify(p[1]) return p -end \ No newline at end of file +end diff --git a/src/basic_recipes/tricontourf.jl b/src/basic_recipes/tricontourf.jl index deef1fc3e49..a62fd591eec 100644 --- a/src/basic_recipes/tricontourf.jl +++ b/src/basic_recipes/tricontourf.jl @@ -32,21 +32,26 @@ and vertical positions `ys`. $(ATTRIBUTES) """ @recipe(Tricontourf) do scene - Theme( - levels = 10, - mode = :normal, - colormap = theme(scene, :colormap), - extendlow = nothing, - extendhigh = nothing, - nan_color = :transparent, - inspectable = theme(scene, :inspectable), - transparency = false, - triangulation = DelaunayTriangulation() + return Theme( + levels=10, + mode=:normal, + colormap=theme(scene, :colormap), + extendlow=nothing, + extendhigh=nothing, + nan_color=:transparent, + inspectable=theme(scene, :inspectable), + transparency=false, + triangulation=DelaunayTriangulation(), ) end -function Makie.convert_arguments(::Type{<:Tricontourf}, x::AbstractVector{<:Real}, y::AbstractVector{<:Real}, z::AbstractVector{<:Real}) - map(x -> elconvert(Float32, x), (x, y, z)) +function Makie.convert_arguments( + ::Type{<:Tricontourf}, + x::AbstractVector{<:Real}, + y::AbstractVector{<:Real}, + z::AbstractVector{<:Real}, +) + return map(x -> elconvert(Float32, x), (x, y, z)) end function compute_contourf_colormap(levels, cmap, elow, ehigh) @@ -70,7 +75,7 @@ function compute_contourf_colormap(levels, cmap, elow, ehigh) return cm end -function compute_lowcolor(el, cmap) +compute_lowcolor(el, cmap) = if isnothing(el) return RGBAf(0, 0, 0, 0) elseif el === automatic || el == :auto @@ -78,9 +83,8 @@ function compute_lowcolor(el, cmap) else return to_color(el)::RGBAf end -end -function compute_highcolor(eh, cmap) +compute_highcolor(eh, cmap) = if isnothing(eh) return RGBAf(0, 0, 0, 0) elseif eh === automatic || eh == :auto @@ -88,20 +92,21 @@ function compute_highcolor(eh, cmap) else return to_color(eh)::RGBAf end -end -function Makie.plot!(c::Tricontourf{<:Tuple{<:AbstractVector{<:Real},<:AbstractVector{<:Real},<:AbstractVector{<:Real}}}) +function Makie.plot!( + c::Tricontourf{<:Tuple{<:AbstractVector{<:Real},<:AbstractVector{<:Real},<:AbstractVector{<:Real}}}, +) xs, ys, zs = c[1:3] c.attributes[:_computed_levels] = lift(zs, c.levels, c.mode) do zs, levels, mode - _get_isoband_levels(Val(mode), levels, vec(zs)) + return _get_isoband_levels(Val(mode), levels, vec(zs)) end colorrange = lift(c._computed_levels) do levels - minimum(levels), maximum(levels) + return minimum(levels), maximum(levels) end - computed_colormap = lift(compute_contourf_colormap, c._computed_levels, c.colormap, c.extendlow, - c.extendhigh) + computed_colormap = + lift(compute_contourf_colormap, c._computed_levels, c.colormap, c.extendlow, c.extendhigh) c.attributes[:_computed_colormap] = computed_colormap lowcolor = Observable{RGBAf}() @@ -119,7 +124,15 @@ function Makie.plot!(c::Tricontourf{<:Tuple{<:AbstractVector{<:Real},<:AbstractV polys = Observable(PolyType[]) colors = Observable(Float64[]) - function calculate_polys(xs, ys, zs, levels::Vector{Float32}, is_extended_low, is_extended_high, triangulation) + function calculate_polys( + xs, + ys, + zs, + levels::Vector{Float32}, + is_extended_low, + is_extended_high, + triangulation, + ) empty!(polys[]) empty!(colors[]) @@ -130,7 +143,7 @@ function Makie.plot!(c::Tricontourf{<:Tuple{<:AbstractVector{<:Real},<:AbstractV @assert issorted(levels) is_extended_low && pushfirst!(levels, -Inf) is_extended_high && push!(levels, Inf) - lows = levels[1:end-1] + lows = levels[1:(end - 1)] highs = levels[2:end] trianglelist = compute_triangulation(triangulation, xs, ys) @@ -140,12 +153,12 @@ function Makie.plot!(c::Tricontourf{<:Tuple{<:AbstractVector{<:Real},<:AbstractV for (fc, lc) in zip(filledcontours, levelcenters) pointvecs = map(fc.polylines) do vecs - map(Point2f, vecs) + return map(Point2f, vecs) end if isempty(pointvecs) continue end - + for pointvec in pointvecs p = Makie.Polygon(pointvec) push!(polys[], p) @@ -159,21 +172,30 @@ function Makie.plot!(c::Tricontourf{<:Tuple{<:AbstractVector{<:Real},<:AbstractV onany(calculate_polys, xs, ys, zs, c._computed_levels, is_extended_low, is_extended_high, c.triangulation) # onany doesn't get called without a push, so we call # it on a first run! - calculate_polys(xs[], ys[], zs[], c._computed_levels[], is_extended_low[], is_extended_high[], c.triangulation[]) + calculate_polys( + xs[], + ys[], + zs[], + c._computed_levels[], + is_extended_low[], + is_extended_high[], + c.triangulation[], + ) - poly!(c, + return poly!( + c, polys, - colormap = c._computed_colormap, - colorrange = colorrange, - highclip = highcolor, - lowclip = lowcolor, - nan_color = c.nan_color, - color = colors, - strokewidth = 0, - strokecolor = :transparent, - shading = false, - inspectable = c.inspectable, - transparency = c.transparency + colormap=c._computed_colormap, + colorrange=colorrange, + highclip=highcolor, + lowclip=lowcolor, + nan_color=c.nan_color, + color=colors, + strokewidth=0, + strokecolor=:transparent, + shading=false, + inspectable=c.inspectable, + transparency=c.transparency, ) end @@ -184,25 +206,29 @@ end function compute_triangulation(triangulation::AbstractMatrix{<:Int}, xs, ys) if size(triangulation, 1) != 3 - throw(ArgumentError("Triangulation matrix must be of size (3, n) but is of size $(size(triangulation)).")) + throw( + ArgumentError( + "Triangulation matrix must be of size (3, n) but is of size $(size(triangulation)).", + ), + ) end - triangulation + return triangulation end # FIXME: TriplotBase augments levels so here the implementation is just repeated without that step function filled_tricontours(x, y, z, t, levels) m = TriplotBase.TriMesh(x, y, t) - filled_tricontours(m, z, levels) + return filled_tricontours(m, z, levels) end function filled_tricontours(m::TriplotBase.TriMesh, z, levels) @assert issorted(levels) nlevels = length(levels) filled_contours = TriplotBase.FilledContour{eltype(levels)}[] - for i=1:nlevels-1 + for i in 1:(nlevels - 1) lower = levels[i] - upper = levels[i+1] + upper = levels[i + 1] push!(filled_contours, TriplotBase.generate_filled_contours(m, z, lower, upper)) end - filled_contours + return filled_contours end diff --git a/src/basic_recipes/volumeslices.jl b/src/basic_recipes/volumeslices.jl index a43598099b5..3ec10f103be 100644 --- a/src/basic_recipes/volumeslices.jl +++ b/src/basic_recipes/volumeslices.jl @@ -10,17 +10,17 @@ Draws heatmap slices of the volume v $(ATTRIBUTES) """ @recipe(VolumeSlices, x, y, z, volume) do scene - Attributes(; + return Attributes(; default_theme(scene, Heatmap)..., - bbox_visible = true, - bbox_color = RGBAf(0.5, 0.5, 0.5, 0.5) + bbox_visible=true, + bbox_color=RGBAf(0.5, 0.5, 0.5, 0.5), ) end function plot!(plot::VolumeSlices) @extract plot (x, y, z, volume) replace_automatic!(plot, :colorrange) do - map(extrema, volume) + return map(extrema, volume) end # heatmap will fail if we don't keep its attributes clean @@ -33,25 +33,23 @@ function plot!(plot::VolumeSlices) mx, Mx = extrema(x) my, My = extrema(y) mz, Mz = extrema(z) - Rect3(mx, my, mz, Mx-mx, My-my, Mz-mz) + return Rect3(mx, my, mz, Mx - mx, My - my, Mz - mz) end axes = :x, :y, :z - for (ax, p, r, (X, Y)) ∈ zip(axes, (:yz, :xz, :xy), (x, y, z), ((y, z), (x, z), (x, y))) - plot[Symbol(:heatmap_, p)] = hmap = heatmap!( - plot, attr, X, Y, zeros(length(X[]), length(Y[])) - ) + for (ax, p, r, (X, Y)) in zip(axes, (:yz, :xz, :xy), (x, y, z), ((y, z), (x, z), (x, y))) + plot[Symbol(:heatmap_, p)] = hmap = heatmap!(plot, attr, X, Y, zeros(length(X[]), length(Y[]))) plot[Symbol(:update_, p)] = update = i -> begin transform!(hmap, (p, r[][i])) indices = ntuple(Val(3)) do j - axes[j] == ax ? i : (:) + return axes[j] == ax ? i : (:) end hmap[3][] = view(volume[], indices...) end update(1) # trigger once to place heatmaps correctly end - linesegments!(plot, bbox, color = bbox_color, visible = bbox_visible, inspectable = false) + linesegments!(plot, bbox, color=bbox_color, visible=bbox_visible, inspectable=false) - plot + return plot end diff --git a/src/basic_recipes/waterfall.jl b/src/basic_recipes/waterfall.jl index 04667aba03a..633840e2c55 100644 --- a/src/basic_recipes/waterfall.jl +++ b/src/basic_recipes/waterfall.jl @@ -67,28 +67,11 @@ function Makie.plot!(p::Waterfall) ) end - barplot!( - p, - lift(x -> x.xy, fromto); - p.attributes..., - fillto=lift(x -> x.fillto, fromto), - stack=automatic, - ) + barplot!(p, lift(x -> x.xy, fromto); p.attributes..., fillto=lift(x -> x.fillto, fromto), stack=automatic) if p.show_direction[] - function direction_markers( - fromto, - marker_pos, - marker_neg, - width, - gap, - dodge, - n_dodge, - dodge_gap, - ) - xs = first( - compute_x_and_width(first.(fromto.xy), width, gap, dodge, n_dodge, dodge_gap) - ) + function direction_markers(fromto, marker_pos, marker_neg, width, gap, dodge, n_dodge, dodge_gap) + xs = first(compute_x_and_width(first.(fromto.xy), width, gap, dodge, n_dodge, dodge_gap)) xy = similar(fromto.xy) shapes = fill(marker_pos, length(xs)) for i in eachindex(xs) @@ -114,11 +97,7 @@ function Makie.plot!(p::Waterfall) p.dodge_gap, ) - scatter!( - p, - lift(x -> x.xy, markers); - marker=lift(x -> x.shapes, markers), - color=p.direction_color) + scatter!(p, lift(x -> x.xy, markers); marker=lift(x -> x.shapes, markers), color=p.direction_color) end return p diff --git a/src/basic_recipes/wireframe.jl b/src/basic_recipes/wireframe.jl index 374a2f4464c..fcdb3ffa99c 100644 --- a/src/basic_recipes/wireframe.jl +++ b/src/basic_recipes/wireframe.jl @@ -15,8 +15,8 @@ See [`wireframe`](@ref). """ wireframe! -function convert_arguments(::Type{<: Wireframe}, x::AbstractVector, y::AbstractVector, z::AbstractMatrix) - (ngrid(x, y)..., z) +function convert_arguments(::Type{<:Wireframe}, x::AbstractVector, y::AbstractVector, z::AbstractMatrix) + return (ngrid(x, y)..., z) end xvector(x::AbstractVector, len) = x @@ -26,19 +26,19 @@ xvector(x::AbstractMatrix, len) = x yvector(x, len) = xvector(x, len)' yvector(x::AbstractMatrix, len) = x -function plot!(plot::Wireframe{<: Tuple{<: Any, <: Any, <: AbstractMatrix}}) +function plot!(plot::Wireframe{<:Tuple{<:Any,<:Any,<:AbstractMatrix}}) points_faces = lift(plot[1:3]...) do x, y, z M, N = size(z) points = vec(Point3f.(xvector(x, M), yvector(y, N), z)) # Connect the vetices with faces, as one would use for a 2D Rectangle # grid with M,N grid points faces = decompose(LineFace{GLIndex}, Tesselation(Rect2(0, 0, 1, 1), (M, N))) - connect(points, faces) + return connect(points, faces) end - linesegments!(plot, Attributes(plot), points_faces) + return linesegments!(plot, Attributes(plot), points_faces) end -function plot!(plot::Wireframe{Tuple{T}}) where T +function plot!(plot::Wireframe{Tuple{T}}) where {T} points = lift(plot[1]) do g # get the point representation of the geometry indices = decompose(LineFace{GLIndex}, g) @@ -50,5 +50,5 @@ function plot!(plot::Wireframe{Tuple{T}}) where T return connect(points, indices) end end - linesegments!(plot, Attributes(plot), points) + return linesegments!(plot, Attributes(plot), points) end diff --git a/src/bezier.jl b/src/bezier.jl index 924f0d675bc..ebfa0315a0b 100644 --- a/src/bezier.jl +++ b/src/bezier.jl @@ -18,9 +18,7 @@ struct CurveTo p::Point2{Float64} end -CurveTo(cx1, cy1, cx2, cy2, p1, p2) = CurveTo( - Point(cx1, cy1), Point(cx2, cy2), Point(p1, p2) -) +CurveTo(cx1, cy1, cx2, cy2, p1, p2) = CurveTo(Point(cx1, cy1), Point(cx2, cy2), Point(p1, p2)) struct EllipticalArc c::Point2{Float64} @@ -31,12 +29,11 @@ struct EllipticalArc a2::Float64 end -EllipticalArc(cx, cy, r1, r2, angle, a1, a2) = EllipticalArc(Point(cx, cy), - r1, r2, angle, a1, a2) +EllipticalArc(cx, cy, r1, r2, angle, a1, a2) = EllipticalArc(Point(cx, cy), r1, r2, angle, a1, a2) struct ClosePath end -const PathCommand = Union{MoveTo, LineTo, CurveTo, EllipticalArc, ClosePath} +const PathCommand = Union{MoveTo,LineTo,CurveTo,EllipticalArc,ClosePath} struct BezierPath commands::Vector{PathCommand} @@ -54,7 +51,7 @@ StableHashTraits.transform(c::ClosePath) = 0 Base.:(==)(b1::BezierPath, b2::BezierPath) = b1.commands == b2.commands Base.broadcastable(b::BezierPath) = Ref(b) -function Base.:+(pc::P, p::Point2) where P <: PathCommand +function Base.:+(pc::P, p::Point2) where {P<:PathCommand} fnames = fieldnames(P) return P(map(f -> getfield(pc, f) + p, fnames)...) end @@ -76,7 +73,11 @@ scale(c::ClosePath, v::VecTypes{2}) = c function scale(e::EllipticalArc, v::VecTypes{2}) x, y = v if abs(x) != abs(y) - throw(ArgumentError("Currently you can only scale EllipticalArc such that abs(x) == abs(y) if the angle != 0")) + throw( + ArgumentError( + "Currently you can only scale EllipticalArc such that abs(x) == abs(y) if the angle != 0", + ), + ) end ang, a1, a2 = if x > 0 && y > 0 e.angle, e.a1, e.a2 @@ -85,9 +86,9 @@ function scale(e::EllipticalArc, v::VecTypes{2}) elseif x < 0 && y > 0 pi - e.angle, -e.a1, -e.a2 else - pi - e.angle, pi-e.a1, pi-e.a2 + pi - e.angle, pi - e.a1, pi - e.a2 end - EllipticalArc(e.c .* v, e.r1 * abs(x), e.r2 * abs(y), ang, a1, a2) + return EllipticalArc(e.c .* v, e.r1 * abs(x), e.r2 * abs(y), ang, a1, a2) end rotmatrix2d(a) = Mat2(cos(a), sin(a), -sin(a), cos(a)) @@ -96,17 +97,17 @@ rotate(c::ClosePath, a) = c rotate(l::LineTo, a) = LineTo(rotmatrix2d(a) * l.p) function rotate(c::CurveTo, a) m = rotmatrix2d(a) - CurveTo(m * c.c1, m * c.c2, m *c.p) + return CurveTo(m * c.c1, m * c.c2, m * c.p) end function rotate(e::EllipticalArc, a) m = rotmatrix2d(a) newc = m * e.c newangle = e.angle + a - EllipticalArc(newc, e.r1, e.r2, newangle, e.a1, e.a2) + return EllipticalArc(newc, e.r1, e.r2, newangle, e.a1, e.a2) end rotate(b::BezierPath, a) = BezierPath(PathCommand[rotate(c::PathCommand, a) for c in b.commands]) -function fit_to_bbox(b::BezierPath, bb_target::Rect2; keep_aspect = true) +function fit_to_bbox(b::BezierPath, bb_target::Rect2; keep_aspect=true) bb_path = bbox(b) ws_path = widths(bb_path) ws_target = widths(bb_target) @@ -121,11 +122,11 @@ function fit_to_bbox(b::BezierPath, bb_target::Rect2; keep_aspect = true) scale_factor end - bb_t = translate(scale(translate(b, -center_path), scale_factor_aspect), center_target) + return bb_t = translate(scale(translate(b, -center_path), scale_factor_aspect), center_target) end -function fit_to_unit_square(b::BezierPath, keep_aspect = true) - fit_to_bbox(b, Rect2((0.0, 0.0), (1.0, 1.0)), keep_aspect = keep_aspect) +function fit_to_unit_square(b::BezierPath, keep_aspect=true) + return fit_to_bbox(b, Rect2((0.0, 0.0), (1.0, 1.0)), keep_aspect=keep_aspect) end Base.:+(pc::EllipticalArc, p::Point2) = EllipticalArc(pc.c + p, pc.r1, pc.r2, pc.angle, pc.a1, pc.a2) @@ -136,11 +137,7 @@ Base.:+(bp::BezierPath, p::Point2) = BezierPath(bp.commands .+ Ref(p)) const BezierCircle = let r = 0.47 # sqrt(1/pi) - BezierPath([ - MoveTo(Point(r, 0.0)), - EllipticalArc(Point(0.0, 0), r, r, 0.0, 0.0, 2pi), - ClosePath(), - ]) + BezierPath([MoveTo(Point(r, 0.0)), EllipticalArc(Point(0.0, 0), r, r, 0.0, 0.0, 2pi), ClosePath()]) end const BezierUTriangle = let @@ -148,70 +145,60 @@ const BezierUTriangle = let h = 0.97 # sqrt(aspect) * sqrt(2) w = 0.97 # 1/sqrt(aspect) * sqrt(2) # r = Float32(sqrt(1 / (3 * sqrt(3) / 4))) - p1 = Point(0, h/2) - p2 = Point2(-w/2, -h/2) - p3 = Point2(w/2, -h/2) + p1 = Point(0, h / 2) + p2 = Point2(-w / 2, -h / 2) + p3 = Point2(w / 2, -h / 2) centroid = (p1 + p2 + p3) / 3 - bp = BezierPath([ - MoveTo(p1 - centroid), - LineTo(p2 - centroid), - LineTo(p3 - centroid), - ClosePath() - ]) + bp = BezierPath([MoveTo(p1 - centroid), LineTo(p2 - centroid), LineTo(p3 - centroid), ClosePath()]) end -const BezierLTriangle = rotate(BezierUTriangle, pi/2) +const BezierLTriangle = rotate(BezierUTriangle, pi / 2) const BezierDTriangle = rotate(BezierUTriangle, pi) -const BezierRTriangle = rotate(BezierUTriangle, 3pi/2) - +const BezierRTriangle = rotate(BezierUTriangle, 3pi / 2) const BezierSquare = let - r = 0.95 * sqrt(pi)/2/2 # this gives a little less area as the r=0.5 circle + r = 0.95 * sqrt(pi) / 2 / 2 # this gives a little less area as the r=0.5 circle BezierPath([ MoveTo(Point2(r, -r)), LineTo(Point2(r, r)), LineTo(Point2(-r, r)), LineTo(Point2(-r, -r)), - ClosePath() + ClosePath(), ]) end const BezierCross = let - cutfraction = 2/3 + cutfraction = 2 / 3 r = 0.5 # 1/(2 * sqrt(1 - cutfraction^2)) ri = 0.166 #r * (1 - cutfraction) first_three = Point2[(r, ri), (ri, ri), (ri, r)] - all = map(0:pi/2:3pi/2) do a + all = (x -> reduce(vcat, x))(map(0:(pi / 2):(3pi / 2)) do a m = Mat2f(sin(a), cos(a), cos(a), -sin(a)) - Ref(m) .* first_three - end |> x -> reduce(vcat, x) + return Ref(m) .* first_three + end) - BezierPath([ - MoveTo(all[1]), - LineTo.(all[2:end])..., - ClosePath() - ]) + BezierPath([MoveTo(all[1]), LineTo.(all[2:end])..., ClosePath()]) end -const BezierX = rotate(BezierCross, pi/4) +const BezierX = rotate(BezierCross, pi / 4) function bezier_ngon(n, radius, angle) - points = [radius * Point2f(cos(a + angle), sin(a + angle)) - for a in range(0, 2pi, length = n+1)[1:end-1]] - BezierPath([ - MoveTo(points[1]); + points = + [radius * Point2f(cos(a + angle), sin(a + angle)) for a in range(0, 2pi, length=n + 1)[1:(end - 1)]] + return BezierPath([ + MoveTo(points[1]) LineTo.(points[2:end]) ]) end function bezier_star(n, inner_radius, outer_radius, angle) points = [ - (isodd(i) ? outer_radius : inner_radius) * - Point2f(cos(a + angle), sin(a + angle)) - for (i, a) in enumerate(range(0, 2pi, length = 2n+1)[1:end-1])] - BezierPath([ - MoveTo(points[1]); + (isodd(i) ? outer_radius : inner_radius) * Point2f(cos(a + angle), sin(a + angle)) for + (i, a) in enumerate(range(0, 2pi, length=2n + 1)[1:(end - 1)]) + ] + return BezierPath([ + MoveTo(points[1]) LineTo.(points[2:end]) ]) end @@ -240,7 +227,7 @@ function BezierPath(poly::Polygon) return BezierPath(commands) end -function BezierPath(svg::AbstractString; fit = false, bbox = nothing, flipy = false, keep_aspect = true) +function BezierPath(svg::AbstractString; fit=false, bbox=nothing, flipy=false, keep_aspect=true) commands = parse_bezier_commands(svg) p = BezierPath(commands) if flipy @@ -248,12 +235,12 @@ function BezierPath(svg::AbstractString; fit = false, bbox = nothing, flipy = fa end if fit if bbox === nothing - p = fit_to_bbox(p, Rect2f((-0.5, -0.5), (1.0, 1.0)), keep_aspect = keep_aspect) + p = fit_to_bbox(p, Rect2f((-0.5, -0.5), (1.0, 1.0)), keep_aspect=keep_aspect) else - p = fit_to_bbox(p, bbox, keep_aspect = keep_aspect) + p = fit_to_bbox(p, bbox, keep_aspect=keep_aspect) end end - p + return p end function parse_bezier_commands(svg) @@ -291,7 +278,6 @@ function parse_bezier_commands(svg) end while i <= length(args) - comm = args[i] # command letter is omitted, use last command @@ -301,27 +287,27 @@ function parse_bezier_commands(svg) end if comm == "M" - x, y = parse.(Float64, args[i+1:i+2]) + x, y = parse.(Float64, args[(i + 1):(i + 2)]) push!(commands, MoveTo(Point2(x, y))) i += 3 elseif comm == "m" - x, y = parse.(Float64, args[i+1:i+2]) + x, y = parse.(Float64, args[(i + 1):(i + 2)]) push!(commands, MoveTo(Point2(x, y) + lastp())) i += 3 elseif comm == "L" - x, y = parse.(Float64, args[i+1:i+2]) + x, y = parse.(Float64, args[(i + 1):(i + 2)]) push!(commands, LineTo(Point2(x, y))) i += 3 elseif comm == "l" - x, y = parse.(Float64, args[i+1:i+2]) + x, y = parse.(Float64, args[(i + 1):(i + 2)]) push!(commands, LineTo(Point2(x, y) + lastp())) i += 3 elseif comm == "H" - x = parse(Float64, args[i+1]) + x = parse(Float64, args[i + 1]) push!(commands, LineTo(Point2(x, lastp()[2]))) i += 2 elseif comm == "h" - x = parse(Float64, args[i+1]) + x = parse(Float64, args[i + 1]) push!(commands, LineTo(X(x) + lastp())) i += 2 elseif comm == "Z" @@ -331,55 +317,53 @@ function parse_bezier_commands(svg) push!(commands, ClosePath()) i += 1 elseif comm == "C" - x1, y1, x2, y2, x3, y3 = parse.(Float64, args[i+1:i+6]) + x1, y1, x2, y2, x3, y3 = parse.(Float64, args[(i + 1):(i + 6)]) push!(commands, CurveTo(Point2(x1, y1), Point2(x2, y2), Point2(x3, y3))) i += 7 elseif comm == "c" - x1, y1, x2, y2, x3, y3 = parse.(Float64, args[i+1:i+6]) + x1, y1, x2, y2, x3, y3 = parse.(Float64, args[(i + 1):(i + 6)]) l = lastp() push!(commands, CurveTo(Point2(x1, y1) + l, Point2(x2, y2) + l, Point2(x3, y3) + l)) i += 7 elseif comm == "S" - x1, y1, x2, y2 = parse.(Float64, args[i+1:i+4]) + x1, y1, x2, y2 = parse.(Float64, args[(i + 1):(i + 4)]) prev = commands[end] reflected = prev.p + (prev.p - prev.c2) push!(commands, CurveTo(reflected, Point2(x1, y1), Point2(x2, y2))) i += 5 elseif comm == "s" - x1, y1, x2, y2 = parse.(Float64, args[i+1:i+4]) + x1, y1, x2, y2 = parse.(Float64, args[(i + 1):(i + 4)]) prev = commands[end] reflected = prev.p + (prev.p - prev.c2) l = lastp() push!(commands, CurveTo(reflected, Point2(x1, y1) + l, Point2(x2, y2) + l)) i += 5 elseif comm == "A" - args[i+1:i+7] - r1, r2 = parse.(Float64, args[i+1:i+2]) - angle = parse(Float64, args[i+3]) - large_arc_flag, sweep_flag = parse.(Bool, args[i+4:i+5]) - x2, y2 = parse.(Float64, args[i+6:i+7]) + args[(i + 1):(i + 7)] + r1, r2 = parse.(Float64, args[(i + 1):(i + 2)]) + angle = parse(Float64, args[i + 3]) + large_arc_flag, sweep_flag = parse.(Bool, args[(i + 4):(i + 5)]) + x2, y2 = parse.(Float64, args[(i + 6):(i + 7)]) x1, y1 = lastp() - push!(commands, EllipticalArc(x1, y1, x2, y2, r1, r2, - angle, large_arc_flag, sweep_flag)) + push!(commands, EllipticalArc(x1, y1, x2, y2, r1, r2, angle, large_arc_flag, sweep_flag)) i += 8 elseif comm == "a" - r1, r2 = parse.(Float64, args[i+1:i+2]) - angle = parse(Float64, args[i+3]) - large_arc_flag, sweep_flag = parse.(Bool, args[i+4:i+5]) + r1, r2 = parse.(Float64, args[(i + 1):(i + 2)]) + angle = parse(Float64, args[i + 3]) + large_arc_flag, sweep_flag = parse.(Bool, args[(i + 4):(i + 5)]) x1, y1 = lastp() - x2, y2 = parse.(Float64, args[i+6:i+7]) .+ (x1, y1) + x2, y2 = parse.(Float64, args[(i + 6):(i + 7)]) .+ (x1, y1) - push!(commands, EllipticalArc(x1, y1, x2, y2, r1, r2, - angle, large_arc_flag, sweep_flag)) + push!(commands, EllipticalArc(x1, y1, x2, y2, r1, r2, angle, large_arc_flag, sweep_flag)) i += 8 elseif comm == "v" - dy = parse(Float64, args[i+1]) + dy = parse(Float64, args[i + 1]) l = lastp() push!(commands, LineTo(Point2(l[1], l[2] + dy))) i += 2 elseif comm == "V" - y = parse(Float64, args[i+1]) + y = parse(Float64, args[i + 1]) l = lastp() push!(commands, LineTo(Point2(l[1], y))) i += 2 @@ -391,10 +375,9 @@ function parse_bezier_commands(svg) end lastcomm = comm - end - commands + return commands end function EllipticalArc(x1, y1, x2, y2, rx, ry, ϕ, largearc::Bool, sweepflag::Bool) @@ -406,16 +389,13 @@ function EllipticalArc(x1, y1, x2, y2, rx, ry, ϕ, largearc::Bool, sweepflag::Bo m1 = Mat2(cos(ϕ), -sin(ϕ), sin(ϕ), cos(ϕ)) x1′, y1′ = m1 * (0.5 * (p1 - p2)) - tempsqrt = (rx^2 * ry^2 - rx^2 * y1′^2 - ry^2 * x1′^2) / - (rx^2 * y1′^2 + ry^2 * x1′^2) + tempsqrt = (rx^2 * ry^2 - rx^2 * y1′^2 - ry^2 * x1′^2) / (rx^2 * y1′^2 + ry^2 * x1′^2) - c′ = (largearc == sweepflag ? -1 : 1) * - sqrt(tempsqrt) * Point(rx * y1′ / ry, -ry * x1′ / rx) + c′ = (largearc == sweepflag ? -1 : 1) * sqrt(tempsqrt) * Point(rx * y1′ / ry, -ry * x1′ / rx) c = Mat2(cos(ϕ), sin(ϕ), -sin(ϕ), cos(ϕ)) * c′ + 0.5 * (p1 + p2) - vecangle(u, v) = sign(u[1] * v[2] - u[2] * v[1]) * - acos(dot(u, v) / (norm(u) * norm(v))) + vecangle(u, v) = sign(u[1] * v[2] - u[2] * v[1]) * acos(dot(u, v) / (norm(u) * norm(v))) px(sign) = Point((sign * x1′ - c′[1]) / rx, (sign * y1′ - c′[2]) / rx) @@ -429,7 +409,7 @@ function EllipticalArc(x1, y1, x2, y2, rx, ry, ϕ, largearc::Bool, sweepflag::Bo Δθ_pre end - EllipticalArc(c, rx, ry, ϕ, θ1, θ1 + Δθ) + return EllipticalArc(c, rx, ry, ϕ, θ1, θ1 + Δθ) end ################################################### @@ -460,33 +440,22 @@ function make_outline(path) @assert n_contours == length(contours) push!(contours, n_points) # Manually create outline, since FT_Outline_New seems to be problematic on windows somehow - outline = FT_Outline( - n_contours, - n_points, - pointer(points), - pointer(tags), - pointer(contours), - 0 - ) + outline = FT_Outline(n_contours, n_points, pointer(points), pointer(tags), pointer(contours), 0) # Return Ref + arrays that went into outline, so the GC doesn't abandon them return (Ref(outline), points, tags, contours) end ftvec(p) = FT_Vector(round(Int, p[1]), round(Int, p[2])) -function convert_command(m::MoveTo) - true, 1, ftvec.([m.p]), [FT_Curve_Tag_On] -end +convert_command(m::MoveTo) = true, 1, ftvec.([m.p]), [FT_Curve_Tag_On] -function convert_command(l::LineTo) - false, 1, ftvec.([l.p]), [FT_Curve_Tag_On] -end +convert_command(l::LineTo) = false, 1, ftvec.([l.p]), [FT_Curve_Tag_On] function convert_command(c::CurveTo) - false, 3, ftvec.([c.c1, c.c2, c.p]), [FT_Curve_Tag_Cubic, FT_Curve_Tag_Cubic, FT_Curve_Tag_On] + return false, 3, ftvec.([c.c1, c.c2, c.p]), [FT_Curve_Tag_Cubic, FT_Curve_Tag_Cubic, FT_Curve_Tag_On] end -function render_path(path, bitmap_size_px = 256) +function render_path(path, bitmap_size_px=256) # in the outline, 1 unit = 1/64px scale_factor = bitmap_size_px * 64 @@ -499,10 +468,7 @@ function render_path(path, bitmap_size_px = 256) path_unit_square = fit_to_unit_square(path_replaced, false) - path_transformed = Makie.scale( - path_unit_square, - scale_factor, - ) + path_transformed = Makie.scale(path_unit_square, scale_factor) outline_ref = make_outline(path_transformed) @@ -512,23 +478,10 @@ function render_path(path, bitmap_size_px = 256) pixelbuffer = zeros(UInt8, h * pitch) bitmap_ref = Ref{FT_Bitmap}() GC.@preserve pixelbuffer outline_ref begin - bitmap_ref[] = FT_Bitmap( - h, - w, - pitch, - pointer(pixelbuffer), - 256, - FT_PIXEL_MODE_GRAY, - C_NULL, - C_NULL - ) + bitmap_ref[] = FT_Bitmap(h, w, pitch, pointer(pixelbuffer), 256, FT_PIXEL_MODE_GRAY, C_NULL, C_NULL) lib = FreeTypeAbstraction.FREE_FONT_LIBRARY[] @assert lib != C_NULL - err = FT_Outline_Get_Bitmap( - FreeTypeAbstraction.FREE_FONT_LIBRARY[], - outline_ref[1], - bitmap_ref, - ) + err = FT_Outline_Get_Bitmap(FreeTypeAbstraction.FREE_FONT_LIBRARY[], outline_ref[1], bitmap_ref) @assert err == 0 return reshape(pixelbuffer, (w, h)) end @@ -555,10 +508,9 @@ function replace_nonfreetype_commands(path) end i += 1 end - newpath + return newpath end - Makie.convert_attribute(b::BezierPath, ::key"marker", ::key"scatter") = b Makie.convert_attribute(ab::AbstractVector{<:BezierPath}, ::key"marker", ::key"scatter") = ab @@ -587,7 +539,7 @@ function bbox(b::BezierPath) end prev = comm end - bb + return bb end segment(p, l::LineTo) = LineSegment(p, l.p) @@ -596,17 +548,12 @@ segment(p, c::CurveTo) = BezierSegment(p, c.c1, c.c2, c.p) endpoint(m::MoveTo) = m.p endpoint(l::LineTo) = l.p endpoint(c::CurveTo) = c.p -function endpoint(e::EllipticalArc) - point_at_angle(e, e.a2) -end +endpoint(e::EllipticalArc) = point_at_angle(e, e.a2) function point_at_angle(e::EllipticalArc, theta) M = abs(e.r1) * cos(theta) N = abs(e.r2) * sin(theta) - Point2f( - e.c[1] + cos(e.angle) * M - sin(e.angle) * N, - e.c[2] + sin(e.angle) * M + cos(e.angle) * N - ) + return Point2f(e.c[1] + cos(e.angle) * M - sin(e.angle) * N, e.c[2] + sin(e.angle) * M + cos(e.angle) * N) end function cleanup_bbox(bb::Rect2f) @@ -617,17 +564,12 @@ function cleanup_bbox(bb::Rect2f) return bb end -bbox(p, x::Union{LineTo, CurveTo}) = bbox(segment(p, x)) -function bbox(p, e::EllipticalArc) - bbox(elliptical_arc_to_beziers(e)) -end +bbox(p, x::Union{LineTo,CurveTo}) = bbox(segment(p, x)) +bbox(p, e::EllipticalArc) = bbox(elliptical_arc_to_beziers(e)) -function bbox(ls::LineSegment) - Rect2f(ls.from, ls.to - ls.from) -end +bbox(ls::LineSegment) = Rect2f(ls.from, ls.to - ls.from) function bbox(b::BezierSegment) - p0 = b.from p1 = b.c1 p2 = b.c2 @@ -637,68 +579,67 @@ function bbox(b::BezierSegment) ma = [max.(p0, p3)...] c = -p0 + p1 - b = p0 - 2p1 + p2 + b = p0 - 2p1 + p2 a = -p0 + 3p1 - 3p2 + 1p3 - h = [(b.*b - a.*c)...] + h = [(b .* b - a .* c)...] if h[1] > 0 h[1] = sqrt(h[1]) t = (-b[1] - h[1]) / a[1] if t > 0 && t < 1 - s = 1.0-t - q = s*s*s*p0[1] + 3.0*s*s*t*p1[1] + 3.0*s*t*t*p2[1] + t*t*t*p3[1] - mi[1] = min(mi[1],q) - ma[1] = max(ma[1],q) + s = 1.0 - t + q = s * s * s * p0[1] + 3.0 * s * s * t * p1[1] + 3.0 * s * t * t * p2[1] + t * t * t * p3[1] + mi[1] = min(mi[1], q) + ma[1] = max(ma[1], q) end - t = (-b[1] + h[1])/a[1] - if t>0 && t<1 - s = 1.0-t - q = s*s*s*p0[1] + 3.0*s*s*t*p1[1] + 3.0*s*t*t*p2[1] + t*t*t*p3[1] - mi[1] = min(mi[1],q) - ma[1] = max(ma[1],q) + t = (-b[1] + h[1]) / a[1] + if t > 0 && t < 1 + s = 1.0 - t + q = s * s * s * p0[1] + 3.0 * s * s * t * p1[1] + 3.0 * s * t * t * p2[1] + t * t * t * p3[1] + mi[1] = min(mi[1], q) + ma[1] = max(ma[1], q) end end - if h[2]>0.0 + if h[2] > 0.0 h[2] = sqrt(h[2]) - t = (-b[2] - h[2])/a[2] - if t>0.0 && t<1.0 - s = 1.0-t - q = s*s*s*p0[2] + 3.0*s*s*t*p1[2] + 3.0*s*t*t*p2[2] + t*t*t*p3[2] - mi[2] = min(mi[2],q) - ma[2] = max(ma[2],q) + t = (-b[2] - h[2]) / a[2] + if t > 0.0 && t < 1.0 + s = 1.0 - t + q = s * s * s * p0[2] + 3.0 * s * s * t * p1[2] + 3.0 * s * t * t * p2[2] + t * t * t * p3[2] + mi[2] = min(mi[2], q) + ma[2] = max(ma[2], q) end - t = (-b[2] + h[2])/a[2] - if t>0.0 && t<1.0 - s = 1.0-t - q = s*s*s*p0[2] + 3.0*s*s*t*p1[2] + 3.0*s*t*t*p2[2] + t*t*t*p3[2] - mi[2] = min(mi[2],q) - ma[2] = max(ma[2],q) + t = (-b[2] + h[2]) / a[2] + if t > 0.0 && t < 1.0 + s = 1.0 - t + q = s * s * s * p0[2] + 3.0 * s * s * t * p1[2] + 3.0 * s * t * t * p2[2] + t * t * t * p3[2] + mi[2] = min(mi[2], q) + ma[2] = max(ma[2], q) end end - Rect2f(Point(mi...), Point(ma...) - Point(mi...)) + return Rect2f(Point(mi...), Point(ma...) - Point(mi...)) end - function elliptical_arc_to_beziers(arc::EllipticalArc) delta_a = abs(arc.a2 - arc.a1) n_beziers = ceil(Int, delta_a / 0.5pi) - angles = range(arc.a1, arc.a2, length = n_beziers + 1) + angles = range(arc.a1, arc.a2, length=n_beziers + 1) startpoint = Point2f(cos(arc.a1), sin(arc.a1)) - curves = map(angles[1:end-1], angles[2:end]) do start, stop + curves = map(angles[1:(end - 1)], angles[2:end]) do start, stop theta = stop - start - kappa = 4/3 * tan(theta/4) + kappa = 4 / 3 * tan(theta / 4) c1 = Point2f(cos(start) - kappa * sin(start), sin(start) + kappa * cos(start)) c2 = Point2f(cos(stop) + kappa * sin(stop), sin(stop) - kappa * cos(stop)) b = Point2f(cos(stop), sin(stop)) - CurveTo(c1, c2, b) + return CurveTo(c1, c2, b) end path = BezierPath([LineTo(startpoint), curves...]) path = scale(path, Vec(arc.r1, arc.r2)) path = rotate(path, arc.angle) - path = translate(path, arc.c) + return path = translate(path, arc.c) end diff --git a/src/camera/camera.jl b/src/camera/camera.jl index 338aec7233b..3dd5a50a960 100644 --- a/src/camera/camera.jl +++ b/src/camera/camera.jl @@ -1,13 +1,11 @@ -function Base.copy(x::Camera) - Camera(ntuple(7) do i - getfield(x, i) - end...) -end +Base.copy(x::Camera) = Camera(ntuple(7) do i + return getfield(x, i) +end...) function Base.:(==)(a::Camera, b::Camera) - to_value(a.view) == to_value(b.view) && - to_value(a.projection) == to_value(b.projection) && - to_value(a.resolution) == to_value(b.resolution) + return to_value(a.view) == to_value(b.view) && + to_value(a.projection) == to_value(b.projection) && + to_value(a.resolution) == to_value(b.resolution) end function Base.show(io::IO, camera::Camera) @@ -18,7 +16,7 @@ function Base.show(io::IO, camera::Camera) println(io, " projection: ", camera.projection[]) println(io, " projectionview: ", camera.projectionview[]) println(io, " resolution: ", camera.resolution[]) - println(io, " eyeposition: ", camera.eyeposition[]) + return println(io, " eyeposition: ", camera.eyeposition[]) end function disconnect!(c::Camera) @@ -39,14 +37,12 @@ function disconnect!(observables::Vector) return end -struct CameraLift{F, Args} +struct CameraLift{F,Args} f::F args::Args end -function (cl::CameraLift{F, Args})(val) where {F, Args} - cl.f(map(to_value, cl.args)...) -end +(cl::CameraLift{F,Args})(val) where {F,Args} = cl.f(map(to_value, cl.args)...) """ on(f, c::Camera, observables::Observable...) @@ -67,10 +63,10 @@ end function Camera(px_area) pixel_space = lift(px_area) do window_size - nearclip = -10_000f0 - farclip = 10_000f0 + nearclip = -10_000.0f0 + farclip = 10_000.0f0 w, h = Float32.(widths(window_size)) - return orthographicprojection(0f0, w, 0f0, h, nearclip, farclip) + return orthographicprojection(0.0f0, w, 0.0f0, h, nearclip, farclip) end view = Observable(Mat4f(I)) proj = Observable(Mat4f(I)) @@ -80,9 +76,9 @@ function Camera(px_area) view, proj, proj_view, - lift(a-> Vec2f(widths(a)), px_area), + lift(a -> Vec2f(widths(a)), px_area), Observable(Vec3f(1)), - ObserverFunction[] + ObserverFunction[], ) end @@ -92,7 +88,7 @@ function set_proj_view!(camera::Camera, projection, view) # But nobody should do that, right? # GLMakie uses map on view camera.view[] = view - camera.projection[] = projection + return camera.projection[] = projection end is_mouseinside(x, target) = is_mouseinside(get_scene(x), target) diff --git a/src/camera/camera2d.jl b/src/camera/camera2d.jl index 3a9a07c9024..6fa252130c6 100644 --- a/src/camera/camera2d.jl +++ b/src/camera/camera2d.jl @@ -2,9 +2,9 @@ struct Camera2D <: AbstractCamera area::Observable{Rect2f} zoomspeed::Observable{Float32} zoombutton::Observable{ButtonTypes} - panbutton::Observable{Union{ButtonTypes, Vector{ButtonTypes}}} + panbutton::Observable{Union{ButtonTypes,Vector{ButtonTypes}}} padding::Observable{Float32} - last_area::Observable{Vec{2, Int}} + last_area::Observable{Vec{2,Int}} update_limits::Observable{Bool} end @@ -15,15 +15,15 @@ Creates a 2D camera for the given Scene. """ function cam2d!(scene::SceneLike; kw_args...) cam_attributes = merged_get!(:cam2d, scene, Attributes(kw_args)) do - Attributes( - area = Observable(Rectf(0, 0, 1, 1)), - zoomspeed = 0.10f0, - zoombutton = nothing, - panbutton = Mouse.right, - selectionbutton = (Keyboard.space, Mouse.left), - padding = 0.001, - last_area = Vec(size(scene)), - update_limits = false, + return Attributes( + area=Observable(Rectf(0, 0, 1, 1)), + zoomspeed=0.10f0, + zoombutton=nothing, + panbutton=Mouse.right, + selectionbutton=(Keyboard.space, Mouse.left), + padding=0.001, + last_area=Vec(size(scene)), + update_limits=false, ) end cam = from_dict(Camera2D, cam_attributes) @@ -34,12 +34,11 @@ function cam2d!(scene::SceneLike; kw_args...) correct_ratio!(scene, cam) selection_rect!(scene, cam, cam_attributes.selectionbutton) cameracontrols!(scene, cam) - cam + return cam end wscale(screenrect, viewrect) = widths(viewrect) ./ widths(screenrect) - """ update_cam!(scene::SceneLike, area) @@ -58,7 +57,7 @@ function update_cam!(scene::Scene, cam::Camera2D, area3d::Rect) area = Rect2f(area3d) area = positive_widths(area) # ignore rects with width almost 0 - any(x-> x ≈ 0.0, widths(area)) && return + any(x -> x ≈ 0.0, widths(area)) && return pa = pixelarea(scene)[] px_wh = normalize(widths(pa)) @@ -73,22 +72,22 @@ function update_cam!(scene::Scene, cam::Camera2D, area3d::Rect) newwh = s .* widths(area) cam.area[] = Rectf(minimum(area), newwh) end - update_cam!(scene, cam) + return update_cam!(scene, cam) end function update_cam!(scene::SceneLike, cam::Camera2D) x, y = minimum(cam.area[]) - w, h = widths(cam.area[]) ./ 2f0 + w, h = widths(cam.area[]) ./ 2.0f0 # These observables should be final, no one should do map(cam.projection), # so we don't push! and just update the value in place view = translationmatrix(Vec3f(-x - w, -y - h, 0)) - projection = orthographicprojection(-w, w, -h, h, -10_000f0, 10_000f0) + projection = orthographicprojection(-w, w, -h, h, -10_000.0f0, 10_000.0f0) set_proj_view!(camera(scene), projection, view) cam.last_area[] = Vec(size(scene)) return end -function correct_ratio!(scene, cam) +correct_ratio!(scene, cam) = on(camera(scene), pixelarea(scene)) do area neww = widths(area) change = neww .- cam.last_area[] @@ -100,7 +99,6 @@ function correct_ratio!(scene, cam) end return end -end function add_pan!(scene::SceneLike, cam::Camera2D) startpos = RefValue((0.0, 0.0)) @@ -110,7 +108,7 @@ function add_pan!(scene::SceneLike, cam::Camera2D) on( camera(scene), Observable.((scene, cam, startpos, drag_active))..., - e.mousebutton + e.mousebutton, ) do scene, cam, startpos, active, event mp = e.mouseposition[] if ispressed(scene, cam.panbutton[]) @@ -135,7 +133,7 @@ function add_pan!(scene::SceneLike, cam::Camera2D) on( camera(scene), Observable.((scene, cam, startpos, drag_active))..., - e.mouseposition + e.mouseposition, ) do scene, cam, startpos, active, pos if active[] && ispressed(scene, cam.panbutton[]) diff = startpos[] .- pos @@ -157,7 +155,7 @@ function add_zoom!(scene::SceneLike, cam::Camera2D) zoom = Float32(x[2]) if zoom != 0 && ispressed(scene, zoombutton) && is_mouseinside(scene) pa = pixelarea(scene)[] - z = (1f0 - zoomspeed)^zoom + z = (1.0f0 - zoomspeed)^zoom mp = Vec2f(e.mouseposition[]) - minimum(pa) mp = (mp .* wscale(pa, area)) + minimum(area) p1, p2 = minimum(area), maximum(area) @@ -180,28 +178,18 @@ end function absrect(rect) xy, wh = minimum(rect), widths(rect) xy = ntuple(Val(2)) do i - wh[i] < 0 ? xy[i] + wh[i] : xy[i] + return wh[i] < 0 ? xy[i] + wh[i] : xy[i] end return Rectf(Vec2f(xy), Vec2f(abs.(wh))) end - function selection_rect!(scene, cam, key) rect = RefValue(Rectf(NaN, NaN, NaN, NaN)) - lw = 2f0 - scene_unscaled = Scene( - scene, transformation = Transformation(), - cam = copy(camera(scene)), clear = false - ) + lw = 2.0f0 + scene_unscaled = Scene(scene, transformation=Transformation(), cam=copy(camera(scene)), clear=false) scene_unscaled.clear = false - rect_vis = lines!( - scene_unscaled, - rect[], - linestyle = :dot, - linewidth = 2f0, - color = (:black, 0.4), - visible = false - ) + rect_vis = + lines!(scene_unscaled, rect[], linestyle=:dot, linewidth=2.0f0, color=(:black, 0.4), visible=false) waspressed = RefValue(false) on(camera(scene), events(scene).mousebutton, key) do event, key if ispressed(scene, key) && is_mouseinside(scene) @@ -249,7 +237,7 @@ function selection_rect!(scene, cam, key) return rect_vis, rect end -function reset!(cam, boundingbox, preserveratio = true) +function reset!(cam, boundingbox, preserveratio=true) w1 = widths(boundingbox) if preserveratio w2 = widths(cam[Screen][Area]) @@ -272,7 +260,7 @@ function add_restriction!(cam, window, rarea::Rect2, minwidths::Vec) restrict_action = paused_action(1.0) do t o = lerp(origin(area_ref[]), origin(cam[Area]), t) wh = lerp(widths(area_ref[]), widths(cam[Area]), t) - update_cam!(cam, Rectf(o, wh)) + return update_cam!(cam, Rectf(o, wh)) end on(window, Mouse.Drag) do drag if drag == Mouse.up && !isplaying(restrict_action) @@ -284,9 +272,9 @@ function add_restriction!(cam, window, rarea::Rect2, minwidths::Vec) maxi = maxi - newmax newo = newo - maxi newwh = newmax - newo - scale = 1f0 + scale = 1.0f0 for (w1, w2) in zip(minwidths, newwh) - stmp = w1 > w2 ? w1 / w2 : 1f0 + stmp = w1 > w2 ? w1 / w2 : 1.0f0 scale = max(scale, stmp) end newwh = newwh * scale @@ -297,12 +285,11 @@ function add_restriction!(cam, window, rarea::Rect2, minwidths::Vec) end return end - restrict_action + return restrict_action end struct PixelCamera <: AbstractCamera end - struct UpdatePixelCam camera::Camera near::Float32 @@ -311,8 +298,8 @@ end function (cam::UpdatePixelCam)(window_size) w, h = Float32.(widths(window_size)) - projection = orthographicprojection(0f0, w, 0f0, h, cam.near, cam.far) - set_proj_view!(cam.camera, projection, Mat4f(I)) + projection = orthographicprojection(0.0f0, w, 0.0f0, h, cam.near, cam.far) + return set_proj_view!(cam.camera, projection, Mat4f(I)) end """ @@ -320,7 +307,7 @@ end Creates a pixel-level camera for the `Scene`. No controls! """ -function campixel!(scene::Scene; nearclip=-10_000f0, farclip=10_000f0) +function campixel!(scene::Scene; nearclip=-10_000.0f0, farclip=10_000.0f0) disconnect!(camera(scene)) update_once = Observable(false) closure = UpdatePixelCam(camera(scene), nearclip, farclip) @@ -340,12 +327,12 @@ struct RelativeCamera <: AbstractCamera end Creates a pixel-level camera for the `Scene`. No controls! """ -function cam_relative!(scene::Scene; nearclip=-10_000f0, farclip=10_000f0) - projection = orthographicprojection(0f0, 1f0, 0f0, 1f0, nearclip, farclip) +function cam_relative!(scene::Scene; nearclip=-10_000.0f0, farclip=10_000.0f0) + projection = orthographicprojection(0.0f0, 1.0f0, 0.0f0, 1.0f0, nearclip, farclip) set_proj_view!(camera(scene), projection, Mat4f(I)) cam = RelativeCamera() cameracontrols!(scene, cam) - cam + return cam end # disconnect!(::Makie.PixelCamera) = nothing diff --git a/src/camera/camera3d.jl b/src/camera/camera3d.jl index dc05aeb5ea0..bc12cec1ff7 100644 --- a/src/camera/camera3d.jl +++ b/src/camera/camera3d.jl @@ -82,70 +82,68 @@ You can also make adjustments to the camera position, rotation and zoom by calli """ function Camera3D(scene::Scene; kwargs...) attr = merged_get!(:cam3d, scene, Attributes(kwargs)) do - Attributes( + return Attributes( # Keyboard controls # Translations - up_key = Keyboard.r, - down_key = Keyboard.f, - left_key = Keyboard.a, - right_key = Keyboard.d, - forward_key = Keyboard.w, - backward_key = Keyboard.s, + up_key=Keyboard.r, + down_key=Keyboard.f, + left_key=Keyboard.a, + right_key=Keyboard.d, + forward_key=Keyboard.w, + backward_key=Keyboard.s, # Zooms - zoom_in_key = Keyboard.u, - zoom_out_key = Keyboard.o, - stretch_view_key = Keyboard.page_up, - contract_view_key = Keyboard.page_down, + zoom_in_key=Keyboard.u, + zoom_out_key=Keyboard.o, + stretch_view_key=Keyboard.page_up, + contract_view_key=Keyboard.page_down, # Rotations - pan_left_key = Keyboard.j, - pan_right_key = Keyboard.l, - tilt_up_key = Keyboard.i, - tilt_down_key = Keyboard.k, - roll_clockwise_key = Keyboard.e, - roll_counterclockwise_key = Keyboard.q, + pan_left_key=Keyboard.j, + pan_right_key=Keyboard.l, + tilt_up_key=Keyboard.i, + tilt_down_key=Keyboard.k, + roll_clockwise_key=Keyboard.e, + roll_counterclockwise_key=Keyboard.q, # Mouse controls - translation_button = Mouse.right, - scroll_mod = true, - rotation_button = Mouse.left, + translation_button=Mouse.right, + scroll_mod=true, + rotation_button=Mouse.left, # Shared controls - fix_x_key = Keyboard.x, - fix_y_key = Keyboard.y, - fix_z_key = Keyboard.z, - reset = Keyboard.home, + fix_x_key=Keyboard.x, + fix_y_key=Keyboard.y, + fix_z_key=Keyboard.z, + reset=Keyboard.home, # Settings - keyboard_rotationspeed = 1f0, - keyboard_translationspeed = 0.5f0, - keyboard_zoomspeed = 1f0, - mouse_rotationspeed = 1f0, - mouse_translationspeed = 1f0, - mouse_zoomspeed = 1f0, - circular_rotation = (true, true, true), - fov = 45f0, # base fov - near = automatic, - far = automatic, - rotation_center = :lookat, - update_rate = 1/30, - projectiontype = Perspective, - fixed_axis = true, - zoom_shift_lookat = false, # doesn't really work with fov - cad = false, + keyboard_rotationspeed=1.0f0, + keyboard_translationspeed=0.5f0, + keyboard_zoomspeed=1.0f0, + mouse_rotationspeed=1.0f0, + mouse_translationspeed=1.0f0, + mouse_zoomspeed=1.0f0, + circular_rotation=(true, true, true), + fov=45.0f0, # base fov + near=automatic, + far=automatic, + rotation_center=:lookat, + update_rate=1 / 30, + projectiontype=Perspective, + fixed_axis=true, + zoom_shift_lookat=false, # doesn't really work with fov + cad=false, # internal - selected = true + selected=true, ) end cam = Camera3D( pop!(attr, :eyeposition, Vec3f(3)), - pop!(attr, :lookat, Vec3f(0)), - pop!(attr, :upvector, Vec3f(0, 0, 1)), - - Observable(1f0), + pop!(attr, :lookat, Vec3f(0)), + pop!(attr, :upvector, Vec3f(0, 0, 1)), + Observable(1.0f0), Observable(attr[:fov][]), Observable(attr[:near][] === automatic ? 0.1f0 : attr[:near][]), - Observable(attr[:far][] === automatic ? 100f0 : attr[:far][]), + Observable(attr[:far][] === automatic ? 100.0f0 : attr[:far][]), Observable(-1.0), - - attr + attr, ) disconnect!(camera(scene)) @@ -164,17 +162,30 @@ function Camera3D(scene::Scene; kwargs...) end keynames = ( - :up_key, :down_key, :left_key, :right_key, :forward_key, :backward_key, - :zoom_in_key, :zoom_out_key, :stretch_view_key, :contract_view_key, - :pan_left_key, :pan_right_key, :tilt_up_key, :tilt_down_key, - :roll_clockwise_key, :roll_counterclockwise_key + :up_key, + :down_key, + :left_key, + :right_key, + :forward_key, + :backward_key, + :zoom_in_key, + :zoom_out_key, + :stretch_view_key, + :contract_view_key, + :pan_left_key, + :pan_right_key, + :tilt_up_key, + :tilt_down_key, + :roll_clockwise_key, + :roll_counterclockwise_key, ) # Start ticking if relevant keys are pressed on(camera(scene), events(scene).keyboardbutton) do event - if event.action in (Keyboard.press, Keyboard.repeat) && cam.pulser[] == -1.0 && - attr.selected[] && any(key -> ispressed(scene, attr[key][]), keynames) - + if event.action in (Keyboard.press, Keyboard.repeat) && + cam.pulser[] == -1.0 && + attr.selected[] && + any(key -> ispressed(scene, attr[key][]), keynames) cam.pulser[] = time() return Consume(true) end @@ -184,7 +195,7 @@ function Camera3D(scene::Scene; kwargs...) # de/select plot on click outside/inside # also deselect other cameras deselect_all_cameras!(root(scene)) - on(camera(scene), events(scene).mousebutton, priority = 100) do event + on(camera(scene), events(scene).mousebutton, priority=100) do event if event.action == Mouse.press attr.selected[] = is_mouseinside(scene) end @@ -200,12 +211,12 @@ function Camera3D(scene::Scene; kwargs...) # Trigger updates on scene resize and settings change on(camera(scene), scene.px_area, attr[:fov], attr[:projectiontype]) do _, _, _ - update_cam!(scene, cam) + return update_cam!(scene, cam) end on(camera(scene), attr[:near], attr[:far]) do near, far near === automatic || (cam.near[] = near) - far === automatic || (cam.far[] = far) - update_cam!(scene, cam) + far === automatic || (cam.far[] = far) + return update_cam!(scene, cam) end # reset @@ -215,7 +226,7 @@ function Camera3D(scene::Scene; kwargs...) # might make sense to keep user set lookat, upvector, eyeposition # around somewhere for this? cam.lookat[] = Vec3f(0) - cam.upvector[] = Vec3f(0,0,1) + cam.upvector[] = Vec3f(0, 0, 1) cam.eyeposition[] = Vec3f(3) center!(scene) return Consume(true) @@ -223,15 +234,17 @@ function Camera3D(scene::Scene; kwargs...) return Consume(false) end update_cam!(scene, cam) - cam + return cam end # These imitate the old camera -cam3d!(scene; zoom_shift_lookat = true, fixed_axis = true, kwargs...) = - Camera3D(scene, zoom_shift_lookat = zoom_shift_lookat, fixed_axis = fixed_axis; kwargs...) +function cam3d!(scene; zoom_shift_lookat=true, fixed_axis=true, kwargs...) + return Camera3D(scene, zoom_shift_lookat=zoom_shift_lookat, fixed_axis=fixed_axis; kwargs...) +end -cam3d_cad!(scene; cad = true, zoom_shift_lookat = false, fixed_axis = false, kwargs...) = - Camera3D(scene, cad = cad, zoom_shift_lookat = zoom_shift_lookat, fixed_axis = fixed_axis; kwargs...) +function cam3d_cad!(scene; cad=true, zoom_shift_lookat=false, fixed_axis=false, kwargs...) + return Camera3D(scene, cad=cad, zoom_shift_lookat=zoom_shift_lookat, fixed_axis=fixed_axis; kwargs...) +end function deselect_all_cameras!(scene) cam = cameracontrols(scene) @@ -239,10 +252,9 @@ function deselect_all_cameras!(scene) for child in scene.children deselect_all_cameras!(child) end - nothing + return nothing end - function add_translation!(scene, cam::Camera3D) translationspeed = cam.attributes[:mouse_translationspeed] zoomspeed = cam.attributes[:mouse_zoomspeed] @@ -254,16 +266,15 @@ function add_translation!(scene, cam::Camera3D) last_mousepos = RefValue(Vec2f(0, 0)) dragging = RefValue(false) - function compute_diff(delta) + compute_diff(delta) = if cam.attributes[:projectiontype][] == Orthographic aspect = Float32((/)(widths(scene.px_area[])...)) - aspect_scale = Vec2f(1f0 + aspect, 1f0 + 1f0 / aspect) + aspect_scale = Vec2f(1.0f0 + aspect, 1.0f0 + 1.0f0 / aspect) return cam.zoom_mult[] * delta .* aspect_scale ./ widths(scene.px_area[]) else viewdir = cam.lookat[] - cam.eyeposition[] return 0.002f0 * cam.zoom_mult[] * norm(viewdir) * delta end - end # drag start/stop on(camera(scene), scene.events.mousebutton) do event @@ -278,7 +289,7 @@ function add_translation!(scene, cam::Camera3D) diff = compute_diff(last_mousepos[] .- mousepos) last_mousepos[] = mousepos dragging[] = false - translate_cam!(scene, cam, translationspeed[] .* Vec3f(diff[1], diff[2], 0f0)) + translate_cam!(scene, cam, translationspeed[] .* Vec3f(diff[1], diff[2], 0.0f0)) return Consume(true) end return Consume(false) @@ -290,7 +301,7 @@ function add_translation!(scene, cam::Camera3D) mousepos = screen_relative(scene, mp) diff = compute_diff(last_mousepos[] .- mousepos) last_mousepos[] = mousepos - translate_cam!(scene, cam, translationspeed[] * Vec3f(diff[1], diff[2], 0f0)) + translate_cam!(scene, cam, translationspeed[] * Vec3f(diff[1], diff[2], 0.0f0)) return Consume(true) end return Consume(false) @@ -298,7 +309,7 @@ function add_translation!(scene, cam::Camera3D) on(camera(scene), scene.events.scroll) do scroll if is_mouseinside(scene) && ispressed(scene, scroll_mod[]) - zoom_step = (1f0 + 0.1f0 * zoomspeed[]) ^ -scroll[2] + zoom_step = (1.0f0 + 0.1f0 * zoomspeed[])^-scroll[2] zoom!(scene, cam, zoom_step, shift_lookat[], cad[]) return Consume(true) end @@ -327,7 +338,7 @@ function add_rotation!(scene, cam::Camera3D) rot_scaling = rotationspeed[] * (e.window_dpi[] * 0.005) mp = (last_mousepos[] .- mousepos) .* 0.01f0 .* rot_scaling last_mousepos[] = mousepos - rotate_cam!(scene, cam, Vec3f(-mp[2], mp[1], 0f0), true) + rotate_cam!(scene, cam, Vec3f(-mp[2], mp[1], 0.0f0), true) return Consume(true) end return Consume(false) @@ -340,14 +351,13 @@ function add_rotation!(scene, cam::Camera3D) rot_scaling = rotationspeed[] * (e.window_dpi[] * 0.005) mp = (last_mousepos[] .- mousepos) * 0.01f0 * rot_scaling last_mousepos[] = mousepos - rotate_cam!(scene, cam, Vec3f(-mp[2], mp[1], 0f0), true) + rotate_cam!(scene, cam, Vec3f(-mp[2], mp[1], 0.0f0), true) return Consume(true) end return Consume(false) end end - function on_pulse(scene, cam, timestep) attr = cam.attributes @@ -362,8 +372,8 @@ function on_pulse(scene, cam, timestep) if translating # translation in camera space x/y/z direction - translation = attr[:keyboard_translationspeed][] * timestep * - Vec3f(right - left, up - down, backward - forward) + translation = + attr[:keyboard_translationspeed][] * timestep * Vec3f(right - left, up - down, backward - forward) viewdir = cam.lookat[] - cam.eyeposition[] _translate_cam!(scene, cam, cam.zoom_mult[] * norm(viewdir) * translation) end @@ -379,7 +389,9 @@ function on_pulse(scene, cam, timestep) if rotating # rotations around camera space x/y/z axes - angles = attr[:keyboard_rotationspeed][] * timestep * + angles = + attr[:keyboard_rotationspeed][] * + timestep * Vec3f(up - down, left - right, counterclockwise - clockwise) _rotate_cam!(scene, cam, angles) @@ -391,14 +403,14 @@ function on_pulse(scene, cam, timestep) zooming = zoom_out || zoom_in if zooming - zoom_step = (1f0 + attr[:keyboard_zoomspeed][] * timestep) ^ (zoom_out - zoom_in) + zoom_step = (1.0f0 + attr[:keyboard_zoomspeed][] * timestep)^(zoom_out - zoom_in) _zoom!(scene, cam, zoom_step, false) end stretch = ispressed(scene, attr[:stretch_view_key][]) contract = ispressed(scene, attr[:contract_view_key][]) if stretch || contract - zoom_step = (1f0 + attr[:keyboard_zoomspeed][] * timestep) ^ (stretch - contract) + zoom_step = (1.0f0 + attr[:keyboard_zoomspeed][] * timestep)^(stretch - contract) cam.eyeposition[] = cam.lookat[] + zoom_step * (cam.eyeposition[] - cam.lookat[]) end zooming = zooming || stretch || contract @@ -412,11 +424,10 @@ function on_pulse(scene, cam, timestep) end end - function translate_cam!(scene::Scene, cam::Camera3D, t::VecTypes) _translate_cam!(scene, cam, t) update_cam!(scene, cam) - nothing + return nothing end function _translate_cam!(scene, cam, t) # This uses a camera based coordinate system where @@ -443,11 +454,10 @@ function _translate_cam!(scene, cam, t) return end - function rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) _rotate_cam!(scene, cam, angles, from_mouse) update_cam!(scene, cam) - nothing + return nothing end function _rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) # This applies rotations around the x/y/z axis of the camera coordinate system @@ -479,13 +489,13 @@ function _rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) # drawing circles creates continuous rotations around the fixed axis mp = mouseposition_px(scene) past_half = 0.5f0 .* widths(scene.px_area[]) .> mp - flip = 2f0 * past_half .- 1f0 + flip = 2.0f0 * past_half .- 1.0f0 angle = flip[1] * angles[1] + flip[2] * angles[2] angles = Vec3f(-angle, angle, -angle) # only one fix is true so this only rotates around one axis rotation *= qrotation( Vec3f(fix_x, fix_z, fix_y) .* Vec3f(sign(right[1]), viewdir[2], sign(up[3])), - dot(Vec3f(fix_x, fix_y, fix_z), angles) + dot(Vec3f(fix_x, fix_y, fix_z), angles), ) else # restrict total quaternion rotation to one axis @@ -510,7 +520,6 @@ function _rotate_cam!(scene, cam::Camera3D, angles::VecTypes, from_mouse=false) return end - """ zoom!(scene, zoom_step) @@ -520,12 +529,12 @@ of 1.0 is neutral, larger zooms out and lower zooms in. Note that this method only applies to Camera3D. """ zoom!(scene::Scene, zoom_step) = zoom!(scene, cameracontrols(scene), zoom_step, false, false) -function zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat = false, cad = false) +function zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat=false, cad=false) _zoom!(scene, cam, zoom_step, shift_lookat, cad) update_cam!(scene, cam) - nothing + return nothing end -function _zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat = false, cad = false) +function _zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat=false, cad=false) if cad # move exeposition if mouse is not over the center lookat = cam.lookat[] @@ -534,9 +543,9 @@ function _zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat = false, ca viewdir = lookat - eyepos # -z right = cross(viewdir, up) # +x - rel_pos = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0 + rel_pos = 2.0f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1.0f0 shift = rel_pos[1] * normalize(right) + rel_pos[2] * normalize(up) - shifted = eyepos + 0.1f0 * sign(1f0 - zoom_step) * norm(viewdir) * shift + shifted = eyepos + 0.1f0 * sign(1.0f0 - zoom_step) * norm(viewdir) * shift cam.eyeposition[] = lookat + norm(viewdir) * normalize(shifted - lookat) elseif shift_lookat lookat = cam.lookat[] @@ -551,22 +560,22 @@ function _zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat = false, ca # translate both eyeposition and lookat to more or less keep data # under the mouse in view fov = cam.attributes[:fov][] - before = tan(clamp(cam.zoom_mult[] * fov, 0.01f0, 175f0) / 360f0 * Float32(pi)) - after = tan(clamp(cam.zoom_mult[] * zoom_step * fov, 0.01f0, 175f0) / 360f0 * Float32(pi)) + before = tan(clamp(cam.zoom_mult[] * fov, 0.01f0, 175.0f0) / 360.0f0 * Float32(pi)) + after = tan(clamp(cam.zoom_mult[] * zoom_step * fov, 0.01f0, 175.0f0) / 360.0f0 * Float32(pi)) aspect = Float32((/)(widths(scene.px_area[])...)) - rel_pos = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0 + rel_pos = 2.0f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1.0f0 shift = rel_pos[1] * u_x + rel_pos[2] * u_y shift = -(after - before) * norm(viewdir) * normalize(aspect .* shift) else - mx, my = 2f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1f0 + mx, my = 2.0f0 * mouseposition_px(scene) ./ widths(scene.px_area[]) .- 1.0f0 aspect = Float32((/)(widths(scene.px_area[])...)) - w = 0.5f0 * (1f0 + aspect) * cam.zoom_mult[] - h = 0.5f0 * (1f0 + 1f0 / aspect) * cam.zoom_mult[] - shift = (1f0 - zoom_step) * (mx * w * u_x + my * h * u_y) + w = 0.5f0 * (1.0f0 + aspect) * cam.zoom_mult[] + h = 0.5f0 * (1.0f0 + 1.0f0 / aspect) * cam.zoom_mult[] + shift = (1.0f0 - zoom_step) * (mx * w * u_x + my * h * u_y) end - cam.lookat[] = lookat + shift + cam.lookat[] = lookat + shift cam.eyeposition[] = eyepos + shift end @@ -576,20 +585,20 @@ function _zoom!(scene::Scene, cam::Camera3D, zoom_step, shift_lookat = false, ca return end - function update_cam!(scene::Scene, cam::Camera3D) @extractvalue cam (lookat, eyeposition, upvector) - near = cam.near[]; far = cam.far[] + near = cam.near[] + far = cam.far[] aspect = Float32((/)(widths(scene.px_area[])...)) if cam.attributes[:projectiontype][] == Perspective - fov = clamp(cam.zoom_mult[] * cam.attributes[:fov][], 0.01f0, 175f0) + fov = clamp(cam.zoom_mult[] * cam.attributes[:fov][], 0.01f0, 175.0f0) cam.fov[] = fov proj = perspectiveprojection(fov, aspect, near, far) else - w = 0.5f0 * (1f0 + aspect) * cam.zoom_mult[] - h = 0.5f0 * (1f0 + 1f0 / aspect) * cam.zoom_mult[] + w = 0.5f0 * (1.0f0 + aspect) * cam.zoom_mult[] + h = 0.5f0 * (1.0f0 + 1.0f0 / aspect) * cam.zoom_mult[] proj = orthographicprojection(-w, w, -h, h, near, far) end @@ -597,36 +606,36 @@ function update_cam!(scene::Scene, cam::Camera3D) set_proj_view!(camera(scene), proj, view) - scene.camera.eyeposition[] = cam.eyeposition[] + return scene.camera.eyeposition[] = cam.eyeposition[] end function update_cam!(scene::Scene, camera::Camera3D, area3d::Rect) @extractvalue camera (lookat, eyeposition, upvector) bb = Rect3f(area3d) width = widths(bb) - half_width = width ./ 2f0 + half_width = width ./ 2.0f0 middle = maximum(bb) - half_width old_dir = normalize(eyeposition .- lookat) camera.lookat[] = middle - neweyepos = middle .+ (1.2*norm(width) .* old_dir) + neweyepos = middle .+ (1.2 * norm(width) .* old_dir) camera.eyeposition[] = neweyepos - camera.upvector[] = Vec3f(0,0,1) + camera.upvector[] = Vec3f(0, 0, 1) if camera.attributes[:near][] === automatic camera.near[] = 0.1f0 * norm(widths(bb)) end if camera.attributes[:far][] === automatic - camera.far[] = 3f0 * norm(widths(bb)) + camera.far[] = 3.0f0 * norm(widths(bb)) end if camera.attributes[:projectiontype][] == Orthographic camera.zoom_mult[] = 0.6 * norm(width) else - camera.zoom_mult[] = 1f0 + camera.zoom_mult[] = 1.0f0 end update_cam!(scene, camera) return end -function update_cam!(scene::Scene, camera::Camera3D, eyeposition, lookat, up = Vec3f(0, 0, 1)) +function update_cam!(scene::Scene, camera::Camera3D, eyeposition, lookat, up=Vec3f(0, 0, 1)) camera.lookat[] = Vec3f(lookat) camera.eyeposition[] = Vec3f(eyeposition) camera.upvector[] = Vec3f(up) diff --git a/src/camera/old_camera3d.jl b/src/camera/old_camera3d.jl index 2d5f424cccf..2e5027fab9e 100644 --- a/src/camera/old_camera3d.jl +++ b/src/camera/old_camera3d.jl @@ -25,19 +25,19 @@ in CAD software cameras. """ function old_cam3d_cad!(scene::Scene; kw_args...) cam_attributes = merged_get!(:cam3d, scene, Attributes(kw_args)) do - Attributes( - rotationspeed = 0.01, - translationspeed = 1.0, - eyeposition = Vec3f(3), - lookat = Vec3f(0), - upvector = Vec3f(0, 0, 1), - fov = 45f0, - near = 0.01f0, - far = 100f0, - projectiontype = Perspective, - pan_button = Mouse.right, - rotate_button = Mouse.left, - move_key = nothing + return Attributes( + rotationspeed=0.01, + translationspeed=1.0, + eyeposition=Vec3f(3), + lookat=Vec3f(0), + upvector=Vec3f(0, 0, 1), + fov=45.0f0, + near=0.01f0, + far=100.0f0, + projectiontype=Perspective, + pan_button=Mouse.right, + rotate_button=Mouse.left, + move_key=nothing, ) end cam = from_dict(OldCamera3D, cam_attributes) @@ -48,9 +48,9 @@ function old_cam3d_cad!(scene::Scene; kw_args...) cameracontrols!(scene, cam) on(camera(scene), scene.px_area) do area # update cam when screen ratio changes - update_cam!(scene, cam) + return update_cam!(scene, cam) end - cam + return cam end """ @@ -61,19 +61,19 @@ the plot's axis. """ function old_cam3d_turntable!(scene::Scene; kw_args...) cam_attributes = merged_get!(:cam3d, scene, Attributes(kw_args)) do - Attributes( - rotationspeed = 0.01, - translationspeed = 1.0, - eyeposition = Vec3f(3), - lookat = Vec3f(0), - upvector = Vec3f(0, 0, 1), - fov = 45f0, - near = 0.01f0, - far = 100f0, - projectiontype = Perspective, - pan_button = Mouse.right, - rotate_button = Mouse.left, - move_key = nothing + return Attributes( + rotationspeed=0.01, + translationspeed=1.0, + eyeposition=Vec3f(3), + lookat=Vec3f(0), + upvector=Vec3f(0, 0, 1), + fov=45.0f0, + near=0.01f0, + far=100.0f0, + projectiontype=Perspective, + pan_button=Mouse.right, + rotate_button=Mouse.left, + move_key=nothing, ) end cam = from_dict(OldCamera3D, cam_attributes) @@ -84,9 +84,9 @@ function old_cam3d_turntable!(scene::Scene; kw_args...) cameracontrols!(scene, cam) on(camera(scene), scene.px_area) do area # update cam when screen ratio changes - update_cam!(scene, cam) + return update_cam!(scene, cam) end - cam + return cam end """ @@ -99,22 +99,22 @@ the plot's axis. const old_cam3d! = old_cam3d_turntable! function projection_switch( - wh::Rect2, - fov::T, near::T, far::T, - projectiontype::ProjectionEnum, zoom::T - ) where T <: Real + wh::Rect2, + fov::T, + near::T, + far::T, + projectiontype::ProjectionEnum, + zoom::T, +) where {T<:Real} aspect = T((/)(widths(wh)...)) h = T(tan(fov / 360.0 * pi) * near) w = T(h * aspect) projectiontype == Perspective && return frustum(-w, w, -h, h, near, far) h, w = h * zoom, w * zoom - orthographicprojection(-w, w, -h, h, near, far) + return orthographicprojection(-w, w, -h, h, near, far) end -function rotate_cam( - theta::Vec{3, T}, - cam_right::Vec{3, T}, cam_up::Vec{3, T}, cam_dir::Vec{3, T} - ) where T +function rotate_cam(theta::Vec{3,T}, cam_right::Vec{3,T}, cam_up::Vec{3,T}, cam_dir::Vec{3,T}) where {T} rotation = Quaternion{T}(0, 0, 0, 1) if !all(isfinite.(theta)) # We can only rotate for finite values @@ -133,7 +133,7 @@ function rotate_cam( if theta[3] != 0 rotation *= qrotation(cam_dir, theta[3]) end - rotation + return rotation end # TODO switch button and key because this is the wrong order @@ -151,7 +151,7 @@ function add_translation!(scene, cam, key, button, zoom_shift_lookat::Bool) dragging[] = false diff = (last_mousepos[] - mousepos) * cam.translationspeed[] last_mousepos[] = mousepos - translate_cam!(scene, cam, Vec3f(0f0, diff[1], diff[2])) + translate_cam!(scene, cam, Vec3f(0.0f0, diff[1], diff[2])) return Consume(true) end end @@ -163,7 +163,7 @@ function add_translation!(scene, cam, key, button, zoom_shift_lookat::Bool) mousepos = screen_relative(scene, mp) diff = (last_mousepos[] .- mousepos) * cam.translationspeed[] last_mousepos[] = mousepos - translate_cam!(scene, cam, Vec3f(0f0, diff[1], diff[2])) + translate_cam!(scene, cam, Vec3f(0.0f0, diff[1], diff[2])) return Consume(true) end return Consume(false) @@ -173,7 +173,7 @@ function add_translation!(scene, cam, key, button, zoom_shift_lookat::Bool) if ispressed(scene, button[]) && is_mouseinside(scene) cam_res = Vec2f(widths(scene.px_area[])) mouse_pos_normalized = mouseposition_px(scene) ./ cam_res - mouse_pos_normalized = 2*mouse_pos_normalized .- 1f0 + mouse_pos_normalized = 2 * mouse_pos_normalized .- 1.0f0 zoom_step = scroll[2] zoom!(scene, mouse_pos_normalized, zoom_step, zoom_shift_lookat) return Consume(true) @@ -199,7 +199,7 @@ function add_rotation!(scene, cam, button, key, fixed_axis::Bool) rot_scaling = cam.rotationspeed[] * (e.window_dpi[] * 0.005) mp = (last_mousepos[] - mousepos) * rot_scaling last_mousepos[] = mousepos - rotate_cam!(scene, cam, Vec3f(mp[1], -mp[2], 0f0), fixed_axis) + rotate_cam!(scene, cam, Vec3f(mp[1], -mp[2], 0.0f0), fixed_axis) return Consume(true) end end @@ -212,7 +212,7 @@ function add_rotation!(scene, cam, button, key, fixed_axis::Bool) rot_scaling = cam.rotationspeed[] * (e.window_dpi[] * 0.005) mp = (last_mousepos[] .- mousepos) * rot_scaling last_mousepos[] = mousepos - rotate_cam!(scene, cam, Vec3f(mp[1], -mp[2], 0f0), fixed_axis) + rotate_cam!(scene, cam, Vec3f(mp[1], -mp[2], 0.0f0), fixed_axis) return Consume(true) end return Consume(false) @@ -224,7 +224,9 @@ end Translate the camera by a translation vector given in camera space. """ -translate_cam!(scene::Scene, translation::VecTypes) = translate_cam!(scene, cameracontrols(scene), translation) +function translate_cam!(scene::Scene, translation::VecTypes) + return translate_cam!(scene, cameracontrols(scene), translation) +end function translate_cam!(scene::Scene, cam::OldCamera3D, _translation::VecTypes) translation = Vec3f(_translation) translation == Vec3f(0) && return @@ -259,12 +261,11 @@ function zoom!(scene, point::VecTypes, zoom_step, shift_lookat::Bool) cam = cameracontrols(scene) @extractvalue cam (projectiontype, lookat, eyeposition, upvector, projectiontype) - # split zoom into two components: # the offset perpendicular to `eyeposition - lookat`, based on mouse offset ~ ray_dir # the offset parallel to `eyeposition - lookat` ~ dir - ray_eye = inv(scene.camera.projection[]) * Vec4f(point[1],point[2],0,0) - ray_eye = Vec4f(ray_eye[Vec(1, 2)]...,0,0) + ray_eye = inv(scene.camera.projection[]) * Vec4f(point[1], point[2], 0, 0) + ray_eye = Vec4f(ray_eye[Vec(1, 2)]..., 0, 0) ray_dir = Vec3f((inv(scene.camera.view[]) * ray_eye)) dir = eyeposition - lookat @@ -274,19 +275,19 @@ function zoom!(scene, point::VecTypes, zoom_step, shift_lookat::Bool) if projectiontype == Perspective ray_dir *= norm(dir) end - cam.eyeposition[] = eyeposition + (ray_dir - dir) * (1f0 - 0.9f0 ^ zoom_step) - cam.lookat[] = lookat + (1f0 - 0.9f0 ^ zoom_step) * ray_dir + cam.eyeposition[] = eyeposition + (ray_dir - dir) * (1.0f0 - 0.9f0^zoom_step) + cam.lookat[] = lookat + (1.0f0 - 0.9f0^zoom_step) * ray_dir else # Rotations need more extreme eyeposition shifts step = zoom_step - while abs(step) > 0f0 + while abs(step) > 0.0f0 cam.eyeposition[] = cam.eyeposition[] + sign(zoom_step) * (ray_dir - dir * 0.1f0) dir = cam.eyeposition[] - lookat step -= sign(step) end end - update_cam!(scene, cam) + return update_cam!(scene, cam) end """ @@ -298,7 +299,7 @@ the camera according to the Euler angles (α, β, γ). """ rotate_cam!(scene::Scene, theta_v::Number...) = rotate_cam!(scene, cameracontrols(scene), theta_v) rotate_cam!(scene::Scene, theta_v::VecTypes) = rotate_cam!(scene, cameracontrols(scene), theta_v) -function rotate_cam!(scene::Scene, cam::OldCamera3D, _theta_v::VecTypes, fixed_axis::Bool = true) +function rotate_cam!(scene::Scene, cam::OldCamera3D, _theta_v::VecTypes, fixed_axis::Bool=true) theta_v = Vec3f(_theta_v) theta_v == Vec3f(0) && return #nothing to do! @extractvalue cam (eyeposition, lookat, upvector) @@ -322,26 +323,26 @@ function update_cam!(scene::Scene, cam::OldCamera3D) zoom = norm(lookat - eyeposition) # TODO this means you can't set FarClip... SAD! # TODO use boundingbox(scene) for optimal far/near - far = max(zoom * 5f0, 30f0) + far = max(zoom * 5.0f0, 30.0f0) proj = projection_switch(scene.px_area[], fov, near, far, projectiontype, zoom) view = Makie.lookat(eyeposition, lookat, upvector) set_proj_view!(camera(scene), proj, view) - scene.camera.eyeposition[] = cam.eyeposition[] + return scene.camera.eyeposition[] = cam.eyeposition[] end function update_cam!(scene::Scene, camera::OldCamera3D, area3d::Rect) @extractvalue camera (fov, near, lookat, eyeposition, upvector) bb = Rect3f(area3d) width = widths(bb) - half_width = width/2f0 + half_width = width / 2.0f0 middle = maximum(bb) - half_width old_dir = normalize(eyeposition .- lookat) camera.lookat[] = middle - neweyepos = middle .+ (1.2*norm(width) .* old_dir) + neweyepos = middle .+ (1.2 * norm(width) .* old_dir) camera.eyeposition[] = neweyepos - camera.upvector[] = Vec3f(0,0,1) + camera.upvector[] = Vec3f(0, 0, 1) camera.near[] = 0.1f0 * norm(widths(bb)) - camera.far[] = 3f0 * norm(widths(bb)) + camera.far[] = 3.0f0 * norm(widths(bb)) update_cam!(scene, camera) return end @@ -351,9 +352,11 @@ end Updates the camera's controls to point to the specified location. """ -update_cam!(scene::Scene, eyeposition, lookat, up = Vec3f(0, 0, 1)) = update_cam!(scene, cameracontrols(scene), eyeposition, lookat, up) +function update_cam!(scene::Scene, eyeposition, lookat, up=Vec3f(0, 0, 1)) + return update_cam!(scene, cameracontrols(scene), eyeposition, lookat, up) +end -function update_cam!(scene::Scene, camera::OldCamera3D, eyeposition, lookat, up = Vec3f(0, 0, 1)) +function update_cam!(scene::Scene, camera::OldCamera3D, eyeposition, lookat, up=Vec3f(0, 0, 1)) camera.lookat[] = Vec3f(lookat) camera.eyeposition[] = Vec3f(eyeposition) camera.upvector[] = Vec3f(up) diff --git a/src/camera/projection_math.jl b/src/camera/projection_math.jl index 717224c6a6a..869f6060d96 100644 --- a/src/camera/projection_math.jl +++ b/src/camera/projection_math.jl @@ -1,55 +1,81 @@ -function scalematrix(s::Vec{3, T}) where T +function scalematrix(s::Vec{3,T}) where {T} T0, T1 = zero(T), one(T) - Mat{4}( - s[1],T0, T0, T0, - T0, s[2],T0, T0, - T0, T0, s[3],T0, - T0, T0, T0, T1, - ) + return Mat{4}(s[1], T0, T0, T0, T0, s[2], T0, T0, T0, T0, s[3], T0, T0, T0, T0, T1) end -translationmatrix_x(x::T) where {T} = translationmatrix(Vec{3, T}(x, 0, 0)) -translationmatrix_y(y::T) where {T} = translationmatrix(Vec{3, T}(0, y, 0)) -translationmatrix_z(z::T) where {T} = translationmatrix(Vec{3, T}(0, 0, z)) +translationmatrix_x(x::T) where {T} = translationmatrix(Vec{3,T}(x, 0, 0)) +translationmatrix_y(y::T) where {T} = translationmatrix(Vec{3,T}(0, y, 0)) +translationmatrix_z(z::T) where {T} = translationmatrix(Vec{3,T}(0, 0, z)) -function translationmatrix(t::Vec{3, T}) where T +function translationmatrix(t::Vec{3,T}) where {T} T0, T1 = zero(T), one(T) - Mat{4}( - T1, T0, T0, T0, - T0, T1, T0, T0, - T0, T0, T1, T0, - t[1],t[2],t[3],T1, - ) + return Mat{4}(T1, T0, T0, T0, T0, T1, T0, T0, T0, T0, T1, T0, t[1], t[2], t[3], T1) end rotate(angle, axis::Vec{3}) = rotationmatrix4(qrotation(convert(Array, axis), angle)) -rotate(::Type{T}, angle::Number, axis::Vec{3}) where {T} = rotate(T(angle), convert(Vec{3, T}, axis)) +rotate(::Type{T}, angle::Number, axis::Vec{3}) where {T} = rotate(T(angle), convert(Vec{3,T}, axis)) function rotationmatrix_x(angle::Number) T0, T1 = (0, 1) - Mat{4}( - T1, T0, T0, T0, - T0, cos(angle), sin(angle), T0, - T0, -sin(angle), cos(angle), T0, - T0, T0, T0, T1 + return Mat{4}( + T1, + T0, + T0, + T0, + T0, + cos(angle), + sin(angle), + T0, + T0, + -sin(angle), + cos(angle), + T0, + T0, + T0, + T0, + T1, ) end function rotationmatrix_y(angle::Number) T0, T1 = (0, 1) - Mat{4}( - cos(angle), T0, -sin(angle), T0, - T0, T1, T0, T0, - sin(angle), T0, cos(angle), T0, - T0, T0, T0, T1 + return Mat{4}( + cos(angle), + T0, + -sin(angle), + T0, + T0, + T1, + T0, + T0, + sin(angle), + T0, + cos(angle), + T0, + T0, + T0, + T0, + T1, ) end function rotationmatrix_z(angle::Number) T0, T1 = (0, 1) - Mat{4}( - cos(angle), sin(angle), T0, T0, - -sin(angle), cos(angle), T0, T0, - T0, T0, T1, T0, - T0, T0, T0, T1 + return Mat{4}( + cos(angle), + sin(angle), + T0, + T0, + -sin(angle), + cos(angle), + T0, + T0, + T0, + T0, + T1, + T0, + T0, + T0, + T0, + T1, ) end @@ -76,14 +102,26 @@ end M : array View frustum matrix (4x4). """ -function frustum(left::T, right::T, bottom::T, top::T, znear::T, zfar::T) where T +function frustum(left::T, right::T, bottom::T, top::T, znear::T, zfar::T) where {T} (right == left || bottom == top || znear == zfar) && return Mat{4,4,T}(I) T0, T1, T2 = zero(T), one(T), T(2) return Mat{4}( - T2 * znear / (right - left), T0, T0, T0, - T0, T2 * znear / (top - bottom), T0, T0, - (right + left) / (right - left), (top + bottom) / (top - bottom), -(zfar + znear) / (zfar - znear), -T1, - T0, T0, (-T2 * znear * zfar) / (zfar - znear), T0 + T2 * znear / (right - left), + T0, + T0, + T0, + T0, + T2 * znear / (top - bottom), + T0, + T0, + (right + left) / (right - left), + (top + bottom) / (top - bottom), + -(zfar + znear) / (zfar - znear), + -T1, + T0, + T0, + (-T2 * znear * zfar) / (zfar - znear), + T0, ) end @@ -94,31 +132,27 @@ the y-axis (measured in degrees), the specified `aspect` ratio, and near and far clipping planes `znear`, `zfar`. Optionally specify the element type `T` of the matrix. """ -function perspectiveprojection(fovy::T, aspect::T, znear::T, zfar::T) where T +function perspectiveprojection(fovy::T, aspect::T, znear::T, zfar::T) where {T} (znear == zfar) && error("znear ($znear) must be different from tfar ($zfar)") h = T(tan(fovy / 360.0 * pi) * znear) w = T(h * aspect) return frustum(-w, w, -h, h, znear, zfar) end -function perspectiveprojection( - ::Type{T}, fovy::Number, aspect::Number, znear::Number, zfar::Number - ) where T - perspectiveprojection(T(fovy), T(aspect), T(znear), T(zfar)) +function perspectiveprojection(::Type{T}, fovy::Number, aspect::Number, znear::Number, zfar::Number) where {T} + return perspectiveprojection(T(fovy), T(aspect), T(znear), T(zfar)) end """ `proj = perspectiveprojection([T], rect, fov, near, far)` defines the projection ratio in terms of the rectangular view size `rect` rather than the aspect ratio. """ -function perspectiveprojection(wh::Rect2, fov::T, near::T, far::T) where T - perspectiveprojection(fov, T(wh.w/wh.h), near, far) +function perspectiveprojection(wh::Rect2, fov::T, near::T, far::T) where {T} + return perspectiveprojection(fov, T(wh.w / wh.h), near, far) end -function perspectiveprojection( - ::Type{T}, wh::Rect2, fov::Number, near::Number, far::Number - ) where T - perspectiveprojection(T(fov), T(wh.w/wh.h), T(near), T(far)) +function perspectiveprojection(::Type{T}, wh::Rect2, fov::Number, near::Number, far::Number) where {T} + return perspectiveprojection(T(fov), T(wh.w / wh.h), T(near), T(far)) end """ @@ -129,69 +163,87 @@ the component of `up` that is perpendicular to the vector pointing from `eyeposition` to `lookat` will be used. All inputs must be supplied as 3-vectors. """ -function lookat(eyePos::Vec{3, T}, lookAt::Vec{3, T}, up::Vec{3, T}) where T - zaxis = normalize(eyePos-lookAt) - xaxis = normalize(cross(up, zaxis)) - yaxis = normalize(cross(zaxis, xaxis)) +function lookat(eyePos::Vec{3,T}, lookAt::Vec{3,T}, up::Vec{3,T}) where {T} + zaxis = normalize(eyePos - lookAt) + xaxis = normalize(cross(up, zaxis)) + yaxis = normalize(cross(zaxis, xaxis)) T0, T1 = zero(T), one(T) return Mat{4}( - xaxis[1], yaxis[1], zaxis[1], T0, - xaxis[2], yaxis[2], zaxis[2], T0, - xaxis[3], yaxis[3], zaxis[3], T0, - T0, T0, T0, T1 + xaxis[1], + yaxis[1], + zaxis[1], + T0, + xaxis[2], + yaxis[2], + zaxis[2], + T0, + xaxis[3], + yaxis[3], + zaxis[3], + T0, + T0, + T0, + T0, + T1, ) * translationmatrix(-eyePos) end -function lookat(::Type{T}, eyePos::Vec{3}, lookAt::Vec{3}, up::Vec{3}) where T - lookat(Vec{3,T}(eyePos), Vec{3,T}(lookAt), Vec{3,T}(up)) +function lookat(::Type{T}, eyePos::Vec{3}, lookAt::Vec{3}, up::Vec{3}) where {T} + return lookat(Vec{3,T}(eyePos), Vec{3,T}(lookAt), Vec{3,T}(up)) end -function orthographicprojection(wh::Rect2, near::T, far::T) where T +function orthographicprojection(wh::Rect2, near::T, far::T) where {T} w, h = widths(wh) - orthographicprojection(zero(T), T(w), zero(T), T(h), near, far) + return orthographicprojection(zero(T), T(w), zero(T), T(h), near, far) end -function orthographicprojection( - ::Type{T}, wh::Rect2, near::Number, far::Number - ) where T - orthographicprojection(wh, T(near), T(far)) +function orthographicprojection(::Type{T}, wh::Rect2, near::Number, far::Number) where {T} + return orthographicprojection(wh, T(near), T(far)) end -function orthographicprojection( - left::T, right::T, - bottom::T, top::T, - znear::T, zfar::T - ) where T - (right==left || bottom==top || znear==zfar) && return Mat{4,4,T}(I) +function orthographicprojection(left::T, right::T, bottom::T, top::T, znear::T, zfar::T) where {T} + (right == left || bottom == top || znear == zfar) && return Mat{4,4,T}(I) T0, T1, T2 = zero(T), one(T), T(2) - Mat{4}( - T2/(right-left), T0, T0, T0, - T0, T2/(top-bottom), T0, T0, - T0, T0, -T2/(zfar-znear), T0, - -(right+left)/(right-left), -(top+bottom)/(top-bottom), -(zfar+znear)/(zfar-znear), T1 + return Mat{4}( + T2 / (right - left), + T0, + T0, + T0, + T0, + T2 / (top - bottom), + T0, + T0, + T0, + T0, + -T2 / (zfar - znear), + T0, + -(right + left) / (right - left), + -(top + bottom) / (top - bottom), + -(zfar + znear) / (zfar - znear), + T1, ) end -function orthographicprojection(::Type{T}, - left ::Number, right::Number, - bottom::Number, top ::Number, - znear ::Number, zfar ::Number - ) where T - orthographicprojection( - T(left), T(right), - T(bottom), T(top), - T(znear), T(zfar) - ) +function orthographicprojection( + ::Type{T}, + left::Number, + right::Number, + bottom::Number, + top::Number, + znear::Number, + zfar::Number, +) where {T} + return orthographicprojection(T(left), T(right), T(bottom), T(top), T(znear), T(zfar)) end mutable struct Pivot{T} - origin ::Vec{3, T} - xaxis ::Vec{3, T} - yaxis ::Vec{3, T} - zaxis ::Vec{3, T} - rotation ::Quaternion - translation ::Vec{3, T} - scale ::Vec{3, T} + origin::Vec{3,T} + xaxis::Vec{3,T} + yaxis::Vec{3,T} + zaxis::Vec{3,T} + rotation::Quaternion + translation::Vec{3,T} + scale::Vec{3,T} end GeometryBasics.origin(p::Pivot) = p.origin @@ -199,31 +251,43 @@ GeometryBasics.origin(p::Pivot) = p.origin rotationmatrix4(q::Quaternion{T}) where {T} = Mat4{T}(q) function transformationmatrix(p::Pivot) - translationmatrix(p.origin) * #go to origin - rotationmatrix4(p.rotation) * #apply rotation - translationmatrix(-p.origin)* # go back to origin - translationmatrix(p.translation) #apply translation + return translationmatrix(p.origin) * #go to origin + rotationmatrix4(p.rotation) * #apply rotation + translationmatrix(-p.origin) * # go back to origin + translationmatrix(p.translation) #apply translation end function transformationmatrix(translation, scale) T = eltype(translation) T0, T1 = zero(T), one(T) return Mat{4}( - scale[1],T0, T0, T0, - T0, scale[2],T0, T0, - T0, T0, scale[3],T0, - translation[1], translation[2], translation[3], T1 + scale[1], + T0, + T0, + T0, + T0, + scale[2], + T0, + T0, + T0, + T0, + scale[3], + T0, + translation[1], + translation[2], + translation[3], + T1, ) end function transformationmatrix(translation, scale, rotation::Quaternion) trans_scale = transformationmatrix(translation, scale) rotation = Mat4f(rotation) - trans_scale*rotation + return trans_scale * rotation end #Calculate rotation between two vectors -function rotation(u::Vec{3, T}, v::Vec{3, T}) where T +function rotation(u::Vec{3,T}, v::Vec{3,T}) where {T} # It is important that the inputs are of equal length when # calculating the half-way vector. u, v = normalize(u), normalize(v) @@ -231,87 +295,65 @@ function rotation(u::Vec{3, T}, v::Vec{3, T}) where T # in this case will be (0, 0, 0), which cannot be normalized. if (u == -v) # 180 degree rotation around any orthogonal vector - other = (abs(dot(u, Vec{3, T}(1,0,0))) < 1.0) ? Vec{3, T}(1,0,0) : Vec{3, T}(0,1,0) + other = (abs(dot(u, Vec{3,T}(1, 0, 0))) < 1.0) ? Vec{3,T}(1, 0, 0) : Vec{3,T}(0, 1, 0) return qrotation(normalize(cross(u, other)), T(180)) end - half = normalize(u+v) + half = normalize(u + v) return Quaternion(cross(u, half)..., dot(u, half)) end -function to_world(scene::Scene, point::T) where T <: StaticVector +function to_world(scene::Scene, point::T) where {T<:StaticVector} cam = scene.camera x = to_world( point, - inv(transformationmatrix(scene)[]) * - inv(cam.view[]) * - inv(cam.projection[]), - T(widths(pixelarea(scene)[])) + inv(transformationmatrix(scene)[]) * inv(cam.view[]) * inv(cam.projection[]), + T(widths(pixelarea(scene)[])), ) - Point2f(x[1], x[2]) + return Point2f(x[1], x[2]) end w_component(x::Point) = 1.0 w_component(x::Vec) = 0.0 -function to_world( - p::StaticVector{N, T}, - prj_view_inv::Mat4, - cam_res::StaticVector - ) where {N, T} +function to_world(p::StaticVector{N,T}, prj_view_inv::Mat4, cam_res::StaticVector) where {N,T} VT = typeof(p) clip_space = ((VT(p) ./ VT(cam_res)) .* T(2)) .- T(1) - pix_space = Vec{4, T}( - clip_space[1], - clip_space[2], - T(0), w_component(p) - ) + pix_space = Vec{4,T}(clip_space[1], clip_space[2], T(0), w_component(p)) ws = prj_view_inv * pix_space - ws ./ ws[4] + return ws ./ ws[4] end -function to_world( - p::Vec{N, T}, - prj_view_inv::Mat4, - cam_res::StaticVector - ) where {N, T} - to_world(Point(p), prj_view_inv, cam_res) .- - to_world(zeros(Point{N, T}), prj_view_inv, cam_res) +function to_world(p::Vec{N,T}, prj_view_inv::Mat4, cam_res::StaticVector) where {N,T} + return to_world(Point(p), prj_view_inv, cam_res) .- to_world(zeros(Point{N,T}), prj_view_inv, cam_res) end -function project(scene::Scene, point::T) where T<:StaticVector +function project(scene::Scene, point::T) where {T<:StaticVector} cam = scene.camera area = pixelarea(scene)[] # TODO, I think we need .+ minimum(area) # Which would be semi breaking at this point though, I suppose - return project( - cam.projectionview[] * - transformationmatrix(scene)[], - Vec2f(widths(area)), - Point(point) - ) + return project(cam.projectionview[] * transformationmatrix(scene)[], Vec2f(widths(area)), Point(point)) end -function project(matrix::Mat4f, p::T, dim4 = 1.0) where T <: VecTypes +function project(matrix::Mat4f, p::T, dim4=1.0) where {T<:VecTypes} p = to_ndim(Vec4f, to_ndim(Vec3f, p, 0.0), dim4) p = matrix * p - to_ndim(T, p, 0.0) + return to_ndim(T, p, 0.0) end function project(proj_view::Mat4f, resolution::Vec2, point::Point) - p4d = to_ndim(Vec4f, to_ndim(Vec3f, point, 0f0), 1f0) + p4d = to_ndim(Vec4f, to_ndim(Vec3f, point, 0.0f0), 1.0f0) clip = proj_view * p4d p = (clip ./ clip[4])[Vec(1, 2)] p = Vec2f(p[1], p[2]) - return (((p .+ 1f0) ./ 2f0) .* (resolution .- 1f0)) .+ 1f0 + return (((p .+ 1.0f0) ./ 2.0f0) .* (resolution .- 1.0f0)) .+ 1.0f0 end -function project_point2(mat4::Mat4, point2::Point2) - Point2f(mat4 * to_ndim(Point4f, to_ndim(Point3f, point2, 0), 1)) -end +project_point2(mat4::Mat4, point2::Point2) = Point2f(mat4 * to_ndim(Point4f, to_ndim(Point3f, point2, 0), 1)) -function transform(model::Mat4, x::T) where T +function transform(model::Mat4, x::T) where {T} x4d = to_ndim(Vec4f, x, 0.0) - to_ndim(T, model * x4d, 0.0) + return to_ndim(T, model * x4d, 0.0) end # project between different coordinate systems/spaces diff --git a/src/colorsampler.jl b/src/colorsampler.jl index 7bca6b4c84a..ef48f2456ed 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -1,6 +1,6 @@ @enum Interpolation Linear Nearest -struct Scaling{F, R} +struct Scaling{F,R} # a function to scale a value by, e.g. log10, sqrt etc scaling_function::F # If nothing, no scaling applied! @@ -9,11 +9,11 @@ end Scaling() = Scaling(identity, nothing) -const NoScaling = Scaling{typeof(identity), Nothing} +const NoScaling = Scaling{typeof(identity),Nothing} -struct Sampler{N, V} <: AbstractArray{RGBAf, 1} +struct Sampler{N,V} <: AbstractArray{RGBAf,1} # the colors to sample from! - colors::AbstractArray{T, N} where T + colors::AbstractArray{T,N} where {T} # or an array of values, which are used to index into colors via interpolation! values::V # additional alpha that gets multiplied @@ -33,7 +33,9 @@ You can use `norm`, to change the range of 0..1 to whatever you want. """ function interpolated_getindex(cmap::AbstractArray, value::Number, norm::VecTypes) cmin, cmax = norm - cmin == cmax && error("Can't interpolate in a range where cmin == cmax. This can happen, for example, if a colorrange is set automatically but there's only one unique value present.") + cmin == cmax && error( + "Can't interpolate in a range where cmin == cmax. This can happen, for example, if a colorrange is set automatically but there's only one unique value present.", + ) i01 = clamp((value - cmin) / (cmax - cmin), 0.0, 1.0) return interpolated_getindex(cmap, i01) end @@ -43,7 +45,7 @@ end Like getindex, but accepts values between 0..1 for `value` and interpolates those to the full range of `cmap`. """ -function interpolated_getindex(cmap::AbstractArray{T}, i01::AbstractFloat) where T +function interpolated_getindex(cmap::AbstractArray{T}, i01::AbstractFloat) where {T} if !isfinite(i01) error("Looking up a non-finite or NaN value in a colormap is undefined.") end @@ -95,7 +97,7 @@ function Base.getindex(sampler::Sampler, i)::RGBAf return RGBAf(color(c), alpha(c) * sampler.alpha) end -function Base.getindex(sampler::Sampler{2, <: AbstractVector{Vec2f}}, i)::RGBAf +function Base.getindex(sampler::Sampler{2,<:AbstractVector{Vec2f}}, i)::RGBAf uv = sampler.values[i] colors = sampler.colors # indexing confirming to OpenGL uv indexing @@ -106,14 +108,17 @@ function Base.getindex(sampler::Sampler{2, <: AbstractVector{Vec2f}}, i)::RGBAf return RGBAf(color(c), alpha(c) * sampler.alpha) end -function sampler(cmap::Union{Symbol, String}, n::Int = 20; - scaling=Scaling(), alpha=1.0, interpolation=Linear) - return sampler(cmap, LinRange(0, 1, n); scaling = scaling, alpha = alpha, interpolation = interpolation) +function sampler(cmap::Union{Symbol,String}, n::Int=20; scaling=Scaling(), alpha=1.0, interpolation=Linear) + return sampler(cmap, LinRange(0, 1, n); scaling=scaling, alpha=alpha, interpolation=interpolation) end -function sampler(cmap::Union{Symbol, String}, values::AbstractVector{<: AbstractFloat}; - scaling=Scaling(), alpha=1.0, interpolation=Linear) - +function sampler( + cmap::Union{Symbol,String}, + values::AbstractVector{<:AbstractFloat}; + scaling=Scaling(), + alpha=1.0, + interpolation=Linear, +) cs = PlotUtils.get_colorscheme(cmap) colors = getindex.(Ref(cs), values) @@ -121,25 +126,27 @@ function sampler(cmap::Union{Symbol, String}, values::AbstractVector{<: Abstract return Sampler(colors, values, alpha, interpolation, scaling) end -function sampler(cmap::Vector{<: Colorant}, values::AbstractVector{<: AbstractFloat}; - scaling=Scaling(), alpha=1.0, interpolation=Linear) +function sampler( + cmap::Vector{<:Colorant}, + values::AbstractVector{<:AbstractFloat}; + scaling=Scaling(), + alpha=1.0, + interpolation=Linear, +) return Sampler(RGBAf.(cmap), values, alpha, interpolation, scaling) end -function sampler(cmap::AbstractVector, values, crange; - alpha=1.0, interpolation=Linear) +function sampler(cmap::AbstractVector, values, crange; alpha=1.0, interpolation=Linear) return Sampler(to_color.(cmap), values, alpha, interpolation, Scaling(identity, crange)) end # uv texture sampler -function sampler(cmap::Matrix{<: Colorant}, uv::AbstractVector{Vec2f}; - alpha=1.0, interpolation=Linear) +function sampler(cmap::Matrix{<:Colorant}, uv::AbstractVector{Vec2f}; alpha=1.0, interpolation=Linear) return Sampler(cmap, uv, alpha, interpolation, Scaling()) end - function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) colormap = get_attribute(primitive, :colormap)::Vector{RGBAf} - _colorrange = get_attribute(primitive, :colorrange)::Union{Nothing, Vec2f} + _colorrange = get_attribute(primitive, :colorrange)::Union{Nothing,Vec2f} if isnothing(_colorrange) # TODO, plot primitive should always expand automatic values colorrange = Vec2f(extrema_nan(numbers)) @@ -149,7 +156,7 @@ function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) lowclip = get_attribute(primitive, :lowclip) highclip = get_attribute(primitive, :highclip) - nan_color = get_attribute(primitive, :nan_color, RGBAf(0,0,0,0)) + nan_color = get_attribute(primitive, :nan_color, RGBAf(0, 0, 0, 0)) cmin, cmax = colorrange::Vec2f @@ -164,6 +171,7 @@ function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) return interpolated_getindex( colormap, Float64(number), # ints don't work in interpolated_getindex - (cmin, cmax)) + (cmin, cmax), + ) end end diff --git a/src/conversions.jl b/src/conversions.jl index 215edf871bb..0628cdf05aa 100644 --- a/src/conversions.jl +++ b/src/conversions.jl @@ -1,7 +1,7 @@ ################################################################################ # Type Conversions # ################################################################################ -const RangeLike = Union{AbstractRange, AbstractVector, ClosedInterval} +const RangeLike = Union{AbstractRange,AbstractVector,ClosedInterval} # if no plot type based conversion is defined, we try using a trait function convert_arguments(T::PlotFunc, args...; kw...) @@ -25,7 +25,7 @@ function convert_arguments(T::PlotFunc, args...; kw...) You can define a method for `Makie.convert_arguments` (a type recipe) for these types or their supertypes to make this set of arguments convertible (See http://docs.makie.org/stable/documentation/recipes/index.html). Alternatively, you can define `Makie.convert_single_argument` for single arguments which have types that are unknown to Makie but which can be converted to known types and fed back to the conversion pipeline. - """ + """, ) else rethrow(ee) @@ -48,7 +48,7 @@ function convert_arguments_individually(T::PlotFunc, args...) end # otherwise we try converting our newly single-converted args again because # now a normal conversion method might work again - convert_arguments(T, single_converted...) + return convert_arguments(T, single_converted...) end function recursively_convert_argument(x) @@ -68,13 +68,13 @@ end convert_single_argument(x) = x # replace missings with NaNs -function convert_single_argument(a::AbstractArray{<:Union{Missing, <:Real}}) - [ismissing(x) ? NaN32 : convert(Float32, x) for x in a] +function convert_single_argument(a::AbstractArray{<:Union{Missing,<:Real}}) + return [ismissing(x) ? NaN32 : convert(Float32, x) for x in a] end # same for points -function convert_single_argument(a::AbstractArray{<:Union{Missing, <:Point{N}}}) where N - [ismissing(x) ? Point{N, Float32}(NaN32) : Point{N, Float32}(x) for x in a] +function convert_single_argument(a::AbstractArray{<:Union{Missing,<:Point{N}}}) where {N} + return [ismissing(x) ? Point{N,Float32}(NaN32) : Point{N,Float32}(x) for x in a] end ################################################################################ @@ -84,25 +84,21 @@ end """ Wrap a single point or equivalent object in a single-element array. """ -function convert_arguments(::PointBased, x::Real, y::Real) - ([Point2f(x, y)],) -end +convert_arguments(::PointBased, x::Real, y::Real) = ([Point2f(x, y)],) -function convert_arguments(::PointBased, x::Real, y::Real, z::Real) - ([Point3f(x, y, z)],) -end +convert_arguments(::PointBased, x::Real, y::Real, z::Real) = ([Point3f(x, y, z)],) -function convert_arguments(::PointBased, position::VecTypes{N, <: Number}) where N - ([convert(Point{N, Float32}, position)],) +function convert_arguments(::PointBased, position::VecTypes{N,<:Number}) where {N} + return ([convert(Point{N,Float32}, position)],) end -function convert_arguments(::PointBased, positions::AbstractVector{<: VecTypes{N, <: Number}}) where N - (elconvert(Point{N, Float32}, positions),) +function convert_arguments(::PointBased, positions::AbstractVector{<:VecTypes{N,<:Number}}) where {N} + return (elconvert(Point{N,Float32}, positions),) end -function convert_arguments(::PointBased, positions::SubArray{<: VecTypes, 1}) +function convert_arguments(::PointBased, positions::SubArray{<:VecTypes,1}) # TODO figure out a good subarray solution - (positions,) + return (positions,) end """ @@ -110,7 +106,7 @@ Enables to use scatter like a surface plot with x::Vector, y::Vector, z::Matrix spanning z over the grid spanned by x y """ function convert_arguments(::PointBased, x::AbstractVector, y::AbstractVector, z::AbstractMatrix) - (vec(Point3f.(x, y', z)),) + return (vec(Point3f.(x, y', z)),) end """ convert_arguments(P, x, y, z)::(Vector) @@ -129,13 +125,18 @@ Takes an input GeometryPrimitive `x` and decomposes it to points. """ convert_arguments(p::PointBased, x::GeometryPrimitive) = convert_arguments(p, decompose(Point, x)) -function convert_arguments(::PointBased, pos::AbstractMatrix{<: Number}) - (to_vertices(pos),) -end +convert_arguments(::PointBased, pos::AbstractMatrix{<:Number}) = (to_vertices(pos),) convert_arguments(P::PointBased, x::AbstractVector{<:Real}, y::AbstractVector{<:Real}) = (Point2f.(x, y),) -convert_arguments(P::PointBased, x::AbstractVector{<:Real}, y::AbstractVector{<:Real}, z::AbstractVector{<:Real}) = (Point3f.(x, y, z),) +function convert_arguments( + P::PointBased, + x::AbstractVector{<:Real}, + y::AbstractVector{<:Real}, + z::AbstractVector{<:Real}, +) + return (Point3f.(x, y, z),) +end """ convert_arguments(P, y)::Vector @@ -155,9 +156,12 @@ from `x` and `y`. `P` is the plot Type (it is optional). """ #convert_arguments(::PointBased, x::RealVector, y::RealVector) = (Point2f.(x, y),) -convert_arguments(P::PointBased, x::ClosedInterval, y::RealVector) = convert_arguments(P, LinRange(extrema(x)..., length(y)), y) -convert_arguments(P::PointBased, x::RealVector, y::ClosedInterval) = convert_arguments(P, x, LinRange(extrema(y)..., length(x))) - +function convert_arguments(P::PointBased, x::ClosedInterval, y::RealVector) + return convert_arguments(P, LinRange(extrema(x)..., length(y)), y) +end +function convert_arguments(P::PointBased, x::RealVector, y::ClosedInterval) + return convert_arguments(P, x, LinRange(extrema(y)..., length(x))) +end """ convert_arguments(P, x)::(Vector) @@ -171,26 +175,22 @@ function convert_arguments(P::PointBased, x::Rect2) return convert_arguments(P, decompose(Point2f, x)[[1, 2, 4, 3]]) end -function convert_arguments(P::PointBased, mesh::AbstractMesh) - return convert_arguments(P, decompose(Point3f, mesh)) -end +convert_arguments(P::PointBased, mesh::AbstractMesh) = convert_arguments(P, decompose(Point3f, mesh)) -function convert_arguments(PB::PointBased, linesegments::FaceView{<:Line, P}) where {P<:AbstractPoint} +function convert_arguments(PB::PointBased, linesegments::FaceView{<:Line,P}) where {P<:AbstractPoint} # TODO FaceView should be natively supported by backends! return convert_arguments(PB, collect(reinterpret(P, linesegments))) end -function convert_arguments(P::PointBased, rect::Rect3) - return (decompose(Point3f, rect),) -end +convert_arguments(P::PointBased, rect::Rect3) = (decompose(Point3f, rect),) -function convert_arguments(P::Type{<: LineSegments}, rect::Rect3) +function convert_arguments(P::Type{<:LineSegments}, rect::Rect3) f = decompose(LineFace{Int}, rect) p = connect(decompose(Point3f, rect), f) return convert_arguments(P, p) end -function convert_arguments(::Type{<: Lines}, rect::Rect3) +function convert_arguments(::Type{<:Lines}, rect::Rect3) points = unique(decompose(Point3f, rect)) push!(points, Point3f(NaN)) # use to seperate linesegments return (points[[1, 2, 3, 4, 1, 5, 6, 2, 9, 6, 8, 3, 9, 5, 7, 4, 9, 7, 8]],) @@ -210,7 +210,7 @@ end Takes an input `Array{LineString}` or a `MultiLineString` and decomposes it to points. """ -function convert_arguments(PB::PointBased, linestring::Union{Array{<:LineString}, MultiLineString}) +function convert_arguments(PB::PointBased, linestring::Union{Array{<:LineString},MultiLineString}) arr = copy(convert_arguments(PB, linestring[1])[1]) for ls in 2:length(linestring) push!(arr, Point2f(NaN)) @@ -246,7 +246,7 @@ end Takes an input `Array{Polygon}` or a `MultiPolygon` and decomposes it to points. """ -function convert_arguments(PB::PointBased, mp::Union{Array{<:Polygon}, MultiPolygon}) +function convert_arguments(PB::PointBased, mp::Union{Array{<:Polygon},MultiPolygon}) arr = copy(convert_arguments(PB, mp[1])[1]) for p in 2:length(mp) push!(arr, Point2f(NaN)) @@ -255,7 +255,6 @@ function convert_arguments(PB::PointBased, mp::Union{Array{<:Polygon}, MultiPoly return (arr,) end - ################################################################################ # SurfaceLike # ################################################################################ @@ -268,14 +267,19 @@ function edges(v::AbstractVector) # Equivalent to # mids = 0.5 .* (v[1:end-1] .+ v[2:end]) # borders = [2v[1] - mids[1]; mids; 2v[end] - mids[end]] - borders = [0.5 * (v[max(1, i)] + v[min(end, i+1)]) for i in 0:length(v)] + borders = [0.5 * (v[max(1, i)] + v[min(end, i + 1)]) for i in 0:length(v)] borders[1] = 2borders[1] - borders[2] - borders[end] = 2borders[end] - borders[end-1] + borders[end] = 2borders[end] - borders[end - 1] return borders end end -function adjust_axes(::DiscreteSurface, x::AbstractVector{<:Number}, y::AbstractVector{<:Number}, z::AbstractMatrix) +function adjust_axes( + ::DiscreteSurface, + x::AbstractVector{<:Number}, + y::AbstractVector{<:Number}, + z::AbstractMatrix, +) x̂, ŷ = map((x, y), size(z)) do v, sz return length(v) == sz ? edges(v) : v end @@ -292,14 +296,26 @@ whether they represent edges or centers of the heatmap bins. If they are centers, convert to edges. Convert eltypes to `Float32` and return outputs as a `Tuple`. """ -function convert_arguments(SL::SurfaceLike, x::AbstractVecOrMat{<: Number}, y::AbstractVecOrMat{<: Number}, z::AbstractMatrix{<: Union{Number, Colorant}}) +function convert_arguments( + SL::SurfaceLike, + x::AbstractVecOrMat{<:Number}, + y::AbstractVecOrMat{<:Number}, + z::AbstractMatrix{<:Union{Number,Colorant}}, +) return map(el32convert, adjust_axes(SL, x, y, z)) end -function convert_arguments(SL::SurfaceLike, x::AbstractVecOrMat{<: Number}, y::AbstractVecOrMat{<: Number}, z::AbstractMatrix{<:Number}) +function convert_arguments( + SL::SurfaceLike, + x::AbstractVecOrMat{<:Number}, + y::AbstractVecOrMat{<:Number}, + z::AbstractMatrix{<:Number}, +) return map(el32convert, adjust_axes(SL, x, y, z)) end -convert_arguments(sl::SurfaceLike, x::AbstractMatrix, y::AbstractMatrix) = convert_arguments(sl, x, y, zeros(size(y))) +function convert_arguments(sl::SurfaceLike, x::AbstractMatrix, y::AbstractMatrix) + return convert_arguments(sl, x, y, zeros(size(y))) +end """ convert_arguments(P, x, y, z)::Tuple{ClosedInterval, ClosedInterval, Matrix} @@ -309,7 +325,7 @@ linspaces with size(z, 1/2) `P` is the plot Type (it is optional). """ function convert_arguments(P::SurfaceLike, x::ClosedInterval, y::ClosedInterval, z::AbstractMatrix) - convert_arguments(P, to_linspace(x, size(z, 1)), to_linspace(y, size(z, 2)), z) + return convert_arguments(P, to_linspace(x, size(z, 1)), to_linspace(y, size(z, 2)), z) end """ @@ -322,15 +338,20 @@ and stores the `ClosedInterval` to `n` and `m`, plus the original matrix in a Tu """ function convert_arguments(sl::SurfaceLike, data::AbstractMatrix) n, m = Float32.(size(data)) - convert_arguments(sl, 0f0 .. n, 0f0 .. m, el32convert(data)) + return convert_arguments(sl, 0.0f0 .. n, 0.0f0 .. m, el32convert(data)) end function convert_arguments(ds::DiscreteSurface, data::AbstractMatrix) n, m = Float32.(size(data)) - convert_arguments(ds, edges(1:n), edges(1:m), el32convert(data)) + return convert_arguments(ds, edges(1:n), edges(1:m), el32convert(data)) end -function convert_arguments(SL::SurfaceLike, x::AbstractVector{<:Number}, y::AbstractVector{<:Number}, z::AbstractVector{<:Number}) +function convert_arguments( + SL::SurfaceLike, + x::AbstractVector{<:Number}, + y::AbstractVector{<:Number}, + z::AbstractVector{<:Number}, +) if !(length(x) == length(y) == length(z)) error("x, y and z need to have the same length. Lengths are $(length.((x, y, z)))") end @@ -352,10 +373,9 @@ function convert_arguments(SL::SurfaceLike, x::AbstractVector{<:Number}, y::Abst j = searchsortedfirst(y_centers, yi) @inbounds zs[i, j] = zi end - convert_arguments(SL, x_centers, y_centers, zs) + return convert_arguments(SL, x_centers, y_centers, zs) end - """ convert_arguments(P, x, y, f)::(Vector, Vector, Matrix) @@ -363,7 +383,12 @@ Takes vectors `x` and `y` and the function `f`, and applies `f` on the grid that This is equivalent to `f.(x, y')`. `P` is the plot Type (it is optional). """ -function convert_arguments(sl::SurfaceLike, x::AbstractVector{T1}, y::AbstractVector{T2}, f::Function) where {T1, T2} +function convert_arguments( + sl::SurfaceLike, + x::AbstractVector{T1}, + y::AbstractVector{T2}, + f::Function, +) where {T1,T2} if !applicable(f, x[1], y[1]) error("You need to pass a function with signature f(x::$T1, y::$T2). Found: $f") end @@ -385,12 +410,18 @@ and stores the `ClosedInterval` to `n`, `m` and `k`, plus the original array in `P` is the plot Type (it is optional). """ -function convert_arguments(::VolumeLike, data::AbstractArray{T, 3}) where T +function convert_arguments(::VolumeLike, data::AbstractArray{T,3}) where {T} n, m, k = Float32.(size(data)) - return (0f0 .. n, 0f0 .. m, 0f0 .. k, el32convert(data)) + return (0.0f0 .. n, 0.0f0 .. m, 0.0f0 .. k, el32convert(data)) end -function convert_arguments(::VolumeLike, x::RangeLike, y::RangeLike, z::RangeLike, data::AbstractArray{T, 3}) where T +function convert_arguments( + ::VolumeLike, + x::RangeLike, + y::RangeLike, + z::RangeLike, + data::AbstractArray{T,3}, +) where {T} return (x, y, z, el32convert(data)) end """ @@ -400,11 +431,16 @@ Takes 3 `AbstractVector` `x`, `y`, and `z` and the `AbstractMatrix` `i`, and put `P` is the plot Type (it is optional). """ -function convert_arguments(::VolumeLike, x::AbstractVector, y::AbstractVector, z::AbstractVector, i::AbstractArray{T, 3}) where T - (x, y, z, el32convert(i)) +function convert_arguments( + ::VolumeLike, + x::AbstractVector, + y::AbstractVector, + z::AbstractVector, + i::AbstractArray{T,3}, +) where {T} + return (x, y, z, el32convert(i)) end - """ convert_arguments(P, x, y, z, f)::(Vector, Vector, Vector, Matrix) @@ -419,7 +455,7 @@ function convert_arguments(::VolumeLike, x::AbstractVector, y::AbstractVector, z end _x, _y, _z = ntuple(Val(3)) do i A = (x, y, z)[i] - reshape(A, ntuple(j-> j != i ? 1 : length(A), Val(3))) + return reshape(A, ntuple(j -> j != i ? 1 : length(A), Val(3))) end return (x, y, z, el32convert.(f.(_x, _y, _z))) end @@ -428,7 +464,7 @@ end # <:Lines # ################################################################################ -function convert_arguments(::Type{<: Lines}, x::Rect2) +function convert_arguments(::Type{<:Lines}, x::Rect2) # TODO fix the order of decompose points = decompose(Point2f, x) return (points[[1, 2, 4, 3, 1]],) @@ -442,11 +478,14 @@ end Accepts a Vector of Pair of Points (e.g. `[Point(0, 0) => Point(1, 1), ...]`) to encode e.g. linesegments or directions. """ -function convert_arguments(::Type{<: LineSegments}, positions::AbstractVector{E}) where E <: Union{Pair{A, A}, Tuple{A, A}} where A <: VecTypes{N, T} where {N, T} - (elconvert(Point{N, Float32}, reinterpret(Point{N, T}, positions)),) +function convert_arguments( + ::Type{<:LineSegments}, + positions::AbstractVector{E}, +) where {E<:Union{Pair{A,A},Tuple{A,A}}} where {A<:VecTypes{N,T}} where {N,T} + return (elconvert(Point{N,Float32}, reinterpret(Point{N,T}, positions)),) end -function convert_arguments(::Type{<: LineSegments}, x::Rect2) +function convert_arguments(::Type{<:LineSegments}, x::Rect2) # TODO fix the order of decompose points = decompose(Point2f, x) return (points[[1, 2, 2, 4, 4, 3, 3, 1]],) @@ -463,7 +502,6 @@ Takes an input `AbstractString` `x` and converts it to a string. """ # convert_arguments(::Type{<: Text}, x::AbstractString) = (String(x),) - ################################################################################ # <:Mesh # ################################################################################ @@ -474,11 +512,8 @@ Takes an input `AbstractString` `x` and converts it to a string. Takes real vectors x, y, z and constructs a mesh out of those, under the assumption that every 3 points form a triangle. """ -function convert_arguments( - T::Type{<:Mesh}, - x::RealVector, y::RealVector, z::RealVector - ) - convert_arguments(T, Point3f.(x, y, z)) +function convert_arguments(T::Type{<:Mesh}, x::RealVector, y::RealVector, z::RealVector) + return convert_arguments(T, Point3f.(x, y, z)) end """ convert_arguments(Mesh, xyz::AbstractVector)::GLNormalMesh @@ -486,11 +521,8 @@ end Takes an input mesh and a vector `xyz` representing the vertices of the mesh, and creates indices under the assumption, that each triplet in `xyz` forms a triangle. """ -function convert_arguments( - MT::Type{<:Mesh}, - xyz::AbstractVector - ) - faces = connect(UInt32.(0:length(xyz)-1), GLTriangleFace) +function convert_arguments(MT::Type{<:Mesh}, xyz::AbstractVector) + faces = connect(UInt32.(0:(length(xyz) - 1)), GLTriangleFace) # TODO support faceview natively return convert_arguments(MT, xyz, collect(faces)) end @@ -504,20 +536,12 @@ function convert_arguments(::Type{<:Mesh}, mesh::GeometryBasics.Mesh{N}) where { mesh = GeometryBasics.pointmeta(mesh, decompose(Vec3f, n)) end end - return (GeometryBasics.mesh(mesh, pointtype=Point{N, Float32}, facetype=GLTriangleFace),) + return (GeometryBasics.mesh(mesh, pointtype=Point{N,Float32}, facetype=GLTriangleFace),) end -function convert_arguments( - MT::Type{<:Mesh}, - meshes::AbstractVector{<: Union{AbstractMesh, AbstractPolygon}} - ) - return (meshes,) -end +convert_arguments(MT::Type{<:Mesh}, meshes::AbstractVector{<:Union{AbstractMesh,AbstractPolygon}}) = (meshes,) -function convert_arguments( - MT::Type{<:Mesh}, - xyz::Union{AbstractPolygon, AbstractVector{<: AbstractPoint{2}}} - ) +function convert_arguments(MT::Type{<:Mesh}, xyz::Union{AbstractPolygon,AbstractVector{<:AbstractPoint{2}}}) return convert_arguments(MT, triangle_mesh(xyz)) end @@ -534,10 +558,12 @@ Takes real vectors x, y, z and constructs a triangle mesh out of those, using th faces in `indices`, which can be integers (every 3 -> one triangle), or GeometryBasics.NgonFace{N, <: Integer}. """ function convert_arguments( - T::Type{<: Mesh}, - x::RealVector, y::RealVector, z::RealVector, - indices::AbstractVector - ) + T::Type{<:Mesh}, + x::RealVector, + y::RealVector, + z::RealVector, + indices::AbstractVector, +) return convert_arguments(T, Point3f.(x, y, z), indices) end @@ -548,13 +574,9 @@ Takes `vertices` and `indices`, and creates a triangle mesh out of those. See [`to_vertices`](@ref) and [`to_triangles`](@ref) for more information about accepted types. """ -function convert_arguments( - ::Type{<:Mesh}, - vertices::AbstractArray, - indices::AbstractArray - ) +function convert_arguments(::Type{<:Mesh}, vertices::AbstractArray, indices::AbstractArray) m = normal_mesh(to_vertices(vertices), to_triangles(indices)) - (m,) + return (m,) end ################################################################################ @@ -563,13 +585,13 @@ end function convert_arguments(P::PlotFunc, r::AbstractVector, f::Function) ptype = plottype(P, Lines) - to_plotspec(ptype, convert_arguments(ptype, r, f.(r))) + return to_plotspec(ptype, convert_arguments(ptype, r, f.(r))) end function convert_arguments(P::PlotFunc, i::AbstractInterval, f::Function) x, y = PlotUtils.adapted_grid(f, endpoints(i)) ptype = plottype(P, Lines) - to_plotspec(ptype, convert_arguments(ptype, x, y)) + return to_plotspec(ptype, convert_arguments(ptype, x, y)) end # The following `tryrange` code was copied from Plots.jl @@ -580,7 +602,7 @@ function tryrange(F::AbstractArray, vec) rets = [tryrange(f, vec) for f in F] # get the preferred for each maxind = maximum(indexin(rets, vec)) # get the last attempt that succeeded (most likely to fit all) rets .= [tryrange(f, vec[maxind:maxind]) for f in F] # ensure that all functions compute there - rets[1] + return rets[1] end function tryrange(F, vec) @@ -591,44 +613,44 @@ function tryrange(F, vec) catch end end - error("$F is not a Function, or is not defined at any of the values $vec") + return error("$F is not a Function, or is not defined at any of the values $vec") end # OffsetArrays conversions function convert_arguments(sl::SurfaceLike, wm::OffsetArray) - x1, y1 = wm.offsets .+ 1 - nx, ny = size(wm) - x = range(x1, length = nx) - y = range(y1, length = ny) - v = parent(wm) - return convert_arguments(sl, x, y, v) + x1, y1 = wm.offsets .+ 1 + nx, ny = size(wm) + x = range(x1, length=nx) + y = range(y1, length=ny) + v = parent(wm) + return convert_arguments(sl, x, y, v) end ################################################################################ # Helper Functions # ################################################################################ -to_linspace(interval, N) = range(minimum(interval), stop = maximum(interval), length = N) +to_linspace(interval, N) = range(minimum(interval), stop=maximum(interval), length=N) """ Converts the elemen array type to `T1` without making a copy if the element type matches """ -elconvert(::Type{T1}, x::AbstractArray{T2, N}) where {T1, T2, N} = convert(AbstractArray{T1, N}, x) +elconvert(::Type{T1}, x::AbstractArray{T2,N}) where {T1,T2,N} = convert(AbstractArray{T1,N}, x) float32type(x::Type) = Float32 -float32type(::Type{<: RGB}) = RGB{Float32} -float32type(::Type{<: RGBA}) = RGBA{Float32} -float32type(::Type{<: Colorant}) = RGBA{Float32} -float32type(x::AbstractArray{T}) where T = float32type(T) -float32type(x::T) where T = float32type(T) +float32type(::Type{<:RGB}) = RGB{Float32} +float32type(::Type{<:RGBA}) = RGBA{Float32} +float32type(::Type{<:Colorant}) = RGBA{Float32} +float32type(x::AbstractArray{T}) where {T} = float32type(T) +float32type(x::T) where {T} = float32type(T) el32convert(x::AbstractArray) = elconvert(float32type(x), x) el32convert(x::AbstractArray{Float32}) = x el32convert(x::Observable) = lift(el32convert, x) el32convert(x) = convert(float32type(x), x) -function el32convert(x::AbstractArray{T, N}) where {T<:Union{Missing, <: Number}, N} +function el32convert(x::AbstractArray{T,N}) where {T<:Union{Missing,<:Number},N} return map(x) do elem return (ismissing(elem) ? NaN32 : convert(Float32, elem))::Float32 - end::Array{Float32, N} + end::Array{Float32,N} end """ to_triangles(indices) @@ -645,18 +667,14 @@ function to_triangles(x::AbstractVector{Int}) return to_triangles(idx0) end -function to_triangles(idx0::AbstractVector{UInt32}) - reinterpret(GLTriangleFace, idx0) -end +to_triangles(idx0::AbstractVector{UInt32}) = reinterpret(GLTriangleFace, idx0) -function to_triangles(faces::AbstractVector{TriangleFace{T}}) where T - elconvert(GLTriangleFace, faces) -end +to_triangles(faces::AbstractVector{TriangleFace{T}}) where {T} = elconvert(GLTriangleFace, faces) -function to_triangles(faces::AbstractMatrix{T}) where T <: Integer +function to_triangles(faces::AbstractMatrix{T}) where {T<:Integer} @assert size(faces, 2) == 3 return broadcast(1:size(faces, 1), 3) do fidx, n - GLTriangleFace(ntuple(i-> faces[fidx, i], n)) + return GLTriangleFace(ntuple(i -> faces[fidx, i], n)) end end @@ -675,47 +693,46 @@ Converts a representation of vertices `v` to its canonical representation as a - if `v` has 2 or 3 rows, it will treat each column as a vertex, - otherwise if `v` has 2 or 3 columns, it will treat each row as a vertex. """ -function to_vertices(verts::AbstractVector{<: VecTypes{3, T}}) where T +function to_vertices(verts::AbstractVector{<:VecTypes{3,T}}) where {T} vert3f0 = T != Float32 ? Point3f.(verts) : verts return reinterpret(Point3f, vert3f0) end -function to_vertices(verts::AbstractVector{<: VecTypes}) - to_vertices(to_ndim.(Point3f, verts, 0.0)) -end +to_vertices(verts::AbstractVector{<:VecTypes}) = to_vertices(to_ndim.(Point3f, verts, 0.0)) -function to_vertices(verts::AbstractMatrix{<: Number}) +function to_vertices(verts::AbstractMatrix{<:Number}) if size(verts, 1) in (2, 3) to_vertices(verts, Val(1)) elseif size(verts, 2) in (2, 3) to_vertices(verts, Val(2)) else - error("You are using a matrix for vertices which uses neither dimension to encode the dimension of the space. Please have either size(verts, 1/2) in the range of 2-3. Found: $(size(verts))") + error( + "You are using a matrix for vertices which uses neither dimension to encode the dimension of the space. Please have either size(verts, 1/2) in the range of 2-3. Found: $(size(verts))", + ) end end -function to_vertices(verts::AbstractMatrix{T}, ::Val{1}) where T <: Number +function to_vertices(verts::AbstractMatrix{T}, ::Val{1}) where {T<:Number} N = size(verts, 1) if T == Float32 && N == 3 - reinterpret(Point{N, T}, elconvert(T, vec(verts))) + reinterpret(Point{N,T}, elconvert(T, vec(verts))) else let N = Val(N), lverts = verts broadcast(1:size(verts, 2), N) do vidx, n - to_ndim(Point3f, ntuple(i-> lverts[i, vidx], n), 0.0) + return to_ndim(Point3f, ntuple(i -> lverts[i, vidx], n), 0.0) end end end end -function to_vertices(verts::AbstractMatrix{T}, ::Val{2}) where T <: Number +function to_vertices(verts::AbstractMatrix{T}, ::Val{2}) where {T<:Number} let N = Val(size(verts, 2)), lverts = verts broadcast(1:size(verts, 1), N) do vidx, n - to_ndim(Point3f, ntuple(i-> lverts[vidx, i], n), 0.0) + return to_ndim(Point3f, ntuple(i -> lverts[vidx, i], n), 0.0) end end end - ################################################################################ # Attribute conversions # ################################################################################ @@ -748,11 +765,11 @@ convert_attribute(p::Nothing, ::key"lowclip") = p convert_attribute(p, ::key"nan_color") = to_color(p) struct Palette - colors::Vector{RGBA{Float32}} - i::Ref{Int} - Palette(colors) = new(to_color.(colors), zero(Int)) + colors::Vector{RGBA{Float32}} + i::Ref{Int} + Palette(colors) = new(to_color.(colors), zero(Int)) end -Palette(name::Union{String, Symbol}, n = 8) = Palette(categorical_colors(name, n)) +Palette(name::Union{String,Symbol}, n=8) = Palette(categorical_colors(name, n)) function to_color(p::Palette) N = length(p.colors) p.i[] = p.i[] == N ? 1 : p.i[] + 1 @@ -765,9 +782,9 @@ to_color(c::Colorant) = convert(RGBA{Float32}, c) to_color(c::Symbol) = to_color(string(c)) to_color(c::String) = parse(RGBA{Float32}, c) to_color(c::AbstractArray) = to_color.(c) -to_color(c::AbstractArray{<: Colorant, N}) where N = convert(Array{RGBAf, N}, c) +to_color(c::AbstractArray{<:Colorant,N}) where {N} = convert(Array{RGBAf,N}, c) to_color(p::AbstractPattern) = p -function to_color(c::Tuple{<: Any, <: Number}) +function to_color(c::Tuple{<:Any,<:Number}) col = to_color(c[1]) return RGBAf(Colors.color(col), alpha(col) * c[2]) end @@ -782,18 +799,16 @@ convert_attribute(c, ::key"markersize", ::key"scatter") = to_2d_scale(c) convert_attribute(c, ::key"markersize", ::key"meshscatter") = to_3d_scale(c) to_2d_scale(x::Number) = Vec2f(x) to_2d_scale(x::VecTypes) = to_ndim(Vec2f, x, 1) -to_2d_scale(x::Tuple{<:Number, <:Number}) = to_ndim(Vec2f, x, 1) +to_2d_scale(x::Tuple{<:Number,<:Number}) = to_ndim(Vec2f, x, 1) to_2d_scale(x::AbstractVector) = to_2d_scale.(x) to_3d_scale(x::Number) = Vec3f(x) to_3d_scale(x::VecTypes) = to_ndim(Vec3f, x, 1) to_3d_scale(x::AbstractVector) = to_3d_scale.(x) - convert_attribute(x, ::key"uv_offset_width") = Vec4f(x) convert_attribute(x::AbstractVector{Vec4f}, ::key"uv_offset_width") = x - convert_attribute(c::Number, ::key"glowwidth") = Float32(c) convert_attribute(c::Number, ::key"strokewidth") = Float32(c) @@ -815,17 +830,17 @@ convert_attribute(A::AbstractVector, ::key"linestyle") = A convert_attribute(ls::Union{Symbol,AbstractString}, ::key"linestyle") = line_pattern(ls, :normal) function convert_attribute(ls::Tuple{<:Union{Symbol,AbstractString},<:Any}, ::key"linestyle") - line_pattern(ls[1], ls[2]) + return line_pattern(ls[1], ls[2]) end function line_pattern(linestyle, gaps) pattern = line_diff_pattern(linestyle, gaps) - isnothing(pattern) ? pattern : float.([0.0; cumsum(pattern)]) + return isnothing(pattern) ? pattern : float.([0.0; cumsum(pattern)]) end "The linestyle patterns are inspired by the LaTeX package tikZ as seen here https://tex.stackexchange.com/questions/45275/tikz-get-values-for-predefined-dash-patterns." -function line_diff_pattern(ls::Symbol, gaps = :normal) +function line_diff_pattern(ls::Symbol, gaps=:normal) if ls == :solid nothing elseif ls == :dash @@ -837,18 +852,16 @@ function line_diff_pattern(ls::Symbol, gaps = :normal) elseif ls == :dashdotdot line_diff_pattern("-..", gaps) else - error( - """ - Unkown line style: $ls. Available linestyles are: - :solid, :dash, :dot, :dashdot, :dashdotdot - or a sequence of numbers enumerating the next transparent/opaque region. - This sequence of numbers must be cumulative; 1 unit corresponds to 1 line width. - """ - ) + error(""" + Unkown line style: $ls. Available linestyles are: + :solid, :dash, :dot, :dashdot, :dashdotdot + or a sequence of numbers enumerating the next transparent/opaque region. + This sequence of numbers must be cumulative; 1 unit corresponds to 1 line width. + """) end end -function line_diff_pattern(ls_str::AbstractString, gaps = :normal) +function line_diff_pattern(ls_str::AbstractString, gaps=:normal) dot = 1 dash = 3 check_line_pattern(ls_str) @@ -858,7 +871,7 @@ function line_diff_pattern(ls_str::AbstractString, gaps = :normal) pattern = Float64[] for i in 1:length(ls_str) curr_char = ls_str[i] - next_char = i == lastindex(ls_str) ? ls_str[firstindex(ls_str)] : ls_str[i+1] + next_char = i == lastindex(ls_str) ? ls_str[firstindex(ls_str)] : ls_str[i + 1] # push dash or dot if curr_char == '-' push!(pattern, dash) @@ -872,48 +885,51 @@ function line_diff_pattern(ls_str::AbstractString, gaps = :normal) push!(pattern, dash_gap) end end - pattern + return pattern end "Checks if the linestyle format provided as a string contains only dashes and dots" function check_line_pattern(ls_str) - isnothing(match(r"^[.-]+$", ls_str)) && - throw(ArgumentError("If you provide a string as linestyle, it must only consist of dashes (-) and dots (.)")) + isnothing(match(r"^[.-]+$", ls_str)) && throw( + ArgumentError( + "If you provide a string as linestyle, it must only consist of dashes (-) and dots (.)", + ), + ) - nothing + return nothing end function convert_gaps(gaps) - error_msg = "You provided the gaps modifier $gaps when specifying the linestyle. The modifier must be `∈ ([:normal, :dense, :loose])`, a real number or a collection of two real numbers." - if gaps isa Symbol - gaps in [:normal, :dense, :loose] || throw(ArgumentError(error_msg)) - dot_gaps = (normal = 2, dense = 1, loose = 4) - dash_gaps = (normal = 3, dense = 2, loose = 6) - - dot_gap = getproperty(dot_gaps, gaps) - dash_gap = getproperty(dash_gaps, gaps) - elseif gaps isa Real - dot_gap = gaps - dash_gap = gaps - elseif length(gaps) == 2 && eltype(gaps) <: Real - dot_gap, dash_gap = gaps - else - throw(ArgumentError(error_msg)) - end - (dot_gap = dot_gap, dash_gap = dash_gap) -end - -convert_attribute(c::Tuple{<: Number, <: Number}, ::key"position") = Point2f(c[1], c[2]) -convert_attribute(c::Tuple{<: Number, <: Number, <: Number}, ::key"position") = Point3f(c) -convert_attribute(c::VecTypes{N}, ::key"position") where N = Point{N, Float32}(c) + error_msg = "You provided the gaps modifier $gaps when specifying the linestyle. The modifier must be `∈ ([:normal, :dense, :loose])`, a real number or a collection of two real numbers." + if gaps isa Symbol + gaps in [:normal, :dense, :loose] || throw(ArgumentError(error_msg)) + dot_gaps = (normal=2, dense=1, loose=4) + dash_gaps = (normal=3, dense=2, loose=6) + + dot_gap = getproperty(dot_gaps, gaps) + dash_gap = getproperty(dash_gaps, gaps) + elseif gaps isa Real + dot_gap = gaps + dash_gap = gaps + elseif length(gaps) == 2 && eltype(gaps) <: Real + dot_gap, dash_gap = gaps + else + throw(ArgumentError(error_msg)) + end + return (dot_gap=dot_gap, dash_gap=dash_gap) +end + +convert_attribute(c::Tuple{<:Number,<:Number}, ::key"position") = Point2f(c[1], c[2]) +convert_attribute(c::Tuple{<:Number,<:Number,<:Number}, ::key"position") = Point3f(c) +convert_attribute(c::VecTypes{N}, ::key"position") where {N} = Point{N,Float32}(c) """ Text align, e.g.: """ -to_align(x::Tuple{Symbol, Symbol}) = Vec2f(alignment2num.(x)) +to_align(x::Tuple{Symbol,Symbol}) = Vec2f(alignment2num.(x)) to_align(x::Vec2f) = x -const FONT_CACHE = Dict{String, NativeFont}() +const FONT_CACHE = Dict{String,NativeFont}() """ font conversion @@ -941,7 +957,9 @@ function to_font(x::String) @warn("Could not find font $str, using TeX Gyre Heros Makie") if "tex gyre heros makie" == lowercase(str) # since we fall back to TeX Gyre Heros Makie, we need to check for recursion - error("Recursion encountered; TeX Gyre Heros Makie cannot be located in the font path $fontpath") + error( + "Recursion encountered; TeX Gyre Heros Makie cannot be located in the font path $fontpath", + ) end return to_font("TeX Gyre Heros Makie") end @@ -956,16 +974,17 @@ function to_font(fonts::Attributes, s::Symbol) if haskey(fonts, s) f = fonts[s][] if f isa Symbol - error("The value for font $(repr(s)) was Symbol $(repr(f)), which is not allowed. The value for a font in the fonts collection cannot be another Symbol and must be resolvable via `to_font(x)`.") + error( + "The value for font $(repr(s)) was Symbol $(repr(f)), which is not allowed. The value for a font in the fonts collection cannot be another Symbol and must be resolvable via `to_font(x)`.", + ) end return to_font(fonts[s][]) end - error("The symbol $(repr(s)) is not present in the fonts collection:\n$fonts.") + return error("The symbol $(repr(s)) is not present in the fonts collection:\n$fonts.") end to_font(fonts::Attributes, x) = to_font(x) - """ rotation accepts: to_rotation(b, quaternion) @@ -975,7 +994,7 @@ to_font(fonts::Attributes, x) = to_font(x) to_rotation(s::Quaternionf) = s to_rotation(s::Quaternion) = Quaternionf(s.data...) -function to_rotation(s::VecTypes{N}) where N +function to_rotation(s::VecTypes{N}) where {N} if N == 4 Quaternionf(s...) elseif N == 3 @@ -987,35 +1006,33 @@ function to_rotation(s::VecTypes{N}) where N end end -to_rotation(s::Tuple{VecTypes, Number}) = qrotation(to_ndim(Vec3f, s[1], 0.0), s[2]) +to_rotation(s::Tuple{VecTypes,Number}) = qrotation(to_ndim(Vec3f, s[1], 0.0), s[2]) to_rotation(angle::Number) = qrotation(Vec3f(0, 0, 1), angle) to_rotation(r::AbstractVector) = to_rotation.(r) -to_rotation(r::AbstractVector{<: Quaternionf}) = r +to_rotation(r::AbstractVector{<:Quaternionf}) = r convert_attribute(x, ::key"colorrange") = to_colorrange(x) to_colorrange(x) = isnothing(x) ? nothing : Vec2f(x) convert_attribute(x, ::key"fontsize") = to_fontsize(x) to_fontsize(x::Number) = Float32(x) -to_fontsize(x::AbstractVector{T}) where T <: Number = el32convert(x) +to_fontsize(x::AbstractVector{T}) where {T<:Number} = el32convert(x) convert_attribute(x, ::key"linewidth") = to_linewidth(x) to_linewidth(x) = Float32(x) to_linewidth(x::AbstractVector) = el32convert(x) # ColorBrewer colormaps that support only 8 colors require special handling on the backend, so we show them here. -const colorbrewer_8color_names = String.([ - :Accent, - :Dark2, - :Pastel2, - :Set2 -]) - -const plotutils_names = String.(union( - keys(PlotUtils.ColorSchemes.colorschemes), - keys(PlotUtils.COLORSCHEME_ALIASES), - keys(PlotUtils.MISC_COLORSCHEMES) -)) +const colorbrewer_8color_names = String.([:Accent, :Dark2, :Pastel2, :Set2]) + +const plotutils_names = + String.( + union( + keys(PlotUtils.ColorSchemes.colorschemes), + keys(PlotUtils.COLORSCHEME_ALIASES), + keys(PlotUtils.MISC_COLORSCHEMES), + ) + ) const all_gradient_names = Set(vcat(plotutils_names, colorbrewer_8color_names)) @@ -1031,8 +1048,11 @@ function available_gradients() end end - -to_colormap(cm, categories::Integer) = error("`to_colormap(cm, categories)` is deprecated. Use `Makie.categorical_colors(cm, categories)` for categorical colors, and `resample_cmap(cmap, ncolors)` for continous resampling.") +function to_colormap(cm, categories::Integer) + return error( + "`to_colormap(cm, categories)` is deprecated. Use `Makie.categorical_colors(cm, categories)` for categorical colors, and `resample_cmap(cmap, ncolors)` for continous resampling.", + ) +end """ categorical_colors(colormaplike, categories::Integer) @@ -1040,9 +1060,11 @@ to_colormap(cm, categories::Integer) = error("`to_colormap(cm, categories)` is d Creates categorical colors and tries to match `categories`. Will error if color scheme doesn't contain enough categories. Will drop the n last colors, if request less colors than contained in scheme. """ -function categorical_colors(cols::AbstractVector{<: Colorant}, categories::Integer) +function categorical_colors(cols::AbstractVector{<:Colorant}, categories::Integer) if length(cols) < categories - error("Not enough colors for number of categories. Categories: $(categories), colors: $(length(cols))") + error( + "Not enough colors for number of categories. Categories: $(categories), colors: $(length(cols))", + ) end return cols[1:categories] end @@ -1051,7 +1073,7 @@ function categorical_colors(cols::AbstractVector, categories::Integer) return categorical_colors(to_color.(cols), categories) end -function categorical_colors(cs::Union{String, Symbol}, categories::Integer) +function categorical_colors(cs::Union{String,Symbol}, categories::Integer) cs_string = string(cs) if cs_string in all_gradient_names if haskey(ColorBrewer.colorSchemes, cs_string) @@ -1060,13 +1082,11 @@ function categorical_colors(cs::Union{String, Symbol}, categories::Integer) return categorical_colors(to_colormap(cs_string), categories) end else - error( - """ - There is no color gradient named $cs. - See `available_gradients()` for the list of available gradients, - or look at http://docs.makie.org/dev/generated/colors#Colormap-reference. - """ - ) + error(""" + There is no color gradient named $cs. + See `available_gradients()` for the list of available gradients, + or look at http://docs.makie.org/dev/generated/colors#Colormap-reference. + """) end end @@ -1080,17 +1100,15 @@ end to_colormap(r::Reverse) = reverse(to_colormap(r.data)) to_colormap(cs::ColorScheme) = to_colormap(cs.colors) - - """ to_colormap(b::AbstractVector) An `AbstractVector{T}` with any object that [`to_color`](@ref) accepts. """ to_colormap(cm::AbstractVector)::Vector{RGBAf} = map(to_color, cm) -to_colormap(cm::AbstractVector{<: Colorant}) = convert(Vector{RGBAf}, cm) +to_colormap(cm::AbstractVector{<:Colorant}) = convert(Vector{RGBAf}, cm) -function to_colormap(cs::Tuple{<: Union{Reverse, Symbol, AbstractString}, Real})::Vector{RGBAf} +function to_colormap(cs::Tuple{<:Union{Reverse,Symbol,AbstractString},Real})::Vector{RGBAf} cmap = to_colormap(cs[1]) return RGBAf.(color.(cmap), alpha.(cmap) .* cs[2]) # We need to rework this to conform to the backend interface. end @@ -1101,7 +1119,7 @@ end A Symbol/String naming the gradient. For more on what names are available please see: `available_gradients()`. For now, we support gradients from `PlotUtils` natively. """ -function to_colormap(cs::Union{String, Symbol})::Vector{RGBAf} +function to_colormap(cs::Union{String,Symbol})::Vector{RGBAf} cs_string = string(cs) if cs_string in all_gradient_names if cs_string in colorbrewer_8color_names # special handling for 8 color only @@ -1111,13 +1129,11 @@ function to_colormap(cs::Union{String, Symbol})::Vector{RGBAf} return to_colormap(PlotUtils.get_colorscheme(Symbol(cs_string))) end else - error( - """ - There is no color gradient named $cs. - See `Makie.available_gradients()` for the list of available gradients, - or look at http://docs.makie.org/dev/generated/colors#Colormap-reference. - """ - ) + error(""" + There is no color gradient named $cs. + See `Makie.available_gradients()` for the list of available gradients, + or look at http://docs.makie.org/dev/generated/colors#Colormap-reference. + """) end end @@ -1142,14 +1158,16 @@ function convert_attribute(value, ::key"algorithm") elseif value == 7 return value # makie internal contour implementation else - error("$value is not a valid volume algorithm. Please have a look at the docstring of `to_volume_algorithm` (in the REPL, `?to_volume_algorithm`).") + error( + "$value is not a valid volume algorithm. Please have a look at the docstring of `to_volume_algorithm` (in the REPL, `?to_volume_algorithm`).", + ) end end """ Symbol/String: iso, absorption, mip, absorptionrgba, indexedabsorption """ -function convert_attribute(value::Union{Symbol, String}, k::key"algorithm") +function convert_attribute(value::Union{Symbol,String}, k::key"algorithm") vals = Dict( :iso => IsoValue, :absorption => Absorption, @@ -1158,12 +1176,15 @@ function convert_attribute(value::Union{Symbol, String}, k::key"algorithm") :indexedabsorption => IndexedAbsorptionRGBA, :additive => AdditiveRGBA, ) - convert_attribute(get(vals, Symbol(value)) do - error("$value is not a valid volume algorithm. It must be one of $(keys(vals))") - end, k) + convert_attribute( + get(vals, Symbol(value)) do + return error("$value is not a valid volume algorithm. It must be one of $(keys(vals))") + end, + k, + ) end -const DEFAULT_MARKER_MAP = Dict{Symbol, BezierPath}() +const DEFAULT_MARKER_MAP = Dict{Symbol,BezierPath}() function default_marker_map() # The bezier markers should not look out of place when used together with text @@ -1179,20 +1200,20 @@ function default_marker_map() if isempty(DEFAULT_MARKER_MAP) size_factor = 0.75 DEFAULT_MARKER_MAP[:rect] = scale(BezierSquare, size_factor) - DEFAULT_MARKER_MAP[:diamond] = scale(rotate(BezierSquare, pi/4), size_factor) - DEFAULT_MARKER_MAP[:hexagon] = scale(bezier_ngon(6, 0.5, pi/2), size_factor) + DEFAULT_MARKER_MAP[:diamond] = scale(rotate(BezierSquare, pi / 4), size_factor) + DEFAULT_MARKER_MAP[:hexagon] = scale(bezier_ngon(6, 0.5, pi / 2), size_factor) DEFAULT_MARKER_MAP[:cross] = scale(BezierCross, size_factor) DEFAULT_MARKER_MAP[:xcross] = scale(BezierX, size_factor) DEFAULT_MARKER_MAP[:utriangle] = scale(BezierUTriangle, size_factor) DEFAULT_MARKER_MAP[:dtriangle] = scale(BezierDTriangle, size_factor) DEFAULT_MARKER_MAP[:ltriangle] = scale(BezierLTriangle, size_factor) DEFAULT_MARKER_MAP[:rtriangle] = scale(BezierRTriangle, size_factor) - DEFAULT_MARKER_MAP[:pentagon] = scale(bezier_ngon(5, 0.5, pi/2), size_factor) - DEFAULT_MARKER_MAP[:octagon] = scale(bezier_ngon(8, 0.5, pi/2), size_factor) - DEFAULT_MARKER_MAP[:star4] = scale(bezier_star(4, 0.25, 0.6, pi/2), size_factor) - DEFAULT_MARKER_MAP[:star5] = scale(bezier_star(5, 0.28, 0.6, pi/2), size_factor) - DEFAULT_MARKER_MAP[:star6] = scale(bezier_star(6, 0.30, 0.6, pi/2), size_factor) - DEFAULT_MARKER_MAP[:star8] = scale(bezier_star(8, 0.33, 0.6, pi/2), size_factor) + DEFAULT_MARKER_MAP[:pentagon] = scale(bezier_ngon(5, 0.5, pi / 2), size_factor) + DEFAULT_MARKER_MAP[:octagon] = scale(bezier_ngon(8, 0.5, pi / 2), size_factor) + DEFAULT_MARKER_MAP[:star4] = scale(bezier_star(4, 0.25, 0.6, pi / 2), size_factor) + DEFAULT_MARKER_MAP[:star5] = scale(bezier_star(5, 0.28, 0.6, pi / 2), size_factor) + DEFAULT_MARKER_MAP[:star6] = scale(bezier_star(6, 0.30, 0.6, pi / 2), size_factor) + DEFAULT_MARKER_MAP[:star8] = scale(bezier_star(8, 0.33, 0.6, pi / 2), size_factor) DEFAULT_MARKER_MAP[:vline] = scale(scale(BezierSquare, (0.2, 1.0)), size_factor) DEFAULT_MARKER_MAP[:hline] = scale(scale(BezierSquare, (1.0, 0.2)), size_factor) DEFAULT_MARKER_MAP[:+] = scale(BezierCross, size_factor) @@ -1236,15 +1257,17 @@ to_spritemarker(marker::AbstractVector) = map(to_spritemarker, marker) to_spritemarker(marker::AbstractVector{Char}) = marker # Don't dispatch to the above! to_spritemarker(x::FastPixel) = x to_spritemarker(x::Circle) = x -to_spritemarker(::Type{<: Circle}) = Circle -to_spritemarker(::Type{<: Rect}) = Rect +to_spritemarker(::Type{<:Circle}) = Circle +to_spritemarker(::Type{<:Rect}) = Rect to_spritemarker(x::Rect) = x to_spritemarker(b::BezierPath) = b to_spritemarker(b::Polygon) = BezierPath(b) to_spritemarker(b) = error("Not a valid scatter marker: $(typeof(b))") function to_spritemarker(str::String) - error("Using strings for multiple char markers is deprecated. Use `collect(string)` or `['x', 'o', ...]` instead. Found: $(str)") + return error( + "Using strings for multiple char markers is deprecated. Use `collect(string)` or `['x', 'o', ...]` instead. Found: $(str)", + ) end """ @@ -1257,27 +1280,23 @@ to_spritemarker(marker::Char) = marker """ Matrix of AbstractFloat will be interpreted as a distancefield (negative numbers outside shape, positive inside) """ -to_spritemarker(marker::Matrix{<: AbstractFloat}) = el32convert(marker) +to_spritemarker(marker::Matrix{<:AbstractFloat}) = el32convert(marker) """ Any AbstractMatrix{<: Colorant} or other image type """ -to_spritemarker(marker::AbstractMatrix{<: Colorant}) = marker +to_spritemarker(marker::AbstractMatrix{<:Colorant}) = marker """ A `Symbol` - Available options can be printed with `available_marker_symbols()` """ -function to_spritemarker(marker::Symbol) +to_spritemarker(marker::Symbol) = if haskey(default_marker_map(), marker) return to_spritemarker(default_marker_map()[marker]) else @warn("Unsupported marker: $marker, using ● instead") return '●' end -end - - - convert_attribute(value, ::key"marker", ::key"scatter") = to_spritemarker(value) convert_attribute(value, ::key"isovalue", ::key"volume") = Float32(value) @@ -1285,12 +1304,10 @@ convert_attribute(value, ::key"isorange", ::key"volume") = Float32(value) function convert_attribute(value::Symbol, ::key"marker", ::key"meshscatter") if value == :Sphere - return normal_mesh(Sphere(Point3f(0), 1f0)) + return normal_mesh(Sphere(Point3f(0), 1.0f0)) else error("Unsupported marker: $(value)") end end -function convert_attribute(value::AbstractGeometry, ::key"marker", ::key"meshscatter") - return normal_mesh(value) -end +convert_attribute(value::AbstractGeometry, ::key"marker", ::key"meshscatter") = normal_mesh(value) diff --git a/src/display.jl b/src/display.jl index 6ba313ee9c0..732877a2194 100644 --- a/src/display.jl +++ b/src/display.jl @@ -7,17 +7,15 @@ function backend_show end """ Current backend """ -const CURRENT_BACKEND = Ref{Union{Missing, Module}}(missing) +const CURRENT_BACKEND = Ref{Union{Missing,Module}}(missing) current_backend() = CURRENT_BACKEND[] -function set_active_backend!(backend::Union{Missing, Module}) +function set_active_backend!(backend::Union{Missing,Module}) CURRENT_BACKEND[] = backend return end -function push_screen!(scene::Scene, display) - error("$(display) not a valid Makie display.") -end +push_screen!(scene::Scene, display) = error("$(display) not a valid Makie display.") """ push_screen!(scene::Scene, screen::MakieScreen) @@ -59,7 +57,7 @@ Removes screen from scene and cleans up screen function delete_screen!(scene::Scene, screen::MakieScreen) delete!(screen, scene) empty!(screen) - filter!(x-> x !== screen, scene.current_screens) + filter!(x -> x !== screen, scene.current_screens) return end @@ -69,14 +67,16 @@ function set_screen_config!(backend::Module, new_values) bkeys = keys(backend_defaults) for (k, v) in pairs(new_values) if !(k in bkeys) - error("$k is not a valid screen config. Applicable options: $(keys(backend_defaults)). For help, check `?$(backend).ScreenCofig`") + error( + "$k is not a valid screen config. Applicable options: $(keys(backend_defaults)). For help, check `?$(backend).ScreenCofig`", + ) end backend_defaults[k] = v end return backend_defaults end -function merge_screen_config(::Type{Config}, screen_config_kw) where Config +function merge_screen_config(::Type{Config}, screen_config_kw) where {Config} backend = parentmodule(Config) key = nameof(backend) backend_defaults = CURRENT_DEFAULT_THEME[key] @@ -91,7 +91,6 @@ function merge_screen_config(::Type{Config}, screen_config_kw) where Config return Config(arguments...) end - const ALWAYS_INLINE_PLOTS = Ref{Bool}(false) """ @@ -103,9 +102,7 @@ Only case Makie always shows the plot inside the plotpane is when using VSCode e If you want to always force inlining the plot into the plotpane, set `inline!(true)` (E.g. when run in the VSCode REPL). In other cases `inline!(true/false)` won't do anything. """ -function inline!(inline=true) - ALWAYS_INLINE_PLOTS[] = inline -end +inline!(inline=true) = ALWAYS_INLINE_PLOTS[] = inline """ Base.display(figlike::FigureLike; backend=current_backend(), screen_config...) @@ -138,7 +135,6 @@ end is_displayed(screen::MakieScreen, scene::Scene) = screen in scene.current_screens - # Backends overload display(::Backend.Screen, scene::Scene), while Makie overloads the below, # so that they don't need to worry # about stuff like `update_state_before_display!` @@ -149,7 +145,7 @@ function Base.display(screen::MakieScreen, figlike::FigureLike; update=true, dis return screen end -function _backend_showable(mime::MIME{SYM}) where SYM +function _backend_showable(mime::MIME{SYM}) where {SYM} Backend = current_backend() if ismissing(Backend) return Symbol("text/plain") == SYM @@ -176,9 +172,7 @@ function backend_show(backend, io::IO, ::MIME"text/plain", scene::Scene) return end -function Base.show(io::IO, ::MIME"text/plain", scene::Scene) - show(io, scene) -end +Base.show(io::IO, ::MIME"text/plain", scene::Scene) = show(io, scene) function Base.show(io::IO, m::MIME, figlike::FigureLike) scene = get_scene(figlike) @@ -200,7 +194,7 @@ format2mime(::Type{FileIO.format"TEX"}) = MIME("application/x-tex") format2mime(::Type{FileIO.format"EPS"}) = MIME("application/postscript") format2mime(::Type{FileIO.format"HTML"}) = MIME("text/html") -filetype(::FileIO.File{F}) where F = F +filetype(::FileIO.File{F}) where {F} = F # Allow format to be overridden with first argument """ @@ -225,19 +219,16 @@ Save a `Scene` with the specified filename and format. - `pt_per_unit`: The size of one scene unit in `pt` when exporting to a vector format. - `px_per_unit`: The size of one scene unit in `px` when exporting to a bitmap format. This provides a mechanism to export the same scene with higher or lower resolution. """ -function FileIO.save( - filename::String, fig::FigureLike; args... - ) - FileIO.save(FileIO.query(filename), fig; args...) -end +FileIO.save(filename::String, fig::FigureLike; args...) = FileIO.save(FileIO.query(filename), fig; args...) function FileIO.save( - file::FileIO.Formatted, fig::FigureLike; - resolution = size(get_scene(fig)), - backend = current_backend(), - update = true, - screen_config... - ) + file::FileIO.Formatted, + fig::FigureLike; + resolution=size(get_scene(fig)), + backend=current_backend(), + update=true, + screen_config..., +) scene = get_scene(fig) if resolution != size(scene) resize!(scene, resolution) @@ -258,7 +249,7 @@ function FileIO.save( # 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...) - backend_show(screen, io, mime, scene) + return backend_show(screen, io, mime, scene) end catch e # So, if open(io-> error(...), "w"), the file will get created, but not removed... @@ -272,26 +263,22 @@ raw_io(io::IO) = io raw_io(io::IOContext) = raw_io(io.io) # This has to be overloaded by the backend for its screen type. -function colorbuffer(x::MakieScreen) - error("colorbuffer not implemented for screen $(typeof(x))") -end - -function jl_to_gl_format(image) - @static if VERSION < v"1.6" - d1, d2 = size(image) - bufc = Array{eltype(image)}(undef, d2, d1) #permuted - ind1, ind2 = axes(image) - n = first(ind1) + last(ind1) - for i in ind1 - @simd for j in ind2 - @inbounds bufc[j, n-i] = image[i, j] - end +colorbuffer(x::MakieScreen) = error("colorbuffer not implemented for screen $(typeof(x))") + +jl_to_gl_format(image) = @static if VERSION < v"1.6" + d1, d2 = size(image) + bufc = Array{eltype(image)}(undef, d2, d1) #permuted + ind1, ind2 = axes(image) + n = first(ind1) + last(ind1) + for i in ind1 + @simd for j in ind2 + @inbounds bufc[j, n - i] = image[i, j] end - return bufc - else - reverse!(image; dims=1) - return PermutedDimsArray(image, (2, 1)) end + return bufc +else + reverse!(image; dims=1) + return PermutedDimsArray(image, (2, 1)) end # less specific for overloading by backends @@ -306,7 +293,7 @@ end function apply_screen_config! end -function getscreen(backend::Union{Missing, Module}, scene::Scene, args...; screen_config...) +function getscreen(backend::Union{Missing,Module}, scene::Scene, args...; screen_config...) screen = getscreen(scene) config = Makie.merge_screen_config(backend.ScreenConfig, screen_config) if !isnothing(screen) && parentmodule(typeof(screen)) == backend @@ -335,7 +322,13 @@ or RGBA. used in FFMPEG without conversion - `screen_config`: Backend dependend, look up via `?Backend.Screen`/`Base.doc(Backend.Screen)` """ -function colorbuffer(fig::FigureLike, format::ImageStorageFormat = JuliaNative; update=true, backend = current_backend(), screen_config...) +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...) diff --git a/src/documentation/docstringextension.jl b/src/documentation/docstringextension.jl index 25d991af9d4..226d90f4c62 100644 --- a/src/documentation/docstringextension.jl +++ b/src/documentation/docstringextension.jl @@ -11,8 +11,8 @@ struct DocThemer <: DocStringExtensions.Abbreviation end const ATTRIBUTES = DocThemer() function DocStringExtensions.format(::DocThemer, buf, doc) - binding = doc.data[:binding] |> Docs.resolve - help_attributes(buf, binding; extended=true) + binding = Docs.resolve(doc.data[:binding]) + return help_attributes(buf, binding; extended=true) end ############################################################ @@ -41,7 +41,7 @@ function DocStringExtensions.format(::DocInstances, buf, doc) end # print the Markdown table into the buffer - show(buf, Markdown.MD(Markdown.Table(rows, [:l, :l]))) + return show(buf, Markdown.MD(Markdown.Table(rows, [:l, :l]))) end # """ diff --git a/src/documentation/documentation.jl b/src/documentation/documentation.jl index ce83835cd4c..605111283f2 100644 --- a/src/documentation/documentation.jl +++ b/src/documentation/documentation.jl @@ -14,20 +14,20 @@ Use the optional `extended = true` keyword argument to see more details. """ help(func; kw_args...) = help(stdout, func; kw_args...) #defaults to STDOUT -function help(io::IO, input::Type{T}; extended = false) where T <: AbstractPlot +function help(io::IO, input::Type{T}; extended=false) where {T<:AbstractPlot} buffer = IOBuffer() - _help(buffer, input; extended = extended) - Markdown.parse(String(take!(buffer))) + _help(buffer, input; extended=extended) + return Markdown.parse(String(take!(buffer))) end -function help(io::IO, input::Function; extended = false) +function help(io::IO, input::Function; extended=false) buffer = IOBuffer() - _help(buffer, to_type(input); extended = extended) - Markdown.parse(String(take!(buffer))) + _help(buffer, to_type(input); extended=extended) + return Markdown.parse(String(take!(buffer))) end # Internal help functions -function _help(io::IO, input::Type{T}; extended = false) where T <: AbstractPlot +function _help(io::IO, input::Type{T}; extended=false) where {T<:AbstractPlot} func = to_func(input) str = to_string(input) @@ -37,20 +37,21 @@ function _help(io::IO, input::Type{T}; extended = false) where T <: AbstractPlot # Arguments help_arguments(io, func) if extended - println(io, "Please refer to [`convert_arguments`](@ref) to find the full list of accepted arguments\n") + println( + io, + "Please refer to [`convert_arguments`](@ref) to find the full list of accepted arguments\n", + ) end # Keyword arguments - help_attributes(io, input; extended = extended) + help_attributes(io, input; extended=extended) if extended println(io, "You can see usage examples of `$func` by running:\n") println(io, "`example_database($func)`\n") end end -function _help(io::IO, input::Function; extended = false) - _help(io, to_type(input); extended = extended) -end +_help(io::IO, input::Function; extended=false) = _help(io, to_type(input); extended=extended) """ help_arguments([io], func) @@ -67,7 +68,7 @@ function help_arguments(io::IO, x::Function) println(io, " ", "(Vector, Vector)") println(io, " ", "(Vector, Vector, Vector)") println(io, " ", "(Matrix)") - println(io, "```") + return println(io, "```") end """ @@ -104,7 +105,7 @@ usage: """ help_attributes(x; kw...) = help_attributes(stdout, x; kw...) -function help_attributes(io::IO, Typ::Type{T}; extended = false) where T <: AbstractPlot +function help_attributes(io::IO, Typ::Type{T}; extended=false) where {T<:AbstractPlot} # get and sort list of attributes from function (using Scatter as an example) # this is a symbolic dictionary, with symbols as the keys attributes = default_theme(nothing, Typ) @@ -148,14 +149,14 @@ function help_attributes(io::IO, Typ::Type{T}; extended = false) where T <: Abst end end end - println(io, "```") + return println(io, "```") end -function help_attributes(io::IO, func::Function; extended = false) - help_attributes(io, to_type(func); extended = extended) +function help_attributes(io::IO, func::Function; extended=false) + return help_attributes(io, to_type(func); extended=extended) end -function help_attributes(io::IO, Typ::Type{T}; extended = false) where T <: Axis3D +function help_attributes(io::IO, Typ::Type{T}; extended=false) where {T<:Axis3D} if extended println(io, "OldAxis attributes and their defaults for `$Typ` are: \n") else @@ -163,8 +164,8 @@ function help_attributes(io::IO, Typ::Type{T}; extended = false) where T <: Axis end attributes = default_theme(nothing, Typ) println(io, "```") - print_rec(io, attributes, 1; extended = extended) - println(io, "```") + print_rec(io, attributes, 1; extended=extended) + return println(io, "```") end # ========================================================== @@ -174,13 +175,10 @@ end Maps the input of a Type name to its cooresponding function. """ -function to_func(Typ::Type{<: AbstractPlot{F}}) where F - F -end +to_func(Typ::Type{<:AbstractPlot{F}}) where {F} = F to_func(func::Function) = func - """ to_type(func) @@ -188,18 +186,16 @@ Maps the input of a function name to its cooresponding Type. """ to_type(func::Function) = Combined{func} -to_type(Typ::Type{T}) where T <: AbstractPlot = Typ +to_type(Typ::Type{T}) where {T<:AbstractPlot} = Typ """ to_string(func) Turns the input of a function name or plot Type into a string. """ -function to_string(func::Function) - str = string(typeof(func).name.mt.name) -end +to_string(func::Function) = str = string(typeof(func).name.mt.name) -to_string(Typ::Type{T}) where T <: AbstractPlot = to_string(to_func(Typ)) +to_string(Typ::Type{T}) where {T<:AbstractPlot} = to_string(to_func(Typ)) to_string(s::Symbol) = string(s) to_string(s::String) = s @@ -211,13 +207,13 @@ in a nicely-indented format. Use the optional `extended = true` keyword argument to see more details. """ -function print_rec(io::IO, dict, indent::Int = 1; extended = false) +function print_rec(io::IO, dict, indent::Int=1; extended=false) for (k, v) in dict - print(io, " "^(indent*4), k) + print(io, " "^(indent * 4), k) if isa(to_value(v), Makie.Attributes) print(io, ": ") println(io) - print_rec(io, v.attributes, indent + 1; extended = extended) + print_rec(io, v.attributes, indent + 1; extended=extended) elseif isa(v, Observable) if extended print(io, ": ") diff --git a/src/ffmpeg-util.jl b/src/ffmpeg-util.jl index e44e3038c7c..4c0a235b834 100644 --- a/src/ffmpeg-util.jl +++ b/src/ffmpeg-util.jl @@ -42,9 +42,15 @@ struct VideoStreamOptions rawvideo::Bool function VideoStreamOptions( - format::AbstractString, framerate::Integer, compression, profile, - pixel_format, loglevel::String, input::String, rawvideo::Bool=true) - + format::AbstractString, + framerate::Integer, + compression, + profile, + pixel_format, + loglevel::String, + input::String, + rawvideo::Bool=true, + ) if format == "mp4" (profile === nothing) && (profile = "high422") (pixel_format === nothing) && (pixel_format = (profile == "high444" ? "yuv444p" : "yuv420p")) @@ -55,18 +61,22 @@ struct VideoStreamOptions end # items are name, value, allowed_formats - allowed_kwargs = [("compression", compression, ("mp4", "webm")), - ("profile", profile, ("mp4",)), - ("pixel_format", pixel_format, ("mp4",))] + allowed_kwargs = [ + ("compression", compression, ("mp4", "webm")), + ("profile", profile, ("mp4",)), + ("pixel_format", pixel_format, ("mp4",)), + ] for (name, value, allowed_formats) in allowed_kwargs if !(format in allowed_formats) && value !== nothing - @warn("""`$name`, with value $(repr(value)) - was passed as a keyword argument to `record` or `VideoStream`, - which only has an effect when the output video's format is one of: $(collect(allowed_formats)). - But the actual video format was $(repr(format)). - Keyword arg `$name` will be ignored. - """) + @warn( + """`$name`, with value $(repr(value)) + was passed as a keyword argument to `record` or `VideoStream`, + which only has an effect when the output video's format is one of: $(collect(allowed_formats)). + But the actual video format was $(repr(format)). + Keyword arg `$name` will be ignored. + """ + ) end end @@ -74,15 +84,7 @@ struct VideoStreamOptions error("file needs to be \"pipe:0\" or a valid file path") end - loglevels = Set([ - "quiet", - "panic", - "fatal", - "error", - "warning", - "info", - "verbose", - "debug"]) + loglevels = Set(["quiet", "panic", "fatal", "error", "warning", "info", "verbose", "debug"]) if !(loglevel in loglevels) error("loglevel needs to be one of $(loglevels)") @@ -91,8 +93,26 @@ struct VideoStreamOptions end end -function VideoStreamOptions(; format="mp4", framerate=24, compression=nothing, profile=nothing, pixel_format=nothing, loglevel="quiet", input="pipe:0", rawvideo=true) - return VideoStreamOptions(format, framerate, compression, profile, pixel_format, loglevel, input, rawvideo) +function VideoStreamOptions(; + format="mp4", + framerate=24, + compression=nothing, + profile=nothing, + pixel_format=nothing, + loglevel="quiet", + input="pipe:0", + rawvideo=true, +) + return VideoStreamOptions( + format, + framerate, + compression, + profile, + pixel_format, + loglevel, + input, + rawvideo, + ) end function to_ffmpeg_cmd(vso::VideoStreamOptions, xdim::Integer=0, ydim::Integer=0) @@ -112,7 +132,8 @@ function to_ffmpeg_cmd(vso::VideoStreamOptions, xdim::Integer=0, ydim::Integer=0 # -pix_fmt: (mp4 only) the output pixel format # -profile:v: (mp4 only) the output video profile # -an: no audio in output - (format, framerate, compression, profile, pixel_format) = (vso.format, vso.framerate, vso.compression, vso.profile, vso.pixel_format) + (format, framerate, compression, profile, pixel_format) = + (vso.format, vso.framerate, vso.compression, vso.profile, vso.pixel_format) cpu_cores = length(Sys.cpu_info()) ffmpeg_prefix = ` @@ -166,7 +187,6 @@ function to_ffmpeg_cmd(vso::VideoStreamOptions, xdim::Integer=0, ydim::Integer=0 return `$(ffmpeg_prefix) $(ffmpeg_options)` end - struct VideoStream io::Base.PipeEndpoint process::Base.Process @@ -198,11 +218,19 @@ $(Base.doc(VideoStreamOptions)) * `connect=false`: connect window events or not * `screen_config...`: See `?Backend.Screen` or `Base.doc(Backend.Screen)` for applicable options that can be passed and forwarded to the backend. """ -function VideoStream(fig::FigureLike; - format="mp4", framerate=24, compression=nothing, profile=nothing, pixel_format=nothing, loglevel="quiet", - visible=false, connect=false, backend=current_backend(), - screen_config...) - +function VideoStream( + fig::FigureLike; + format="mp4", + framerate=24, + compression=nothing, + profile=nothing, + pixel_format=nothing, + loglevel="quiet", + visible=false, + connect=false, + backend=current_backend(), + screen_config..., +) dir = mktempdir() path = joinpath(dir, "$(gensym(:video)).$(format)") scene = get_scene(fig) @@ -267,5 +295,5 @@ end function extract_frames(video, frame_folder; loglevel="quiet") path = joinpath(frame_folder, "frame%04d.png") - FFMPEG.ffmpeg_exe(`-loglevel $(loglevel) -i $video -y $path`) + return FFMPEG.ffmpeg_exe(`-loglevel $(loglevel) -i $video -y $path`) end diff --git a/src/figureplotting.jl b/src/figureplotting.jl index 1c71419006a..d137d6e9470 100644 --- a/src/figureplotting.jl +++ b/src/figureplotting.jl @@ -1,5 +1,5 @@ struct AxisPlot - axis + axis::Any plot::AbstractPlot end @@ -13,23 +13,29 @@ get_scene(ap::AxisPlot) = get_scene(ap.axis.scene) function _validate_nt_like_keyword(@nospecialize(kw), name) if !(kw isa NamedTuple || kw isa AbstractDict{Symbol} || kw isa Attributes) - throw(ArgumentError(""" - The $name keyword argument received an unexpected value $(repr(kw)). - The $name keyword expects a collection of Symbol => value pairs, such as NamedTuple, Attributes, or AbstractDict{Symbol}. - The most common cause of this error is trying to create a one-element NamedTuple like (key = value) which instead creates a variable `key` with value `value`. - Write (key = value,) or (; key = value) instead.""" - )) + throw( + ArgumentError( + """ +The $name keyword argument received an unexpected value $(repr(kw)). +The $name keyword expects a collection of Symbol => value pairs, such as NamedTuple, Attributes, or AbstractDict{Symbol}. +The most common cause of this error is trying to create a one-element NamedTuple like (key = value) which instead creates a variable `key` with value `value`. +Write (key = value,) or (; key = value) instead.""", + ), + ) end end function _disallow_keyword(kw, attributes) if haskey(attributes, kw) - throw(ArgumentError("You cannot pass `$kw` as a keyword argument to this plotting function. Note that `axis` can only be passed to non-mutating plotting functions (not ending with a `!`) that implicitly create an axis, and `figure` only to those that implicitly create a `Figure`.")) + throw( + ArgumentError( + "You cannot pass `$kw` as a keyword argument to this plotting function. Note that `axis` can only be passed to non-mutating plotting functions (not ending with a `!`) that implicitly create an axis, and `figure` only to those that implicitly create a `Figure`.", + ), + ) end end -function plot(P::PlotFunc, args...; axis = NamedTuple(), figure = NamedTuple(), kw_attributes...) - +function plot(P::PlotFunc, args...; axis=NamedTuple(), figure=NamedTuple(), kw_attributes...) _validate_nt_like_keyword(axis, "axis") _validate_nt_like_keyword(figure, "figure") @@ -55,7 +61,7 @@ function plot(P::PlotFunc, args...; axis = NamedTuple(), figure = NamedTuple(), fig[1, 1] = ax p = plot!(ax, P, Attributes(kw_attributes), args...) - FigureAxisPlot(fig, ax, p) + return FigureAxisPlot(fig, ax, p) end # without scenelike, use current axis of current figure @@ -63,25 +69,26 @@ end function plot!(P::PlotFunc, args...; kw_attributes...) ax = current_axis(current_figure()) isnothing(ax) && error("There is no current axis to plot into.") - plot!(P, ax, args...; kw_attributes...) + return plot!(P, ax, args...; kw_attributes...) end -function plot(P::PlotFunc, gp::GridPosition, args...; axis = NamedTuple(), kwargs...) - +function plot(P::PlotFunc, gp::GridPosition, args...; axis=NamedTuple(), kwargs...) _validate_nt_like_keyword(axis, "axis") f = get_top_parent(gp) - c = contents(gp, exact = true) + c = contents(gp, exact=true) if !isempty(c) - error(""" - You have used the non-mutating plotting syntax with a GridPosition, which requires an empty GridLayout slot to create an axis in, but there are already the following objects at this layout position: + error( + """ + You have used the non-mutating plotting syntax with a GridPosition, which requires an empty GridLayout slot to create an axis in, but there are already the following objects at this layout position: - $(c) + $(c) - If you meant to plot into an axis at this position, use the plotting function with `!` (e.g. `func!` instead of `func`). - If you really want to place an axis on top of other blocks, make your intention clear and create it manually. - """) + If you meant to plot into an axis at this position, use the plotting function with `!` (e.g. `func!` instead of `func`). + If you really want to place an axis on top of other blocks, make your intention clear and create it manually. + """, + ) end axis = Dict(pairs(axis)) @@ -102,34 +109,36 @@ function plot(P::PlotFunc, gp::GridPosition, args...; axis = NamedTuple(), kwarg gp[] = ax p = plot!(P, ax, args...; kwargs...) - AxisPlot(ax, p) + return AxisPlot(ax, p) end function plot!(P::PlotFunc, gp::GridPosition, args...; kwargs...) - - c = contents(gp, exact = true) + c = contents(gp, exact=true) if !(length(c) == 1 && can_be_current_axis(c[1])) - error("There needs to be a single axis-like object at $(gp.span), $(gp.side) to plot into.\nUse a non-mutating plotting command to create an axis implicitly.") + error( + "There needs to be a single axis-like object at $(gp.span), $(gp.side) to plot into.\nUse a non-mutating plotting command to create an axis implicitly.", + ) end ax = first(c) - plot!(P, ax, args...; kwargs...) + return plot!(P, ax, args...; kwargs...) end -function plot(P::PlotFunc, gsp::GridSubposition, args...; axis = NamedTuple(), kwargs...) - +function plot(P::PlotFunc, gsp::GridSubposition, args...; axis=NamedTuple(), kwargs...) _validate_nt_like_keyword(axis, "axis") - - layout = GridLayoutBase.get_layout_at!(gsp.parent, createmissing = true) - c = contents(gsp, exact = true) + + layout = GridLayoutBase.get_layout_at!(gsp.parent, createmissing=true) + c = contents(gsp, exact=true) if !isempty(c) - error(""" - You have used the non-mutating plotting syntax with a GridSubposition, which requires an empty GridLayout slot to create an axis in, but there are already the following objects at this layout position: + error( + """ + You have used the non-mutating plotting syntax with a GridSubposition, which requires an empty GridLayout slot to create an axis in, but there are already the following objects at this layout position: - $(c) + $(c) - If you meant to plot into an axis at this position, use the plotting function with `!` (e.g. `func!` instead of `func`). - If you really want to place an axis on top of other blocks, make your intention clear and create it manually. - """) + If you meant to plot into an axis at this position, use the plotting function with `!` (e.g. `func!` instead of `func`). + If you really want to place an axis on top of other blocks, make your intention clear and create it manually. + """, + ) end fig = get_top_parent(gsp) @@ -147,27 +156,26 @@ function plot(P::PlotFunc, gsp::GridSubposition, args...; axis = NamedTuple(), k if is2d(proxyscene) ax = Axis(fig; axis...) else - ax = LScene(fig; axis..., scenekw = (camera = automatic,)) + ax = LScene(fig; axis..., scenekw=(camera=automatic,)) end end gsp.parent[gsp.rows, gsp.cols, gsp.side] = ax p = plot!(P, ax, args...; kwargs...) - AxisPlot(ax, p) + return AxisPlot(ax, p) end function plot!(P::PlotFunc, gsp::GridSubposition, args...; kwargs...) - - layout = GridLayoutBase.get_layout_at!(gsp.parent, createmissing = false) + layout = GridLayoutBase.get_layout_at!(gsp.parent, createmissing=false) gp = layout[gsp.rows, gsp.cols, gsp.side] - c = contents(gp, exact = true) + c = contents(gp, exact=true) if !(length(c) == 1 && can_be_current_axis(c[1])) error("There is not just one axis at $(gp).") end ax = first(c) - plot!(P, ax, args...; kwargs...) + return plot!(P, ax, args...; kwargs...) end update_state_before_display!(f::FigureAxisPlot) = update_state_before_display!(f.figure) @@ -177,4 +185,4 @@ function update_state_before_display!(f::Figure) update_state_before_display!(c) end return -end \ No newline at end of file +end diff --git a/src/figures.jl b/src/figures.jl index b1b212c367d..9229bd98494 100644 --- a/src/figures.jl +++ b/src/figures.jl @@ -27,7 +27,7 @@ if an axis is placed at that position (if not it errors) or it can reference an get_scene(fig::Figure) = fig.scene get_scene(fap::FigureAxisPlot) = fap.figure.scene -const _current_figure = Ref{Union{Nothing, Figure}}(nothing) +const _current_figure = Ref{Union{Nothing,Figure}}(nothing) "Returns the current active figure (or the last figure that got created)" current_figure() = _current_figure[] "Set `fig` as the current active scene" @@ -42,29 +42,28 @@ function current_axis!(fig::Figure, ax) error("This axis' parent is not the given figure") end fig.current_axis[] = ax - ax -end -function current_axis!(fig::Figure, ::Nothing) - fig.current_axis[] = nothing + return ax end +current_axis!(fig::Figure, ::Nothing) = fig.current_axis[] = nothing function current_axis!(ax) fig = ax.parent if !(fig isa Figure) - error("Axis parent is not a figure but a $(typeof(ax.parent)). Only axes in figures can have current_axis! called on them.") + error( + "Axis parent is not a figure but a $(typeof(ax.parent)). Only axes in figures can have current_axis! called on them.", + ) end current_axis!(fig, ax) # if the current axis is in a different figure, we switch to that as well # so that current_axis and current_figure are not out of sync current_figure!(fig) - ax + return ax end to_rectsides(n::Number) = to_rectsides((n, n, n, n)) -to_rectsides(t::Tuple{Any, Any, Any, Any}) = GridLayoutBase.RectSides{Float32}(t...) +to_rectsides(t::Tuple{Any,Any,Any,Any}) = GridLayoutBase.RectSides{Float32}(t...) function Figure(; kwargs...) - kwargs_dict = Dict(kwargs) padding = pop!(kwargs_dict, :figure_padding, current_default_theme()[:figure_padding]) scene = Scene(; camera=campixel!, kwargs_dict...) @@ -76,38 +75,29 @@ function Figure(; kwargs...) on(alignmode) do al layout.alignmode[] = al - GridLayoutBase.update!(layout) + return GridLayoutBase.update!(layout) end notify(alignmode) - f = Figure( - scene, - layout, - [], - Attributes(), - Ref{Any}(nothing) - ) + f = Figure(scene, layout, [], Attributes(), Ref{Any}(nothing)) # set figure as layout parent so GridPositions can refer to the figure # if connected correctly layout.parent = f - f + return f end export Figure, current_axis, current_figure, current_axis!, current_figure! +Base.getindex(fig::Figure, rows, cols, side=GridLayoutBase.Inner()) = fig.layout[rows, cols, side] -function Base.getindex(fig::Figure, rows, cols, side = GridLayoutBase.Inner()) - fig.layout[rows, cols, side] -end - -function Base.setindex!(fig::Figure, obj, rows, cols, side = GridLayoutBase.Inner()) +function Base.setindex!(fig::Figure, obj, rows, cols, side=GridLayoutBase.Inner()) fig.layout[rows, cols, side] = obj - obj + return obj end function Base.setindex!(fig::Figure, obj::AbstractArray, rows, cols) fig.layout[rows, cols] = obj - obj + return obj end Base.lastindex(f::Figure, i) = lastindex(f.layout, i) @@ -118,7 +108,6 @@ Base.show(io::IO, fig::Figure) = show(io, fig.scene) Base.show(io::IO, ::MIME"text/plain", fig::Figure) = print(io, "Figure()") # Base.show(io::IO, ::MIME"image/svg+xml", fig::Figure) = show(io, MIME"image/svg+xml"(), fig.scene) - get_figure(gsp::GridLayoutBase.GridSubposition) = get_figure(gsp.parent) function get_figure(gp::GridLayoutBase.GridPosition) top_parent = GridLayoutBase.top_parent(gp.layout) @@ -149,7 +138,7 @@ function resize_to_layout!(fig::Figure) bbox = GridLayoutBase.tight_bbox(fig.layout) new_size = (widths(bbox)...,) resize!(fig.scene, widths(bbox)...) - new_size + return new_size end function Base.empty!(fig::Figure) diff --git a/src/interaction/events.jl b/src/interaction/events.jl index 0a28e6a6cde..25daeccaddf 100644 --- a/src/interaction/events.jl +++ b/src/interaction/events.jl @@ -1,5 +1,4 @@ - window_area(scene, native_window) = not_implemented_for(native_window) window_open(scene, native_window) = not_implemented_for(native_window) mouse_buttons(scene, native_window) = not_implemented_for(native_window) @@ -12,9 +11,8 @@ hasfocus(scene, native_window) = not_implemented_for(native_window) entered_window(scene, native_window) = not_implemented_for(native_window) function connect_screen(scene::Scene, screen) - on(screen.window_open) do open - events(scene).window_open[] = open + return events(scene).window_open[] = open end window_area(scene, screen) @@ -58,8 +56,8 @@ Picks a mouse position. Implemented by the backend. """ function pick end -function pick(::Scene, ::Screen, xy) where Screen - @warn "Picking not supported yet by $(parentmodule(Screen))" maxlog=1 +function pick(::Scene, ::Screen, xy) where {Screen} + @warn "Picking not supported yet by $(parentmodule(Screen))" maxlog = 1 return nothing, 0 end @@ -69,12 +67,10 @@ Calls `func` if one clicks on `plot`. Implemented by the backend. """ function onpick end - ################################################################################ ### ispressed logic ################################################################################ - abstract type BooleanOperator end """ @@ -85,7 +81,7 @@ If more than two arguments are given a tree of `And` structs is created. See also: [`Or`](@ref), [`Not`](@ref), [`ispressed`](@ref), [`&`](@ref) """ -struct And{L, R} <: BooleanOperator +struct And{L,R} <: BooleanOperator left::L right::R end @@ -100,7 +96,7 @@ If more than two arguments are given a tree of `Or` structs is created. See also: [`And`](@ref), [`Not`](@ref), [`ispressed`](@ref), [`|`](@ref) """ -struct Or{L, R} <: BooleanOperator +struct Or{L,R} <: BooleanOperator left::L right::R end @@ -137,7 +133,7 @@ See also: [`And`](@ref), [`Or`](@ref), [`Not`](@ref), [`ispressed`](@ref), [`&`](@ref), [`|`](@ref), [`!`](@ref) """ struct Exclusively <: BooleanOperator - x::Set{Union{Keyboard.Button, Mouse.Button}} + x::Set{Union{Keyboard.Button,Mouse.Button}} end # Printing @@ -147,23 +143,23 @@ function Base.show(io::IO, op::And) show(io, op.left) print(io, " & ") show(io, op.right) - print(io, ")") + return print(io, ")") end function Base.show(io::IO, op::Or) print(io, "(") show(io, op.left) print(io, " | ") show(io, op.right) - print(io, ")") + return print(io, ")") end function Base.show(io::IO, op::Not) print(io, "!") - show(io, op.x) + return show(io, op.x) end function Base.show(io::IO, op::Exclusively) print(io, "exclusively(") join(io, op.x, " & ") - print(io, ")") + return print(io, ")") end # Constructors @@ -173,53 +169,34 @@ Or(left, right, rest...) = Or(Or(left, right), rest...) And(x) = x Or(x) = x - -function Base.:(&)( - left::Union{BooleanOperator, Keyboard.Button, Mouse.Button}, - right::Union{BooleanOperator, Keyboard.Button, Mouse.Button, Bool} - ) - And(left, right) -end function Base.:(&)( - left::Bool, - right::Union{BooleanOperator, Keyboard.Button, Mouse.Button} - ) - And(left, right) + left::Union{BooleanOperator,Keyboard.Button,Mouse.Button}, + right::Union{BooleanOperator,Keyboard.Button,Mouse.Button,Bool}, +) + return And(left, right) end +Base.:(&)(left::Bool, right::Union{BooleanOperator,Keyboard.Button,Mouse.Button}) = And(left, right) function Base.:(|)( - left::Union{BooleanOperator, Keyboard.Button, Mouse.Button}, - right::Union{BooleanOperator, Keyboard.Button, Mouse.Button, Bool} - ) - Or(left, right) + left::Union{BooleanOperator,Keyboard.Button,Mouse.Button}, + right::Union{BooleanOperator,Keyboard.Button,Mouse.Button,Bool}, +) + return Or(left, right) end -function Base.:(|)( - left::Bool, - right::Union{BooleanOperator, Keyboard.Button, Mouse.Button} - ) - Or(left, right) -end -Base.:(!)(x::Union{BooleanOperator, Keyboard.Button, Mouse.Button}) = Not(x) +Base.:(|)(left::Bool, right::Union{BooleanOperator,Keyboard.Button,Mouse.Button}) = Or(left, right) +Base.:(!)(x::Union{BooleanOperator,Keyboard.Button,Mouse.Button}) = Not(x) - -Exclusively(x::Union{Vector, Tuple}) = Exclusively(Set(x)) -Exclusively(x::Union{Keyboard.Button, Mouse.Button}) = Exclusively(Set((x,))) +Exclusively(x::Union{Vector,Tuple}) = Exclusively(Set(x)) +Exclusively(x::Union{Keyboard.Button,Mouse.Button}) = Exclusively(Set((x,))) Exclusively(x::Bool) = x Exclusively(x::Or) = Or(Exclusively(x.left), Exclusively(x.right)) Exclusively(x::And) = Or(Exclusively.(unique(create_sets(x)))...) - # Sets represent `And`, arrays represent `Or` -function create_sets(x::And) - [union(left, right) for left in create_sets(x.left) - for right in create_sets(x.right)] -end +create_sets(x::And) = [union(left, right) for left in create_sets(x.left) for right in create_sets(x.right)] create_sets(x::Or) = vcat(create_sets(x.left), create_sets(x.right)) -create_sets(::Not) = Set{Union{Keyboard.Button, Mouse.Button}}() -function create_sets(b::Union{Keyboard.Button, Mouse.Button}) - [Set{Union{Keyboard.Button, Mouse.Button}}((b,))] -end -create_sets(s::Set) = [Set{Union{Keyboard.Button, Mouse.Button}}(s)] - +create_sets(::Not) = Set{Union{Keyboard.Button,Mouse.Button}}() +create_sets(b::Union{Keyboard.Button,Mouse.Button}) = [Set{Union{Keyboard.Button,Mouse.Button}}((b,))] +create_sets(s::Set) = [Set{Union{Keyboard.Button,Mouse.Button}}(s)] # ispressed and logic evaluation @@ -261,7 +238,7 @@ ispressed(scene, key::Keyboard.Button) = ispressed(events(scene), key) # Boolean Operator evaluation ispressed(scene, op::And) = ispressed(scene, op.left) && ispressed(scene, op.right) -ispressed(scene, op::Or) = ispressed(scene, op.left) || ispressed(scene, op.right) +ispressed(scene, op::Or) = ispressed(scene, op.left) || ispressed(scene, op.right) ispressed(scene, op::Not) = !ispressed(scene, op.x) ispressed(scene::Scene, op::Exclusively) = ispressed(events(scene), op) ispressed(e::Events, op::Exclusively) = op.x == union(e.keyboardstate, e.mousebuttonstate) diff --git a/src/interaction/inspector.jl b/src/interaction/inspector.jl index 6d02b191f81..5be011b0611 100644 --- a/src/interaction/inspector.jl +++ b/src/interaction/inspector.jl @@ -17,7 +17,12 @@ function bbox2string(bbox::Rect3) y: (%0.3f, %0.3f) z: (%0.3f, %0.3f) """, - p0[1], p1[1], p0[2], p1[2], p0[3], p1[3] + p0[1], + p1[1], + p0[2], + p1[2], + p0[3], + p1[3] ) end @@ -30,28 +35,29 @@ function bbox2string(bbox::Rect2) x: (%0.3f, %0.3f) y: (%0.3f, %0.3f) """, - p0[1], p1[1], p0[2], p1[2] + p0[1], + p1[1], + p0[2], + p1[2] ) end color2text(c::AbstractFloat) = @sprintf("%0.3f", c) color2text(c::Symbol) = string(c) color2text(c) = color2text(to_color(c)) -function color2text(c::RGBAf) +color2text(c::RGBAf) = if c.alpha == 1.0 @sprintf("RGB(%0.2f, %0.2f, %0.2f)", c.r, c.g, c.b) else @sprintf("RGBA(%0.2f, %0.2f, %0.2f, %0.2f)", c.r, c.g, c.b, c.alpha) end -end color2text(name, i::Integer, j::Integer, c) = "$name[$i, $j] = $(color2text(c))" function color2text(name, i, j, c) idxs = @sprintf("%0.2f, %0.2f", i, j) - "$name[$idxs] = $(color2text(c))" + return "$name[$idxs] = $(color2text(c))" end - ### dealing with markersize and rotations ######################################## @@ -63,48 +69,47 @@ _to_scale(v::Vector, idx) = _to_scale(v[idx], idx) _to_rotation(x, idx) = to_rotation(x) _to_rotation(x::Vector, idx) = to_rotation(x[idx]) - ### Selecting a point on a nearby line ######################################## function closest_point_on_line(p0::Point2f, p1::Point2f, r::Point2f) # This only works in 2D - AP = P .- A; AB = B .- A - A .+ AB * dot(AP, AB) / dot(AB, AB) + AP = P .- A + AB = B .- A + return A .+ AB * dot(AP, AB) / dot(AB, AB) end function view_ray(scene) inv_projview = inv(camera(scene).projectionview[]) - view_ray(inv_projview, events(scene).mouseposition[], pixelarea(scene)[]) + return view_ray(inv_projview, events(scene).mouseposition[], pixelarea(scene)[]) end function view_ray(inv_view_proj, mpos, area::Rect2) # This figures out the camera view direction from the projectionview matrix (?) # and computes a ray from a near and a far point. # Based on ComputeCameraRay from ImGuizmo - mp = 2f0 .* (mpos .- minimum(area)) ./ widths(area) .- 1f0 + mp = 2.0f0 .* (mpos .- minimum(area)) ./ widths(area) .- 1.0f0 v = inv_view_proj * Vec4f(0, 0, -10, 1) reversed = v[3] < v[4] - near = reversed ? 1f0 - 1e-6 : 0f0 - far = reversed ? 0f0 : 1f0 - 1e-6 + near = reversed ? 1.0f0 - 1e-6 : 0.0f0 + far = reversed ? 0.0f0 : 1.0f0 - 1e-6 - origin = inv_view_proj * Vec4f(mp[1], mp[2], near, 1f0) + origin = inv_view_proj * Vec4f(mp[1], mp[2], near, 1.0f0) origin = origin[Vec(1, 2, 3)] ./ origin[4] - p = inv_view_proj * Vec4f(mp[1], mp[2], far, 1f0) + p = inv_view_proj * Vec4f(mp[1], mp[2], far, 1.0f0) p = p[Vec(1, 2, 3)] ./ p[4] dir = normalize(p .- origin) return origin, dir end - # These work in 2D and 3D function closest_point_on_line(A, B, origin, dir) - closest_point_on_line( + return closest_point_on_line( to_ndim(Point3f, A, 0), to_ndim(Point3f, B, 0), to_ndim(Point3f, origin, 0), - to_ndim(Vec3f, dir, 0) + to_ndim(Vec3f, dir, 0), ) end function closest_point_on_line(A::Point3f, B::Point3f, origin::Point3f, dir::Vec3f) @@ -117,7 +122,7 @@ function closest_point_on_line(A::Point3f, B::Point3f, origin::Point3f, dir::Vec # e_RD, e_perp defines a plane with normal n n = normalize(cross(u_dir, u_perp)) t = dot(origin .- A, n) / dot(u_AB, n) - A .+ clamp(t, 0.0, AB_norm) * u_AB + return A .+ clamp(t, 0.0, AB_norm) * u_AB end function ray_triangle_intersection(A, B, C, origin, dir) @@ -137,24 +142,22 @@ function ray_triangle_intersection(A, B, C, origin, dir) end end - ### Surface positions ######################################## -surface_x(xs::ClosedInterval, i, j, N) = minimum(xs) + (maximum(xs) - minimum(xs)) * (i-1) / (N-1) +surface_x(xs::ClosedInterval, i, j, N) = minimum(xs) + (maximum(xs) - minimum(xs)) * (i - 1) / (N - 1) surface_x(xs, i, j, N) = xs[i] surface_x(xs::AbstractMatrix, i, j, N) = xs[i, j] -surface_y(ys::ClosedInterval, i, j, N) = minimum(ys) + (maximum(ys) - minimum(ys)) * (j-1) / (N-1) +surface_y(ys::ClosedInterval, i, j, N) = minimum(ys) + (maximum(ys) - minimum(ys)) * (j - 1) / (N - 1) surface_y(ys, i, j, N) = ys[j] surface_y(ys::AbstractMatrix, i, j, N) = ys[i, j] function surface_pos(xs, ys, zs, i, j) N, M = size(zs) - Point3f(surface_x(xs, i, j, N), surface_y(ys, i, j, M), zs[i, j]) + return Point3f(surface_x(xs, i, j, N), surface_y(ys, i, j, M), zs[i, j]) end - ### Mapping mesh vertex indices to Vector{Polygon} index ######################################## @@ -178,28 +181,24 @@ function ncoords(poly::Polygon) for int in poly.interiors N += length(int) + 1 end - N + return N end ## Shifted projection ######################################## function shift_project(scene, plot, pos) - project( + return project( camera(scene).projectionview[], Vec2f(widths(pixelarea(scene)[])), - apply_transform(transform_func(plot), pos, to_value(get(plot, :space, :data))) + apply_transform(transform_func(plot), pos, to_value(get(plot, :space, :data))), ) .+ Vec2f(origin(pixelarea(scene)[])) end - - ################################################################################ ### Interactive selection via DataInspector ################################################################################ - - # TODO destructor? mutable struct DataInspector root::Scene @@ -212,11 +211,10 @@ mutable struct DataInspector obsfuncs::Vector{Any} end - function DataInspector(scene::Scene, plot::AbstractPlot, attributes) x = DataInspector(scene, attributes, AbstractPlot[], plot, plot, Any[]) # finalizer(cleanup, x) # doesn't get triggered when this is dereferenced - x + return x end function cleanup(inspector::DataInspector) @@ -224,12 +222,10 @@ function cleanup(inspector::DataInspector) empty!(inspector.obsfuncs) delete!(inspector.root, inspector.plot) clear_temporary_plots!(inspector, inspector.slection) - inspector + return inspector end -function Base.delete!(::Union{Scene, Figure}, inspector::DataInspector) - cleanup(inspector) -end +Base.delete!(::Union{Scene,Figure}, inspector::DataInspector) = cleanup(inspector) enable!(inspector::DataInspector) = inspector.attributes.enabled[] = true disable!(inspector::DataInspector) = inspector.attributes.enabled[] = false @@ -259,44 +255,42 @@ returning a label. See Makie documentation for more detail. tooltip is always in front. - and all attributes from `Tooltip` """ -function DataInspector(fig_or_block; kwargs...) - DataInspector(get_scene(fig_or_block); kwargs...) -end +DataInspector(fig_or_block; kwargs...) = DataInspector(get_scene(fig_or_block); kwargs...) -function DataInspector(scene::Scene; priority = 100, kwargs...) +function DataInspector(scene::Scene; priority=100, kwargs...) parent = root(scene) @assert origin(pixelarea(parent)[]) == Vec2f(0) attrib_dict = Dict(kwargs) base_attrib = Attributes( # General DataInspector settings - range = pop!(attrib_dict, :range, 10), - enabled = pop!(attrib_dict, :enabled, true), - depth = pop!(attrib_dict, :depth, 9e3), - enable_indicators = pop!(attrib_dict, :show_bbox_indicators, true), - offset = get(attrib_dict, :offset, 10f0), + range=pop!(attrib_dict, :range, 10), + enabled=pop!(attrib_dict, :enabled, true), + depth=pop!(attrib_dict, :depth, 9e3), + enable_indicators=pop!(attrib_dict, :show_bbox_indicators, true), + offset=get(attrib_dict, :offset, 10.0f0), # Settings for indicators (plots that highlight the current selection) - indicator_color = pop!(attrib_dict, :indicator_color, :red), - indicator_linewidth = pop!(attrib_dict, :indicator_linewidth, 2), - indicator_linestyle = pop!(attrib_dict, :indicator_linestyle, nothing), + indicator_color=pop!(attrib_dict, :indicator_color, :red), + indicator_linewidth=pop!(attrib_dict, :indicator_linewidth, 2), + indicator_linestyle=pop!(attrib_dict, :indicator_linestyle, nothing), # Reusable values for creating indicators - indicator_visible = false, + indicator_visible=false, # General reusable - _color = RGBAf(0,0,0,0), + _color=RGBAf(0, 0, 0, 0), ) - plot = tooltip!(parent, Observable(Point2f(0)), text = Observable(""); visible=false, attrib_dict...) + plot = tooltip!(parent, Observable(Point2f(0)), text=Observable(""); visible=false, attrib_dict...) on(z -> translate!(plot, 0, 0, z), base_attrib.depth) notify(base_attrib.depth) inspector = DataInspector(parent, plot, base_attrib) e = events(parent) - f1 = on(_ -> on_hover(inspector), e.mouseposition, priority = priority) - f2 = on(_ -> on_hover(inspector), e.scroll, priority = priority) + f1 = on(_ -> on_hover(inspector), e.mouseposition, priority=priority) + f2 = on(_ -> on_hover(inspector), e.scroll, priority=priority) push!(inspector.obsfuncs, f1, f2) @@ -308,7 +302,7 @@ function DataInspector(scene::Scene; priority = 100, kwargs...) return end - inspector + return inspector end DataInspector(; kwargs...) = DataInspector(current_figure(); kwargs...) @@ -342,7 +336,6 @@ function on_hover(inspector) return Consume(false) end - function show_data_recursion(inspector, plot, idx) processed = show_data_recursion(inspector, plot.parent, idx, plot) if processed @@ -382,7 +375,7 @@ function show_data_recursion(inspector, plot::AbstractPlot, idx, source) if processed inspector.selection = plot end - + return processed end end @@ -400,10 +393,7 @@ function clear_temporary_plots!(inspector::DataInspector, plot) end # clear attributes which are reused for indicator plots - for key in ( - :indicator_color, :indicator_linestyle, - :indicator_linewidth, :indicator_visible - ) + for key in (:indicator_color, :indicator_linestyle, :indicator_linewidth, :indicator_visible) empty!(inspector.attributes[key].listeners) end @@ -426,14 +416,10 @@ function update_tooltip_alignment!(inspector, proj_pos) return end - - ################################################################################ ### show_data for primitive plots ################################################################################ - - # TODO: better 3D scaling function show_data(inspector::DataInspector, plot::Scatter, idx) a = inspector.attributes @@ -456,7 +442,6 @@ function show_data(inspector::DataInspector, plot::Scatter, idx) return true end - function show_data(inspector::DataInspector, plot::MeshScatter, idx) a = inspector.attributes tt = inspector.plot @@ -466,7 +451,7 @@ function show_data(inspector::DataInspector, plot::MeshScatter, idx) T = transformationmatrix( plot[1][][idx], _to_scale(plot.markersize[], idx), - _to_rotation(plot.rotations[], idx) + _to_rotation(plot.rotations[], idx), ) if inspector.selection != plot @@ -479,14 +464,18 @@ function show_data(inspector::DataInspector, plot::MeshScatter, idx) upvector = cc.upvector[] end - bbox = Rect{3, Float32}(convert_attribute( - plot.marker[], Key{:marker}(), Key{Makie.plotkey(plot)}() - )) + bbox = + Rect{3,Float32}(convert_attribute(plot.marker[], Key{:marker}(), Key{Makie.plotkey(plot)}())) p = wireframe!( - scene, bbox, model = T, color = a.indicator_color, - linewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle, - visible = a.indicator_visible, inspectable = false + scene, + bbox, + model=T, + color=a.indicator_color, + linewidth=a.indicator_linewidth, + linestyle=a.indicator_linestyle, + visible=a.indicator_visible, + inspectable=false, ) push!(inspector.temp_plots, p) @@ -496,10 +485,8 @@ function show_data(inspector::DataInspector, plot::MeshScatter, idx) elseif !isempty(inspector.temp_plots) p = inspector.temp_plots[1] p.model[] = T - end - a.indicator_visible[] = true end @@ -516,14 +503,13 @@ function show_data(inspector::DataInspector, plot::MeshScatter, idx) return true end - -function show_data(inspector::DataInspector, plot::Union{Lines, LineSegments}, idx) +function show_data(inspector::DataInspector, plot::Union{Lines,LineSegments}, idx) a = inspector.attributes tt = inspector.plot scene = parent_scene(plot) # cast ray from cursor into screen, find closest point to line - p0, p1 = plot[1][][idx-1:idx] + p0, p1 = plot[1][][(idx - 1):idx] origin, dir = view_ray(scene) pos = closest_point_on_line(p0, p1, origin, dir) lw = plot.linewidth[] isa Vector ? plot.linewidth[][idx] : plot.linewidth[] @@ -543,7 +529,6 @@ function show_data(inspector::DataInspector, plot::Union{Lines, LineSegments}, i return true end - function show_data(inspector::DataInspector, plot::Mesh, idx) a = inspector.attributes tt = inspector.plot @@ -565,9 +550,13 @@ function show_data(inspector::DataInspector, plot::Mesh, idx) end p = wireframe!( - scene, bbox, color = a.indicator_color, - linewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle, - visible = a.indicator_visible, inspectable = false + scene, + bbox, + color=a.indicator_color, + linewidth=a.indicator_linewidth, + linestyle=a.indicator_linestyle, + visible=a.indicator_visible, + inspectable=false, ) push!(inspector.temp_plots, p) @@ -592,7 +581,6 @@ function show_data(inspector::DataInspector, plot::Mesh, idx) return true end - function show_data(inspector::DataInspector, plot::Surface, idx) a = inspector.attributes tt = inspector.plot @@ -605,29 +593,32 @@ function show_data(inspector::DataInspector, plot::Surface, idx) ys = plot[2][] zs = plot[3][] w, h = size(zs) - _i = mod1(idx, w); _j = div(idx-1, w) + _i = mod1(idx, w) + _j = div(idx - 1, w) # This isn't the most accurate so we include some neighboring faces origin, dir = view_ray(scene) pos = Point3f(NaN) - for i in _i-1:_i+1, j in _j-1:_j+1 + for i in (_i - 1):(_i + 1), j in (_j - 1):(_j + 1) (1 <= i <= w) && (1 <= j < h) || continue if i - 1 > 0 pos = ray_triangle_intersection( surface_pos(xs, ys, zs, i, j), - surface_pos(xs, ys, zs, i-1, j), - surface_pos(xs, ys, zs, i, j+1), - origin, dir + surface_pos(xs, ys, zs, i - 1, j), + surface_pos(xs, ys, zs, i, j + 1), + origin, + dir, ) end if i + 1 <= w && isnan(pos) pos = ray_triangle_intersection( surface_pos(xs, ys, zs, i, j), - surface_pos(xs, ys, zs, i, j+1), - surface_pos(xs, ys, zs, i+1, j+1), - origin, dir + surface_pos(xs, ys, zs, i, j + 1), + surface_pos(xs, ys, zs, i + 1, j + 1), + origin, + dir, ) end @@ -642,7 +633,7 @@ function show_data(inspector::DataInspector, plot::Surface, idx) tt.text[] = position2string(pos) end tt.visible[] = true - tt.offset[] = 0f0 + tt.offset[] = 0.0f0 else tt.visible[] = false end @@ -651,13 +642,9 @@ function show_data(inspector::DataInspector, plot::Surface, idx) return true end -function show_data(inspector::DataInspector, plot::Heatmap, idx) - show_imagelike(inspector, plot, "H", true) -end +show_data(inspector::DataInspector, plot::Heatmap, idx) = show_imagelike(inspector, plot, "H", true) -function show_data(inspector::DataInspector, plot::Image, idx) - show_imagelike(inspector, plot, "img", false) -end +show_data(inspector::DataInspector, plot::Image, idx) = show_imagelike(inspector, plot, "img", false) function show_imagelike(inspector, plot, name, edge_based) a = inspector.attributes @@ -670,7 +657,8 @@ function show_imagelike(inspector, plot, name, edge_based) x, y = mpos else i, j, z = _pixelated_getindex(plot[1][], plot[2][], plot[3][], mpos, edge_based) - x = i; y = j + x = i + y = j end if haskey(plot, :inspector_label) @@ -688,8 +676,9 @@ function show_imagelike(inspector, plot, name, edge_based) a._color[] = if z isa AbstractFloat interpolated_getindex( - to_colormap(plot.colormap[]), z, - to_value(get(plot.attributes, :colorrange, (0, 1))) + to_colormap(plot.colormap[]), + z, + to_value(get(plot.attributes, :colorrange, (0, 1))), ) else z @@ -704,14 +693,17 @@ function show_imagelike(inspector, plot, name, edge_based) if inspector.selection != plot clear_temporary_plots!(inspector, plot) p = scatter!( - scene, position, color = a._color, - visible = a.indicator_visible, - inspectable = false, - marker=:rect, markersize = map(r -> 3r, a.range), - strokecolor = a.indicator_color, - strokewidth = a.indicator_linewidth + scene, + position, + color=a._color, + visible=a.indicator_visible, + inspectable=false, + marker=:rect, + markersize=map(r -> 3r, a.range), + strokecolor=a.indicator_color, + strokewidth=a.indicator_linewidth, ) - translate!(p, Vec3f(0, 0, a.depth[]-1)) + translate!(p, Vec3f(0, 0, a.depth[] - 1)) push!(inspector.temp_plots, p) elseif !isempty(inspector.temp_plots) p = inspector.temp_plots[1] @@ -723,11 +715,15 @@ function show_imagelike(inspector, plot, name, edge_based) if inspector.selection != plot clear_temporary_plots!(inspector, plot) p = wireframe!( - scene, bbox, color = a.indicator_color, - strokewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle, - visible = a.indicator_visible, inspectable = false + scene, + bbox, + color=a.indicator_color, + strokewidth=a.indicator_linewidth, + linestyle=a.indicator_linestyle, + visible=a.indicator_visible, + inspectable=false, ) - translate!(p, Vec3f(0, 0, a.depth[]-1)) + translate!(p, Vec3f(0, 0, a.depth[] - 1)) push!(inspector.temp_plots, p) elseif !isempty(inspector.temp_plots) p = inspector.temp_plots[1] @@ -742,7 +738,6 @@ function show_imagelike(inspector, plot, name, edge_based) return true end - function _interpolated_getindex(xs, ys, img, mpos) x0, x1 = extrema(xs) y0, y1 = extrema(ys) @@ -750,12 +745,13 @@ function _interpolated_getindex(xs, ys, img, mpos) i = clamp((x - x0) / (x1 - x0) * size(img, 1) + 0.5, 1, size(img, 1)) j = clamp((y - y0) / (y1 - y0) * size(img, 2) + 0.5, 1, size(img, 2)) - l = clamp(floor(Int, i), 1, size(img, 1)-1); - r = clamp(l+1, 2, size(img, 1)) - b = clamp(floor(Int, j), 1, size(img, 2)-1); - t = clamp(b+1, 2, size(img, 2)) - z = ((r-i) * img[l, b] + (i-l) * img[r, b]) * (t-j) + - ((r-i) * img[l, t] + (i-l) * img[r, t]) * (j-b) + l = clamp(floor(Int, i), 1, size(img, 1) - 1) + r = clamp(l + 1, 2, size(img, 1)) + b = clamp(floor(Int, j), 1, size(img, 2) - 1) + t = clamp(b + 1, 2, size(img, 2)) + z = + ((r - i) * img[l, b] + (i - l) * img[r, b]) * (t - j) + + ((r - i) * img[l, t] + (i - l) * img[r, t]) * (j - b) # float, float, value (i, j are no longer used) return i, j, z @@ -769,7 +765,7 @@ function _pixelated_getindex(xs, ys, img, mpos, edge_based) j = clamp(round(Int, (y - y0) / (y1 - y0) * size(img, 2) + 0.5), 1, size(img, 2)) # int, int, value - return i, j, img[i,j] + return i, j, img[i, j] end function _interpolated_getindex(xs::Vector, ys::Vector, img, mpos) @@ -779,16 +775,16 @@ function _interpolated_getindex(xs::Vector, ys::Vector, img, mpos) # z = ((xs[i+1] - x) / w * img[i, j] + (x - xs[i]) / w * img[i+1, j]) * (ys[j+1] - y) / h + # ((xs[i+1] - x) / w * img[i, j+1] + (x - xs[i]) / w * img[i+1, j+1]) * (y - ys[j]) / h # return i, j, z - _interpolated_getindex(minimum(xs)..maximum(xs), minimum(ys)..maximum(ys), img, mpos) + return _interpolated_getindex(minimum(xs) .. maximum(xs), minimum(ys) .. maximum(ys), img, mpos) end function _pixelated_getindex(xs::Vector, ys::Vector, img, mpos, edge_based) if edge_based x, y = mpos - i = max(1, something(findfirst(v -> v >= x, xs), length(xs))-1) - j = max(1, something(findfirst(v -> v >= y, ys), length(ys))-1) + i = max(1, something(findfirst(v -> v >= x, xs), length(xs)) - 1) + j = max(1, something(findfirst(v -> v >= y, ys), length(ys)) - 1) return i, j, img[i, j] else - _pixelated_getindex(minimum(xs)..maximum(xs), minimum(ys)..maximum(ys), img, mpos, edge_based) + _pixelated_getindex(minimum(xs) .. maximum(xs), minimum(ys) .. maximum(ys), img, mpos, edge_based) end end @@ -796,40 +792,30 @@ function _pixelated_image_bbox(xs, ys, img, i::Integer, j::Integer, edge_based) x0, x1 = extrema(xs) y0, y1 = extrema(ys) nw, nh = ((x1 - x0), (y1 - y0)) ./ size(img) - Rect2f(x0 + nw * (i-1), y0 + nh * (j-1), nw, nh) + return Rect2f(x0 + nw * (i - 1), y0 + nh * (j - 1), nw, nh) end function _pixelated_image_bbox(xs::Vector, ys::Vector, img, i::Integer, j::Integer, edge_based) if edge_based - Rect2f(xs[i], ys[j], xs[i+1] - xs[i], ys[j+1] - ys[j]) + Rect2f(xs[i], ys[j], xs[i + 1] - xs[i], ys[j + 1] - ys[j]) else - _pixelated_image_bbox( - minimum(xs)..maximum(xs), minimum(ys)..maximum(ys), - img, i, j, edge_based - ) + _pixelated_image_bbox(minimum(xs) .. maximum(xs), minimum(ys) .. maximum(ys), img, i, j, edge_based) end end -function show_data(inspector::DataInspector, plot, idx, source=nothing) - return false -end - +show_data(inspector::DataInspector, plot, idx, source=nothing) = false ################################################################################ ### show_data for Combined/recipe plots ################################################################################ - - function show_data(inspector::DataInspector, plot::BarPlot, idx, ::Lines) - return show_data(inspector, plot, div(idx-1, 6)+1) + return show_data(inspector, plot, div(idx - 1, 6) + 1) end function show_data(inspector::DataInspector, plot::BarPlot, idx, ::Mesh) - return show_data(inspector, plot, div(idx-1, 4)+1) + return show_data(inspector, plot, div(idx - 1, 4) + 1) end - - function show_data(inspector::DataInspector, plot::BarPlot, idx) a = inspector.attributes tt = inspector.plot @@ -846,9 +832,14 @@ function show_data(inspector::DataInspector, plot::BarPlot, idx) if inspector.selection != plot clear_temporary_plots!(inspector, plot) p = wireframe!( - scene, bbox, model = model, color = a.indicator_color, - strokewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle, - visible = a.indicator_visible, inspectable = false + scene, + bbox, + model=model, + color=a.indicator_color, + strokewidth=a.indicator_linewidth, + linestyle=a.indicator_linestyle, + visible=a.indicator_visible, + inspectable=false, ) translate!(p, Vec3f(0, 0, a.depth[])) push!(inspector.temp_plots, p) @@ -872,7 +863,7 @@ function show_data(inspector::DataInspector, plot::BarPlot, idx) end function show_data(inspector::DataInspector, plot::Arrows, idx, ::LineSegments) - return show_data(inspector, plot, div(idx+1, 2), nothing) + return show_data(inspector, plot, div(idx + 1, 2), nothing) end function show_data(inspector::DataInspector, plot::Arrows, idx, source) a = inspector.plot.attributes @@ -931,7 +922,6 @@ function show_poly(inspector, plot, idx, source) idx = vertexindex2poly(plot[1][], idx) if a.enable_indicators[] - line_collection = copy(convert_arguments(PointBased(), plot[1][][idx].exterior)[1]) for int in plot[1][][idx].interiors push!(line_collection, Point2f(NaN)) @@ -943,11 +933,15 @@ function show_poly(inspector, plot, idx, source) clear_temporary_plots!(inspector, plot) p = lines!( - scene, line_collection, color = a.indicator_color, - strokewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle, - visible = a.indicator_visible, inspectable = false + scene, + line_collection, + color=a.indicator_color, + strokewidth=a.indicator_linewidth, + linestyle=a.indicator_linestyle, + visible=a.indicator_visible, + inspectable=false, ) - translate!(p, Vec3f(0, 0, a.depth[]-1)) + translate!(p, Vec3f(0, 0, a.depth[] - 1)) push!(inspector.temp_plots, p) elseif !isempty(inspector.temp_plots) @@ -977,7 +971,7 @@ function show_data(inspector::DataInspector, plot::VolumeSlices, idx, child::Hea Point3f(T * Point4f(qs[1], ps[1], 0, 1)), Point3f(T * Point4f(qs[1], ps[2], 0, 1)), Point3f(T * Point4f(qs[2], ps[2], 0, 1)), - Point3f(T * Point4f(qs[2], ps[1], 0, 1)) + Point3f(T * Point4f(qs[2], ps[1], 0, 1)), ] origin, dir = view_ray(scene) @@ -990,11 +984,14 @@ function show_data(inspector::DataInspector, plot::VolumeSlices, idx, child::Hea if !isnan(pos) child_idx = findfirst(isequal(child), plot.plots) if child_idx == 2 - x = pos[2]; y = pos[3] + x = pos[2] + y = pos[3] elseif child_idx == 3 - x = pos[1]; y = pos[3] + x = pos[1] + y = pos[3] else - x = pos[1]; y = pos[2] + x = pos[1] + y = pos[2] end i = clamp(round(Int, (x - qs[1]) / (qs[2] - qs[1]) * size(data, 1) + 0.5), 1, size(data, 1)) j = clamp(round(Int, (y - ps[1]) / (ps[2] - ps[1]) * size(data, 2) + 0.5), 1, size(data, 2)) @@ -1004,10 +1001,7 @@ function show_data(inspector::DataInspector, plot::VolumeSlices, idx, child::Hea if haskey(plot, :inspector_label) tt.text[] = plot[:inspector_label][](plot, (i, j), pos) else - tt.text[] = @sprintf( - "x: %0.6f\ny: %0.6f\nz: %0.6f\n%0.6f0", - pos[1], pos[2], pos[3], val - ) + tt.text[] = @sprintf("x: %0.6f\ny: %0.6f\nz: %0.6f\n%0.6f0", pos[1], pos[2], pos[3], val) end tt.visible[] = true else diff --git a/src/interaction/interactive_api.jl b/src/interaction/interactive_api.jl index 309a8ed3fec..61bdd20007a 100644 --- a/src/interaction/interactive_api.jl +++ b/src/interaction/interactive_api.jl @@ -1,7 +1,6 @@ export mouseover, mouseposition, hovered_scene export select_rectangle, select_line, select_point - """ mouseover(fig/ax/scene, plots::AbstractPlot...) @@ -20,7 +19,7 @@ Calls `f(plot, idx)` whenever the mouse is over any of `plots`. `idx` is an index, e.g. when over a scatter plot, it will be the index of the hovered element """ -onpick(f, x, plots::AbstractPlot...; range=1) = onpick(f, get_scene(x), plots..., range = range) +onpick(f, x, plots::AbstractPlot...; range=1) = onpick(f, get_scene(x), plots..., range=range) function onpick(f, scene::Scene, plots::AbstractPlot...; range=1) fplots = flatten_plots(plots) args = range == 1 ? (scene,) : (scene, range) @@ -33,27 +32,27 @@ end @deprecate mouse_selection pick -function flatten_plots(x::Atomic, plots = AbstractPlot[]) +function flatten_plots(x::Atomic, plots=AbstractPlot[]) if isempty(x.plots) push!(plots, x) else flatten_plots(x.plots, plots) end - plots + return plots end -function flatten_plots(x::Combined, plots = AbstractPlot[]) +function flatten_plots(x::Combined, plots=AbstractPlot[]) for elem in x.plots flatten_plots(elem, plots) end - plots + return plots end -function flatten_plots(array, plots = AbstractPlot[]) +function flatten_plots(array, plots=AbstractPlot[]) for elem in array flatten_plots(elem, plots) end - plots + return plots end """ @@ -63,27 +62,23 @@ Returns a new observable that is true whenever the cursor is inside the given sc See also: [`is_mouseinside`](@ref) """ -function mouse_in_scene(scene::Scene; priority = 0) +function mouse_in_scene(scene::Scene; priority=0) p = rootparent(scene) output = Observable(Vec2(0.0)) - on(events(scene).mouseposition, priority = priority) do mp + on(events(scene).mouseposition, priority=priority) do mp output[] = Vec(mp) .- minimum(pixelarea(scene)[]) return Consume(false) end - output + return output end - """ pick(fig/ax/scene, x, y) Returns the plot under pixel position `(x, y)`. """ pick(obj, x::Number, y::Number) = pick(get_scene(obj), x, y) -function pick(scene::Scene, x::Number, y::Number) - return pick(scene, Vec{2, Float64}(x, y)) -end - +pick(scene::Scene, x::Number, y::Number) = pick(scene, Vec{2,Float64}(x, y)) """ pick(fig/ax/scene, xy::VecLike) @@ -95,7 +90,7 @@ pick(obj, xy::VecTypes{2}) = pick(get_scene(obj), xy) function pick(scene::Scene, xy::VecTypes{2}) screen = getscreen(scene) screen === nothing && return (nothing, 0) - pick(scene, screen, Vec{2, Float64}(xy)) + return pick(scene, screen, Vec{2,Float64}(xy)) end """ @@ -108,7 +103,7 @@ pick(obj, xy::VecTypes{2}, range::Real) = pick(get_scene(obj), xy, range) function pick(scene::Scene, xy::VecTypes{2}, range::Real) screen = getscreen(scene) screen === nothing && return (nothing, 0) - pick_closest(scene, screen, xy, range) + return pick_closest(scene, screen, xy, range) end # The backend may handle this more optimally @@ -117,15 +112,16 @@ function pick_closest(scene::SceneLike, screen, xy, range) ((1.0 <= xy[1] <= w) && (1.0 <= xy[2] <= h)) || return (nothing, 0) x0, y0 = max.(1, floor.(Int, xy .- range)) x1, y1 = min.([w, h], floor.(Int, xy .+ range)) - dx = x1 - x0; dy = y1 - y0 + dx = x1 - x0 + dy = y1 - y0 picks = pick(scene, screen, Rect2i(x0, y0, dx, dy)) min_dist = range^2 selected = (0, 0) - x, y = xy .+ 1 .- Vec2f(x0, y0) + x, y = xy .+ 1 .- Vec2f(x0, y0) for i in 1:dx, j in 1:dy - d = (x-i)^2 + (y-j)^2 + d = (x - i)^2 + (y - j)^2 if (d < min_dist) && (picks[i, j][1] != nothing) min_dist = d selected = (i, j) @@ -143,27 +139,28 @@ sorted by distance to `xy`. """ function pick_sorted(scene::Scene, xy, range) screen = getscreen(scene) - screen === nothing && return Tuple{AbstractPlot, Int}[] - pick_sorted(scene, screen, xy, range) + screen === nothing && return Tuple{AbstractPlot,Int}[] + return pick_sorted(scene, screen, xy, range) end function pick_sorted(scene::Scene, screen, xy, range) w, h = widths(events(scene).window_area[]) if !((1.0 <= xy[1] <= w) && (1.0 <= xy[2] <= h)) - return Tuple{AbstractPlot, Int}[] + return Tuple{AbstractPlot,Int}[] end x0, y0 = max.(1, floor.(Int, xy .- range)) x1, y1 = min.([w, h], floor.(Int, xy .+ range)) - dx = x1 - x0; dy = y1 - y0 + dx = x1 - x0 + dy = y1 - y0 picks = pick(scene, screen, Rect2i(x0, y0, dx, dy)) selected = filter(x -> x[1] !== nothing, unique(vec(picks))) distances = [range^2 for _ in selected] - x, y = xy .+ 1 .- Vec2f(x0, y0) + x, y = xy .+ 1 .- Vec2f(x0, y0) for i in 1:dx, j in 1:dy if picks[i, j][1] !== nothing - d = (x-i)^2 + (y-j)^2 + d = (x - i)^2 + (y - j)^2 i = findfirst(isequal(picks[i, j]), selected)::Int if distances[i] > d distances[i] = d @@ -185,7 +182,7 @@ screen boundaries. pick(x, rect::Rect2i) = pick(get_scene(x), rect) function pick(scene::Scene, rect::Rect2i) screen = getscreen(scene) - screen === nothing && return Tuple{AbstractPlot, Int}[] + screen === nothing && return Tuple{AbstractPlot,Int}[] return pick(scene, screen, rect) end @@ -195,9 +192,7 @@ end Normalizes mouse position `pos` relative to the screen rectangle. """ screen_relative(x, mpos) = screen_relative(get_scene(x), mpos) -function screen_relative(scene::Scene, mpos) - return Point2f(mpos) .- Point2f(minimum(pixelarea(scene)[])) -end +screen_relative(scene::Scene, mpos) = Point2f(mpos) .- Point2f(minimum(pixelarea(scene)[])) """ mouseposition(scene = hovered_scene()) @@ -208,14 +203,10 @@ given `scene`. By default uses the `scene` that the mouse is currently hovering over. """ mouseposition(x) = mouseposition(get_scene(x)) -function mouseposition(scene::Scene = hovered_scene()) - return to_world(scene, mouseposition_px(scene)) -end +mouseposition(scene::Scene=hovered_scene()) = to_world(scene, mouseposition_px(scene)) mouseposition_px(x) = mouseposition_px(get_scene(x)) -function mouseposition_px(scene::Scene = hovered_scene()) - return screen_relative(scene, events(scene).mouseposition[]) -end +mouseposition_px(scene::Scene=hovered_scene()) = screen_relative(scene, events(scene).mouseposition[]) """ hovered_scene() @@ -226,7 +217,6 @@ Properly identifies the scene for a plot with multiple sub-plots. """ hovered_scene() = error("hoevered_scene is not implemented yet.") - """ select_rectangle(scene; kwargs...) -> rect @@ -242,7 +232,7 @@ rectangle has area > 0. The `kwargs...` are propagated into `lines!` which plots the selected rectangle. """ -function select_rectangle(scene; blocking = false, priority = 2, strokewidth = 3.0, kwargs...) +function select_rectangle(scene; blocking=false, priority=2, strokewidth=3.0, kwargs...) key = Mouse.left waspressed = Observable(false) rect = Observable(Rectf(0, 0, 1, 1)) # plotted rectangle @@ -250,7 +240,13 @@ function select_rectangle(scene; blocking = false, priority = 2, strokewidth = 3 # Create an initially hidden rectangle plotted_rect = poly!( - scene, rect, visible = false, color = RGBAf(0, 0, 0, 0), strokecolor = RGBAf(0.1, 0.1, 0.8, 0.5), strokewidth = strokewidth, kwargs..., + scene, + rect, + visible=false, + color=RGBAf(0, 0, 0, 0), + strokecolor=RGBAf(0.1, 0.1, 0.8, 0.5), + strokewidth=strokewidth, + kwargs..., ) on(events(scene).mousebutton, priority=priority) do event @@ -306,16 +302,13 @@ and only if the selected line has non-zero length. The `kwargs...` are propagated into `lines!` which plots the selected line. """ -function select_line(scene; blocking = false, priority = 2, kwargs...) +function select_line(scene; blocking=false, priority=2, kwargs...) key = Mouse.left waspressed = Observable(false) - line = Observable([Point2f(0,0), Point2f(1,1)]) - line_ret = Observable([Point2f(0,0), Point2f(1,1)]) + line = Observable([Point2f(0, 0), Point2f(1, 1)]) + line_ret = Observable([Point2f(0, 0), Point2f(1, 1)]) # Create an initially hidden arrow - plotted_line = lines!( - scene, line; visible = false, color = RGBAf(0.1, 0.1, 0.8, 0.5), - linewidth = 4, kwargs..., - ) + plotted_line = lines!(scene, line; visible=false, color=RGBAf(0.1, 0.1, 0.8, 0.5), linewidth=4, kwargs...) on(events(scene).mousebutton, priority=priority) do event if event.button == key && is_mouseinside(scene) @@ -367,16 +360,21 @@ The value of the returned point is updated **only** when the user un-clicks. The `kwargs...` are propagated into `scatter!` which plots the selected point. """ -function select_point(scene; blocking = false, priority=2, kwargs...) +function select_point(scene; blocking=false, priority=2, kwargs...) key = Mouse.left pmarker = Circle(Point2f(0, 0), Float32(1)) waspressed = Observable(false) - point = Observable([Point2f(0,0)]) - point_ret = Observable(Point2f(0,0)) + point = Observable([Point2f(0, 0)]) + point_ret = Observable(Point2f(0, 0)) # Create an initially hidden arrow plotted_point = scatter!( - scene, point; visible = false, marker = pmarker, markersize = 20px, - color = RGBAf(0.1, 0.1, 0.8, 0.5), kwargs..., + scene, + point; + visible=false, + marker=pmarker, + markersize=20px, + color=RGBAf(0.1, 0.1, 0.8, 0.5), + kwargs..., ) on(events(scene).mousebutton, priority=priority) do event diff --git a/src/interaction/iodevices.jl b/src/interaction/iodevices.jl index 416f8580f69..70a2ce50adb 100644 --- a/src/interaction/iodevices.jl +++ b/src/interaction/iodevices.jl @@ -4,151 +4,152 @@ represent keyboard buttons. """ module Keyboard - using ..Makie: INSTANCES # import the docstring extensions - """ - Keyboard.Button - - Enumerates all keyboard buttons. - See the implementation for details. - """ - @enum(Button, - unknown = -1, - # printable keys, - space = 32, - apostrophe = 39, # ', - comma = 44, # ,, - minus = 45, # -, - period = 46, # ., - slash = 47, # /, - _0 = 48, - _1 = 49, - _2 = 50, - _3 = 51, - _4 = 52, - _5 = 53, - _6 = 54, - _7 = 55, - _8 = 56, - _9 = 57, - semicolon = 59, # ;, - equal = 61, # =, - a = 65, - b = 66, - c = 67, - d = 68, - e = 69, - f = 70, - g = 71, - h = 72, - i = 73, - j = 74, - k = 75, - l = 76, - m = 77, - n = 78, - o = 79, - p = 80, - q = 81, - r = 82, - s = 83, - t = 84, - u = 85, - v = 86, - w = 87, - x = 88, - y = 89, - z = 90, - left_bracket = 91, # [, - backslash = 92, # , - right_bracket = 93, # ], - grave_accent = 96, # `, - world_1 = 161, # non-us #1, - world_2 = 162, # non-us #2, - # function keys, - escape = 256, - enter = 257, - tab = 258, - backspace = 259, - insert = 260, - delete = 261, - right = 262, - left = 263, - down = 264, - up = 265, - page_up = 266, - page_down = 267, - home = 268, - _end = 269, - caps_lock = 280, - scroll_lock = 281, - num_lock = 282, - print_screen = 283, - pause = 284, - f1 = 290, - f2 = 291, - f3 = 292, - f4 = 293, - f5 = 294, - f6 = 295, - f7 = 296, - f8 = 297, - f9 = 298, - f10 = 299, - f11 = 300, - f12 = 301, - f13 = 302, - f14 = 303, - f15 = 304, - f16 = 305, - f17 = 306, - f18 = 307, - f19 = 308, - f20 = 309, - f21 = 310, - f22 = 311, - f23 = 312, - f24 = 313, - f25 = 314, - kp_0 = 320, - kp_1 = 321, - kp_2 = 322, - kp_3 = 323, - kp_4 = 324, - kp_5 = 325, - kp_6 = 326, - kp_7 = 327, - kp_8 = 328, - kp_9 = 329, - kp_decimal = 330, - kp_divide = 331, - kp_multiply = 332, - kp_subtract = 333, - kp_add = 334, - kp_enter = 335, - kp_equal = 336, - left_shift = 340, - left_control = 341, - left_alt = 342, - left_super = 343, - right_shift = 344, - right_control = 345, - right_alt = 346, - right_super = 347, - menu = 348, - ) - - """ - Keyboard.Action - - Enumerates all key states/actions in accordance with the GLFW spec. - - $(INSTANCES) - """ - @enum Action begin - release = 0 - press = 1 - repeat = 2 - end +using ..Makie: INSTANCES # import the docstring extensions +""" + Keyboard.Button + +Enumerates all keyboard buttons. +See the implementation for details. +""" +@enum( + Button, + unknown = -1, + # printable keys, + space = 32, + apostrophe = 39, # ', + comma = 44, # ,, + minus = 45, # -, + period = 46, # ., + slash = 47, # /, + _0 = 48, + _1 = 49, + _2 = 50, + _3 = 51, + _4 = 52, + _5 = 53, + _6 = 54, + _7 = 55, + _8 = 56, + _9 = 57, + semicolon = 59, # ;, + equal = 61, # =, + a = 65, + b = 66, + c = 67, + d = 68, + e = 69, + f = 70, + g = 71, + h = 72, + i = 73, + j = 74, + k = 75, + l = 76, + m = 77, + n = 78, + o = 79, + p = 80, + q = 81, + r = 82, + s = 83, + t = 84, + u = 85, + v = 86, + w = 87, + x = 88, + y = 89, + z = 90, + left_bracket = 91, # [, + backslash = 92, # , + right_bracket = 93, # ], + grave_accent = 96, # `, + world_1 = 161, # non-us #1, + world_2 = 162, # non-us #2, + # function keys, + escape = 256, + enter = 257, + tab = 258, + backspace = 259, + insert = 260, + delete = 261, + right = 262, + left = 263, + down = 264, + up = 265, + page_up = 266, + page_down = 267, + home = 268, + _end = 269, + caps_lock = 280, + scroll_lock = 281, + num_lock = 282, + print_screen = 283, + pause = 284, + f1 = 290, + f2 = 291, + f3 = 292, + f4 = 293, + f5 = 294, + f6 = 295, + f7 = 296, + f8 = 297, + f9 = 298, + f10 = 299, + f11 = 300, + f12 = 301, + f13 = 302, + f14 = 303, + f15 = 304, + f16 = 305, + f17 = 306, + f18 = 307, + f19 = 308, + f20 = 309, + f21 = 310, + f22 = 311, + f23 = 312, + f24 = 313, + f25 = 314, + kp_0 = 320, + kp_1 = 321, + kp_2 = 322, + kp_3 = 323, + kp_4 = 324, + kp_5 = 325, + kp_6 = 326, + kp_7 = 327, + kp_8 = 328, + kp_9 = 329, + kp_decimal = 330, + kp_divide = 331, + kp_multiply = 332, + kp_subtract = 333, + kp_add = 334, + kp_enter = 335, + kp_equal = 336, + left_shift = 340, + left_control = 341, + left_alt = 342, + left_super = 343, + right_shift = 344, + right_control = 345, + right_alt = 346, + right_super = 347, + menu = 348, +) + +""" + Keyboard.Action + +Enumerates all key states/actions in accordance with the GLFW spec. + +$(INSTANCES) +""" +@enum Action begin + release = 0 + press = 1 + repeat = 2 +end end """ @@ -156,54 +157,52 @@ Backend independent enums and fields which represent mouse actions. """ module Mouse - using ..Makie: INSTANCES # import the docstring extensions - - """ - Mouse.Button - - Enumerates all mouse buttons in accordance with the GLFW spec. - - $(INSTANCES) - """ - @enum Button begin - left = 0 - middle = 2 - right = 1 # Conform to GLFW - none = -1 # for convenience - end - - """ - Mouse.Action - - Enumerates all mouse states/actions in accordance with the GLFW spec. - - $(INSTANCES) - """ - @enum Action begin - press = 1 - release = 0 - end - - # deprecated, remove eventually - """ - Mouse.DragEnum - - Enumerates the drag states of the mouse. - - $(INSTANCES) - """ - @enum DragEnum begin - down - up - pressed - notpressed - end +using ..Makie: INSTANCES # import the docstring extensions + +""" + Mouse.Button + +Enumerates all mouse buttons in accordance with the GLFW spec. + +$(INSTANCES) +""" +@enum Button begin + left = 0 + middle = 2 + right = 1 # Conform to GLFW + none = -1 # for convenience end -# Void for no button needs to be pressed, -const ButtonTypes = Union{Nothing, Mouse.Button, Keyboard.Button} +""" + Mouse.Action +Enumerates all mouse states/actions in accordance with the GLFW spec. + +$(INSTANCES) +""" +@enum Action begin + press = 1 + release = 0 +end + +# deprecated, remove eventually +""" + Mouse.DragEnum +Enumerates the drag states of the mouse. + +$(INSTANCES) +""" +@enum DragEnum begin + down + up + pressed + notpressed +end +end + +# Void for no button needs to be pressed, +const ButtonTypes = Union{Nothing,Mouse.Button,Keyboard.Button} struct KeyEvent key::Keyboard.Button diff --git a/src/interaction/liftmacro.jl b/src/interaction/liftmacro.jl index eaf867127d2..ec45044e016 100644 --- a/src/interaction/liftmacro.jl +++ b/src/interaction/liftmacro.jl @@ -17,9 +17,7 @@ end find_observable_expressions(x) = Set() is_interpolated_observable(x) = false -function is_interpolated_observable(e::Expr) - e.head == Symbol(:$) && length(e.args) == 1 -end +is_interpolated_observable(e::Expr) = e.head == Symbol(:$) && length(e.args) == 1 """ Replaces every subexpression that looks like a observable expression with a substitute symbol stored in `exprdict`. @@ -70,11 +68,12 @@ nt = (x = Observable(1), y = Observable(2)) ``` """ macro lift(exp) - observable_expr_set = find_observable_expressions(exp) if length(observable_expr_set) == 0 - error("Did not find any interpolated observables. Use '\$(observable)' to interpolate it into the macro.") + error( + "Did not find any interpolated observables. Use '\$(observable)' to interpolate it into the macro.", + ) end # store expressions with their substitute symbols, gensym them manually to be @@ -99,7 +98,7 @@ macro lift(exp) Symbol(:call), Symbol(:lift), esc(function_expression), - esc.(observable_expressions_without_dollar)... + esc.(observable_expressions_without_dollar)..., ) return lift_expression diff --git a/src/interaction/observables.jl b/src/interaction/observables.jl index fa58ddc1793..efb27b3bf42 100644 --- a/src/interaction/observables.jl +++ b/src/interaction/observables.jl @@ -33,11 +33,9 @@ test(Observable(1), Observable(2)) > """ -function map_once( - f, input::Observable, inputrest::Observable... - ) +function map_once(f, input::Observable, inputrest::Observable...) for arg in (input, inputrest...) safe_off(arg, f) end - lift(f, input, inputrest...) + return lift(f, input, inputrest...) end diff --git a/src/interfaces.jl b/src/interfaces.jl index da63febdc95..34258128296 100644 --- a/src/interfaces.jl +++ b/src/interfaces.jl @@ -1,31 +1,31 @@ function default_theme(scene) - Attributes( + return Attributes( # color = theme(scene, :color), - linewidth = 1, - transformation = automatic, - model = automatic, - visible = true, - transparency = false, - overdraw = false, - diffuse = Vec3f(0.4), - specular = Vec3f(0.2), - shininess = 32f0, - nan_color = RGBAf(0,0,0,0), - ssao = false, - inspectable = theme(scene, :inspectable), - depth_shift = 0f0, - space = :data + linewidth=1, + transformation=automatic, + model=automatic, + visible=true, + transparency=false, + overdraw=false, + diffuse=Vec3f(0.4), + specular=Vec3f(0.2), + shininess=32.0f0, + nan_color=RGBAf(0, 0, 0, 0), + ssao=false, + inspectable=theme(scene, :inspectable), + depth_shift=0.0f0, + space=:data, ) end - - -function color_and_colormap!(plot, intensity = plot[:color]) - if isa(intensity[], AbstractArray{<: Number}) - haskey(plot, :colormap) || error("Plot $(typeof(plot)) needs to have a colormap to allow the attribute color to be an array of numbers") +function color_and_colormap!(plot, intensity=plot[:color]) + if isa(intensity[], AbstractArray{<:Number}) + haskey(plot, :colormap) || error( + "Plot $(typeof(plot)) needs to have a colormap to allow the attribute color to be an array of numbers", + ) replace_automatic!(plot, :colorrange) do - lift(distinct_extrema_nan, intensity) + return lift(distinct_extrema_nan, intensity) end replace_automatic!(plot, :highclip) do lift(plot.colormap) do cmap @@ -46,47 +46,44 @@ function color_and_colormap!(plot, intensity = plot[:color]) end end -function calculated_attributes!(T::Type{<: Mesh}, plot) +function calculated_attributes!(T::Type{<:Mesh}, plot) mesha = lift(GeometryBasics.attributes, plot.mesh) - color = haskey(mesha[], :color) ? lift(x-> x[:color], mesha) : plot.color + color = haskey(mesha[], :color) ? lift(x -> x[:color], mesha) : plot.color need_cmap = color_and_colormap!(plot, color) need_cmap || delete!(plot, :colormap) return end -function calculated_attributes!(::Type{<: Union{Heatmap, Image}}, plot) +function calculated_attributes!(::Type{<:Union{Heatmap,Image}}, plot) plot[:color] = plot[3] - color_and_colormap!(plot) + return color_and_colormap!(plot) end -function calculated_attributes!(::Type{<: Surface}, plot) +function calculated_attributes!(::Type{<:Surface}, plot) colors = plot[3] if haskey(plot, :color) color = plot[:color][] - if isa(color, AbstractMatrix{<: Number}) && !(color === to_value(colors)) + if isa(color, AbstractMatrix{<:Number}) && !(color === to_value(colors)) colors = plot[:color] end end - color_and_colormap!(plot, colors) -end - -function calculated_attributes!(::Type{<: MeshScatter}, plot) - color_and_colormap!(plot) + return color_and_colormap!(plot, colors) end +calculated_attributes!(::Type{<:MeshScatter}, plot) = color_and_colormap!(plot) -function calculated_attributes!(::Type{<: Scatter}, plot) +function calculated_attributes!(::Type{<:Scatter}, plot) # calculate base case color_and_colormap!(plot) replace_automatic!(plot, :marker_offset) do # default to middle - lift(x-> to_2d_scale(map(x-> x .* -0.5f0, x)), plot[:markersize]) + return lift(x -> to_2d_scale(map(x -> x .* -0.5f0, x)), plot[:markersize]) end replace_automatic!(plot, :markerspace) do lift(plot.markersize) do ms - if ms isa Pixel || (ms isa AbstractVector && all(x-> ms isa Pixel, ms)) + if ms isa Pixel || (ms isa AbstractVector && all(x -> ms isa Pixel, ms)) return :pixel else return :data @@ -95,32 +92,32 @@ function calculated_attributes!(::Type{<: Scatter}, plot) end end -function calculated_attributes!(::Type{T}, plot) where {T<:Union{Lines, LineSegments}} +function calculated_attributes!(::Type{T}, plot) where {T<:Union{Lines,LineSegments}} color_and_colormap!(plot) pos = plot[1][] # extend one color/linewidth per linesegment to be one (the same) color/linewidth per vertex if T <: LineSegments for attr in [:color, :linewidth] # taken from @edljk in PR #77 - if haskey(plot, attr) && isa(plot[attr][], AbstractVector) && (length(pos) ÷ 2) == length(plot[attr][]) + if haskey(plot, attr) && + isa(plot[attr][], AbstractVector) && + (length(pos) ÷ 2) == length(plot[attr][]) plot[attr] = lift(plot[attr]) do cols - map(i -> cols[(i + 1) ÷ 2], 1:(length(cols) * 2)) + return map(i -> cols[(i + 1) ÷ 2], 1:(length(cols) * 2)) end end end end end -const atomic_function_symbols = ( - :text, :meshscatter, :scatter, :mesh, :linesegments, - :lines, :surface, :volume, :heatmap, :image -) +const atomic_function_symbols = + (:text, :meshscatter, :scatter, :mesh, :linesegments, :lines, :surface, :volume, :heatmap, :image) const atomic_functions = getfield.(Ref(Makie), atomic_function_symbols) -const Atomic{Arg} = Union{map(x-> Combined{x, Arg}, atomic_functions)...} +const Atomic{Arg} = Union{map(x -> Combined{x,Arg}, atomic_functions)...} -function (PT::Type{<: Combined})(parent, transformation, attributes, input_args, converted) - PT(parent, transformation, attributes, input_args, converted, AbstractPlot[]) +function (PT::Type{<:Combined})(parent, transformation, attributes, input_args, converted) + return PT(parent, transformation, attributes, input_args, converted, AbstractPlot[]) end """ @@ -151,14 +148,12 @@ used_attributes(PlotType, args...) = () apply for return type (args...,) """ -function apply_convert!(P, attributes::Attributes, x::Tuple) - return (plottype(P, x...), x) -end +apply_convert!(P, attributes::Attributes, x::Tuple) = (plottype(P, x...), x) """ apply for return type PlotSpec """ -function apply_convert!(P, attributes::Attributes, x::PlotSpec{S}) where S +function apply_convert!(P, attributes::Attributes, x::PlotSpec{S}) where {S} args, kwargs = x.args, x.kwargs # Note that kw_args in the plot spec that are not part of the target plot type # will end in the "global plot" kw_args (rest) @@ -168,7 +163,7 @@ function apply_convert!(P, attributes::Attributes, x::PlotSpec{S}) where S return (plottype(S, P), args) end -function seperate_tuple(args::Observable{<: NTuple{N, Any}}) where N +function seperate_tuple(args::Observable{<:NTuple{N,Any}}) where {N} ntuple(N) do i lift(args) do x if i <= length(x) @@ -180,10 +175,10 @@ function seperate_tuple(args::Observable{<: NTuple{N, Any}}) where N end end -function (PlotType::Type{<: AbstractPlot{Typ}})(scene::SceneLike, attributes::Attributes, args) where Typ +function (PlotType::Type{<:AbstractPlot{Typ}})(scene::SceneLike, attributes::Attributes, args) where {Typ} input = convert.(Observable, args) argnodes = lift(input...) do args... - convert_arguments(PlotType, args...) + return convert_arguments(PlotType, args...) end return PlotType(scene, attributes, input, argnodes) end @@ -201,7 +196,12 @@ function plot(scene::Scene, plot::AbstractPlot) return plot end -function (PlotType::Type{<: AbstractPlot{Typ}})(scene::SceneLike, attributes::Attributes, input, args) where Typ +function (PlotType::Type{<:AbstractPlot{Typ}})( + scene::SceneLike, + attributes::Attributes, + input, + args, +) where {Typ} # The argument type of the final plot object is the assumened to stay constant after # argument conversion. This might not always hold, but it simplifies # things quite a bit @@ -209,11 +209,9 @@ function (PlotType::Type{<: AbstractPlot{Typ}})(scene::SceneLike, attributes::At # construct the fully qualified plot type, from the possible incomplete (abstract) # PlotType - FinalType = Combined{Typ, ArgTyp} - plot_attributes = merged_get!( - ()-> default_theme(scene, FinalType), - plotsym(FinalType), scene, attributes - ) + FinalType = Combined{Typ,ArgTyp} + plot_attributes = + merged_get!(() -> default_theme(scene, FinalType), plotsym(FinalType), scene, attributes) # Transformation is a field of the plot type, but can be given as an attribute trans = get(plot_attributes, :transformation, automatic) @@ -228,27 +226,27 @@ function (PlotType::Type{<: AbstractPlot{Typ}})(scene::SceneLike, attributes::At t end replace_automatic!(plot_attributes, :model) do - transformation.model + return transformation.model end # create the plot, with the full attributes, the input signals, and the final signals. plot_obj = FinalType(scene, transformation, plot_attributes, input, seperate_tuple(args)) calculated_attributes!(plot_obj) - plot_obj + return plot_obj end ## generic definitions # If the Combined has no plot func, calculate them -plottype(::Type{<: Combined{Any}}, argvalues...) = plottype(argvalues...) +plottype(::Type{<:Combined{Any}}, argvalues...) = plottype(argvalues...) plottype(::Type{Any}, argvalues...) = plottype(argvalues...) # If it has something more concrete than Any, use it directly -plottype(P::Type{<: Combined{T}}, argvalues...) where T = P +plottype(P::Type{<:Combined{T}}, argvalues...) where {T} = P ## specialized definitions for types plottype(::AbstractVector, ::AbstractVector, ::AbstractVector) = Scatter plottype(::AbstractVector, ::AbstractVector) = Scatter plottype(::AbstractVector) = Scatter -plottype(::AbstractMatrix{<: Real}) = Heatmap -plottype(::Array{<: AbstractFloat, 3}) = Volume +plottype(::AbstractMatrix{<:Real}) = Heatmap +plottype(::Array{<:AbstractFloat,3}) = Volume plottype(::AbstractString) = Text plottype(::LineString) = Lines @@ -271,12 +269,11 @@ function convert_arguments(P::PlotFunc, args...) end ``` """ -plottype(P1::Type{<: Combined{Any}}, P2::Type{<: Combined{T}}) where T = P2 -plottype(P1::Type{<: Combined{T}}, P2::Type{<: Combined}) where T = P1 +plottype(P1::Type{<:Combined{Any}}, P2::Type{<:Combined{T}}) where {T} = P2 +plottype(P1::Type{<:Combined{T}}, P2::Type{<:Combined}) where {T} = P1 # all the plotting functions that get a plot type -const PlotFunc = Union{Type{Any}, Type{<: AbstractPlot}} - +const PlotFunc = Union{Type{Any},Type{<:AbstractPlot}} ###################################################################### # In this section, the plotting functions have P as the first argument @@ -284,14 +281,14 @@ const PlotFunc = Union{Type{Any}, Type{<: AbstractPlot}} function plot!(P::PlotFunc, scene::SceneLike, args...; kw_attributes...) attributes = Attributes(kw_attributes) - plot!(scene, P, attributes, args...) + return plot!(scene, P, attributes, args...) end # with positional attributes function plot!(P::PlotFunc, scene::SceneLike, attrs::Attributes, args...; kw_attributes...) attributes = merge!(Attributes(kw_attributes), attrs) - plot!(scene, P, attributes, args...) + return plot!(scene, P, attributes, args...) end ###################################################################### @@ -300,19 +297,25 @@ end """ Main plotting signatures that plot/plot! route to if no Plot Type is given """ -function plot!(scene::Union{Combined, SceneLike}, P::PlotFunc, attributes::Attributes, args...; kw_attributes...) +function plot!( + scene::Union{Combined,SceneLike}, + P::PlotFunc, + attributes::Attributes, + args...; + kw_attributes..., +) attributes = merge!(Attributes(kw_attributes), attributes) argvalues = to_value.(args) PreType = plottype(P, argvalues...) # plottype will lose the argument types, so we just extract the plot func # type and recreate the type with the argument type - PreType = Combined{plotfunc(PreType), typeof(argvalues)} + PreType = Combined{plotfunc(PreType),typeof(argvalues)} convert_keys = intersect(used_attributes(PreType, argvalues...), keys(attributes)) kw_signal = if isempty(convert_keys) # lift(f) isn't supported so we need to catch the empty case Observable(()) else # Remove used attributes from `attributes` and collect them in a `Tuple` to pass them more easily - lift((args...)-> Pair.(convert_keys, args), pop!.(attributes, convert_keys)...) + lift((args...) -> Pair.(convert_keys, args), pop!.(attributes, convert_keys)...) end # call convert_arguments for a first time to get things started converted = convert_arguments(PreType, argvalues...; kw_signal[]...) @@ -321,32 +324,29 @@ function plot!(scene::Union{Combined, SceneLike}, P::PlotFunc, attributes::Attri FinalType, argsconverted = apply_convert!(PreType, attributes, converted) converted_node = Observable(argsconverted) - input_nodes = convert.(Observable, args) + input_nodes = convert.(Observable, args) onany(kw_signal, input_nodes...) do kwargs, args... # do the argument conversion inside a lift result = convert_arguments(FinalType, args...; kwargs...) finaltype, argsconverted_ = apply_convert!(FinalType, attributes, result) # avoid a Core.Box (https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured) if finaltype != FinalType error("Plot type changed from $FinalType to $finaltype after conversion. - Changing the plot type based on values in convert_arguments is not allowed" - ) + Changing the plot type based on values in convert_arguments is not allowed") end - converted_node[] = argsconverted_ + return converted_node[] = argsconverted_ end - plot!(scene, FinalType, attributes, input_nodes, converted_node) + return plot!(scene, FinalType, attributes, input_nodes, converted_node) end plot!(p::Combined) = _plot!(p) -_plot!(p::Atomic{T}) where T = p +_plot!(p::Atomic{T}) where {T} = p -function _plot!(p::Combined{fn, T}) where {fn, T} - throw(PlotMethodError(fn, T)) -end +_plot!(p::Combined{fn,T}) where {fn,T} = throw(PlotMethodError(fn, T)) struct PlotMethodError <: Exception - fn - T + fn::Any + T::Any end function Base.showerror(io::IO, err::PlotMethodError) @@ -363,17 +363,16 @@ function Base.showerror(io::IO, err::PlotMethodError) printstyled(io, "plot!(::$(Combined{fn,S} where {S<:T}))"; color=:cyan) print(io, "\nAvailable methods are:\n") for m in methods(plot!) - if m.sig <: Tuple{typeof(plot!), Combined{fn}} + if m.sig <: Tuple{typeof(plot!),Combined{fn}} println(io, " ", m) end end end -function show_attributes(attributes) +show_attributes(attributes) = for (k, v) in attributes println(" ", k, ": ", v[] == nothing ? "nothing" : v[]) end -end """ extract_scene_attributes!(attributes) @@ -397,7 +396,7 @@ function extract_scene_attributes!(attributes) :limits, :padding, :raw, - :SSAO + :SSAO, ) result = Attributes() for k in scene_attributes @@ -406,11 +405,21 @@ function extract_scene_attributes!(attributes) return result end -function plot!(scene::SceneLike, P::PlotFunc, attributes::Attributes, input::NTuple{N, Observable}, args::Observable) where {N} +function plot!( + scene::SceneLike, + P::PlotFunc, + attributes::Attributes, + input::NTuple{N,Observable}, + args::Observable, +) where {N} # create "empty" plot type - empty meaning containing no plots, just attributes + arguments scene_attributes = extract_scene_attributes!(attributes) if haskey(attributes, :textsize) - throw(ArgumentError("The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.")) + throw( + ArgumentError( + "The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.", + ), + ) end plot_object = P(scene, attributes, input, args) # transfer the merged attributes from theme and user defined to the scene @@ -423,12 +432,18 @@ function plot!(scene::SceneLike, P::PlotFunc, attributes::Attributes, input::NTu return plot_object end -function plot!(scene::Combined, P::PlotFunc, attributes::Attributes, input::NTuple{N,Observable}, args::Observable) where {N} +function plot!( + scene::Combined, + P::PlotFunc, + attributes::Attributes, + input::NTuple{N,Observable}, + args::Observable, +) where {N} # create "empty" plot type - empty meaning containing no plots, just attributes + arguments plot_object = P(scene, attributes, input, args) # call user defined recipe overload to fill the plot type plot!(plot_object) push!(scene.plots, plot_object) - plot_object + return plot_object end diff --git a/src/jl_rasterizer/bmp.jl b/src/jl_rasterizer/bmp.jl index bf35407b4d3..a7317eaadf5 100644 --- a/src/jl_rasterizer/bmp.jl +++ b/src/jl_rasterizer/bmp.jl @@ -6,7 +6,7 @@ function writebmp(io, img) # be a multiple of 4 bytes. extrabytes = 4 - ((w * 3) % 4) (extrabytes == 4) && (extrabytes = 0) - paddedsize = ((w * 3) + extrabytes) * h; + paddedsize = ((w * 3) + extrabytes) * h # file header write(io, b"BM") @@ -34,7 +34,7 @@ function writebmp(io, img) write(io, reinterpret(UInt8, green(rgb))) write(io, reinterpret(UInt8, red(rgb))) end - for i = 1:extrabytes + for i in 1:extrabytes write(io, UInt8(0)) end end diff --git a/src/jl_rasterizer/main.jl b/src/jl_rasterizer/main.jl index 471d2a98bde..8064359dd6f 100644 --- a/src/jl_rasterizer/main.jl +++ b/src/jl_rasterizer/main.jl @@ -3,49 +3,46 @@ using GeometryBasics, Interpolations using ImageShow using Makie: orthographicprojection -@inline function edge_function(a, b, c) - (c[1] - a[1]) * (b[2] - a[2]) - (c[2] - a[2]) * (b[1] - a[1]) -end +@inline edge_function(a, b, c) = (c[1] - a[1]) * (b[2] - a[2]) - (c[2] - a[2]) * (b[1] - a[1]) -@inline function src_alpha(c::T) where T <: Colorant +@inline function src_alpha(c::T) where {T<:Colorant} a = alpha(c) a == 0.0 && return zero(T) - c ./ a + return c ./ a end -one_minus_alpha(c::T) where {T <: Colorant} = one(T) .- src_alpha(c) +one_minus_alpha(c::T) where {T<:Colorant} = one(T) .- src_alpha(c) blend(source, dest, src_func, dest_func) = clamp01(src_func(source) .+ dest_func(dest)) ColorTypes.alpha(x::StaticVector) = x[4] -function standard_transparency(source, dest::T) where T - (alpha(source) .* source) .+ ((one(eltype(T)) - alpha(source)) .* dest) +function standard_transparency(source, dest::T) where {T} + return (alpha(source) .* source) .+ ((one(eltype(T)) - alpha(source)) .* dest) end -mutable struct FixedGeomView{GeomOut, VT} +mutable struct FixedGeomView{GeomOut,VT} buffer::Vector{GeomOut} view::VT idx::Int end -struct TriangleStripView{T} <: AbstractVector{NTuple{3, T}} +struct TriangleStripView{T} <: AbstractVector{NTuple{3,T}} parent::AbstractVector{T} end Base.length(x::TriangleStripView) = 2 Base.size(x::TriangleStripView) = (2,) -function Base.getindex(x::TriangleStripView, i) +Base.getindex(x::TriangleStripView, i) = if i === 1 - return ntuple(i-> x.parent[i], 3) + return ntuple(i -> x.parent[i], 3) elseif i === 2 - return map(i-> x.parent[i], (3, 2, 4)) + return map(i -> x.parent[i], (3, 2, 4)) else error("Out of bounds") end -end function FixedGeomView(T, max_primitives, primitive_in, primitive_out) - buffer = Vector{Tuple{Point4f, T}}(undef, max_primitives) + buffer = Vector{Tuple{Point4f,T}}(undef, max_primitives) # TODO implement primitive_in and out correctly # this is for triangle_strip and 4 max_primitives if max_primitives != 4 || primitive_out != :triangle_strip @@ -59,9 +56,7 @@ function FixedGeomView(T, max_primitives, primitive_in, primitive_out) return FixedGeomView(buffer, geometry_view, 1) end -function reset!(A::FixedGeomView) - A.idx = 1 -end +reset!(A::FixedGeomView) = A.idx = 1 function Base.push!(A::FixedGeomView, element) if A.idx > length(A.buffer) @@ -72,7 +67,7 @@ function Base.push!(A::FixedGeomView, element) return end -struct JLRasterizer{Vertex, Args, FragN, VS, FS, GS, GV, EF} +struct JLRasterizer{Vertex,Args,FragN,VS,FS,GS,GV,EF} vertexshader::VS fragmentshader::FS @@ -81,19 +76,19 @@ struct JLRasterizer{Vertex, Args, FragN, VS, FS, GS, GV, EF} emit::EF end -function JLRasterizer{Vertex, Args, FragN}( - vertexshader::VS, - fragmentshader::FS, - geometryshader::GS, - geometry_view::GV, - emit::EF - ) where {Vertex, Args, FragN, VS, FS, GS, GV, EF} - JLRasterizer{Vertex, Args, FragN, VS, FS, GS, GV, EF}( +function JLRasterizer{Vertex,Args,FragN}( + vertexshader::VS, + fragmentshader::FS, + geometryshader::GS, + geometry_view::GV, + emit::EF, +) where {Vertex,Args,FragN,VS,FS,GS,GV,EF} + return JLRasterizer{Vertex,Args,FragN,VS,FS,GS,GV,EF}( vertexshader, fragmentshader, geometryshader, geometry_view, - emit + emit, ) end @@ -102,28 +97,26 @@ function geometry_return_type(vertex_array, vertexshader, geometryshader, unifor emit_t(position, ::T) where {T} = (typ = T) face1 = first(vertex_array) vertex_stage = map(reverse(face1)) do f - vertexshader(f, uniforms...) + return vertexshader(f, uniforms...) end geometryshader(emit_t, vertex_stage, uniforms...) # figure out typ - typ + return typ end -arglength(::Type{T}) where {T <: Tuple} = length(T.parameters) -arglength(::Type{T}) where {T <: AbstractArray} = 1 +arglength(::Type{T}) where {T<:Tuple} = length(T.parameters) +arglength(::Type{T}) where {T<:AbstractArray} = 1 arglength(::Type{T}) where {T} = nfields(T) - function rasterizer( - vertexarray::AbstractArray, - uniforms::Tuple, - vertexshader::Function, - fragmentshader::Function; - geometryshader = nothing, - max_primitives = 4, - primitive_in = :points, - primitive_out = :triangle_strip, - ) - + vertexarray::AbstractArray, + uniforms::Tuple, + vertexshader::Function, + fragmentshader::Function; + geometryshader=nothing, + max_primitives=4, + primitive_in=:points, + primitive_out=:triangle_strip, +) emit, geometry_view = nothing, nothing fragment_in_ndim = if !isnothing(geometryshader) T = geometry_return_type(vertexarray, vertexshader, geometryshader, uniforms) @@ -132,7 +125,7 @@ function rasterizer( arglength(T) else # when we don't have a geometry shader, vertex shader will feed fragment shader - T = Base.Core.Inference.return_type(vertexshader, Tuple{eltype(vertexarray), map(typeof, uniforms)...}) + T = Base.Core.Inference.return_type(vertexshader, Tuple{eltype(vertexarray),map(typeof, uniforms)...}) if T <: Tuple # TODO error handling arglength(T.parameters[2]) @@ -141,32 +134,29 @@ function rasterizer( end end - raster = JLRasterizer{eltype(vertexarray), typeof(uniforms), fragment_in_ndim}( + raster = JLRasterizer{eltype(vertexarray),typeof(uniforms),fragment_in_ndim}( vertexshader, fragmentshader, geometryshader, geometry_view, - emit + emit, ) - raster, (vertexarray, uniforms) + return raster, (vertexarray, uniforms) end - Base.@pure Next(::Val{N}) where {N} = Val(N - 1) -function interpolate(bary, face::NTuple{N, T}, vn::Val{0}, aggregate) where {N, T} +interpolate(bary, face::NTuple{N,T}, vn::Val{0}, aggregate) where {N,T} = if T <: Tuple aggregate else T(aggregate...) end -end -function interpolate(bary, face, vn::Val{N}, aggregate = ()) where N +function interpolate(bary, face, vn::Val{N}, aggregate=()) where {N} @inbounds begin res = ( - bary[1] * getfield(face[1], N) .+ - bary[2] * getfield(face[2], N) .+ + bary[1] * getfield(face[1], N) .+ bary[2] * getfield(face[2], N) .+ bary[3] * getfield(face[3], N) ) end @@ -179,14 +169,16 @@ broadcastmax(a, b) = max.(a, b) function clip2pixel_space(position, resolution) clipspace = position ./ position[4] p = clipspace[Vec(1, 2)] - (((p .+ 1f0) / 2f0) .* (resolution .- 1f0)) .+ 1f0, clipspace[3] + return (((p .+ 1.0f0) / 2.0f0) .* (resolution .- 1.0f0)) .+ 1.0f0, clipspace[3] end - -function (r::JLRasterizer{Vert, Args, FragN})( - canvas, vertex_array::AbstractArray{Vert}, uniforms::Args - ) where {Vert, Args, FragN} - framebuffers = canvas.color; depthbuffer = canvas.depth +function (r::JLRasterizer{Vert,Args,FragN})( + canvas, + vertex_array::AbstractArray{Vert}, + uniforms::Args, +) where {Vert,Args,FragN} + framebuffers = canvas.color + depthbuffer = canvas.depth resolution = Vec2f(size(framebuffers[1])) # hoisting out functions... Seems to help inference a bit. Or not? vshader = r.vertexshader @@ -196,7 +188,7 @@ function (r::JLRasterizer{Vert, Args, FragN})( fragments_drawn = 0 for face in vertex_array vertex_stage = map(reverse(face)) do f - vshader(f, uniforms...) + return vshader(f, uniforms...) end geom_stage = if isnothing(gshader) @@ -210,26 +202,25 @@ function (r::JLRasterizer{Vert, Args, FragN})( for geom_face in geom_stage fdepth = map(geom_face) do vert fv = first(vert) - clip2pixel_space(fv, resolution) + return clip2pixel_space(fv, resolution) end f = map(first, fdepth) depths = map(last, fdepth) vertex_out = map(last, geom_face) # Bounding rectangle - mini = max.(reduce(broadcastmin, f), 1f0) + mini = max.(reduce(broadcastmin, f), 1.0f0) maxi = min.(reduce(broadcastmax, f), resolution) area = edge_function(f[1], f[2], f[3]) - for y = mini[2]:maxi[2] - for x = mini[1]:maxi[1] + for y in mini[2]:maxi[2] + for x in mini[1]:maxi[1] p = Vec(x, y) w = Vec( edge_function(f[2], f[3], p), edge_function(f[3], f[1], p), - edge_function(f[1], f[2], p) + edge_function(f[1], f[2], p), ) yi, xi = round(Int, y), round(Int, x) - if all(w-> w >= 0f0, w) && checkbounds(Bool, framebuffers[1], yi, xi) - + if all(w -> w >= 0.0f0, w) && checkbounds(Bool, framebuffers[1], yi, xi) bary = w / area depth = bary[1] * depths[1] + bary[2] * depths[2] + bary[3] * depths[3] @@ -237,13 +228,13 @@ function (r::JLRasterizer{Vert, Args, FragN})( depthbuffer[yi, xi] = depth fragment_in = interpolate(bary, vertex_out, FragNVal) fragment_out = fshader(fragment_in, uniforms...) - for i = eachindex(fragment_out) + for i in eachindex(fragment_out) src_color = framebuffers[i][yi, xi] dest_color = fragment_out[i] fragments_drawn += 1 framebuffers[i][yi, xi] = standard_transparency( src_color, - RGBA{Float32}(dest_color[1], dest_color[2], dest_color[3], dest_color[4]) + RGBA{Float32}(dest_color[1], dest_color[2], dest_color[3], dest_color[4]), ) end end @@ -264,18 +255,18 @@ smoothstep performs smooth Hermite interpolation between 0 and 1 when edge0 < x ``` Results are undefined if edge0 ≥ edge1. """ -function smoothstep(edge0, edge1, x::T) where T +function smoothstep(edge0, edge1, x::T) where {T} t = clamp.((x .- edge0) ./ (edge1 .- edge0), T(0), T(1)) return t * t * (T(3) - T(2) * t) end -function aastep(threshold1::T, value) where T - afwidth = norm(Vec2f(dFdx(value), dFdy(value))) * T(1.05); - smoothstep(threshold1 - afwidth, threshold1 + afwidth, value) +function aastep(threshold1::T, value) where {T} + afwidth = norm(Vec2f(dFdx(value), dFdy(value))) * T(1.05) + return smoothstep(threshold1 - afwidth, threshold1 + afwidth, value) end -function aastep(threshold1::T, threshold2::T, value::T) where T - afwidth = norm(Vec2f(dFdx(value), dFdy(value))) * T(1.05); +function aastep(threshold1::T, threshold2::T, value::T) where {T} + afwidth = norm(Vec2f(dFdx(value), dFdy(value))) * T(1.05) return ( smoothstep(threshold1 - afwidth, threshold1 + afwidth, value) - smoothstep(threshold2 - afwidth, threshold2 + afwidth, value) @@ -302,8 +293,8 @@ mutable struct Uniforms{F} distance_func::F end -struct VertexCS{N, T} - position::Vec{N, T} +struct VertexCS{N,T} + position::Vec{N,T} color::Vec4f scale::Vec2f end @@ -317,14 +308,9 @@ end function vert_particles(vertex, uniforms) p = vertex.position scale = vertex.scale - return Vertex2Geom( - Vec4f(0,0,1,1), - vertex.color, - Vec4f(p[1], p[2], scale[1], scale[2]) - ) + return Vertex2Geom(Vec4f(0, 0, 1, 1), vertex.color, Vec4f(p[1], p[2], scale[1], scale[2])) end - """ Emits a vertex with """ @@ -355,7 +341,7 @@ function geom_particles(emit!, vertex_out, uniforms) pos_scale = arg.rect pos = pos_scale[Vec(1, 2)] scale = pos_scale[Vec(3, 4)] - quad = Vec4f(0f0, 0f0, scale[1], scale[2]) + quad = Vec4f(0.0f0, 0.0f0, scale[1], scale[2]) uv = arg.uvrect emit_vertex(emit!, quad[Vec(1, 2)], uv[Vec(1, 4)], arg, pos, uniforms) emit_vertex(emit!, quad[Vec(1, 4)], uv[Vec(1, 2)], arg, pos, uniforms) @@ -364,69 +350,67 @@ function geom_particles(emit!, vertex_out, uniforms) return end - function sdf2color(dist, bg_color, color) - inside = aastep(0f0, dist) - mix(bg_color, color, inside) + inside = aastep(0.0f0, dist) + return mix(bg_color, color, inside) end function frag_particles(geom_out, uniforms, image) - uv = geom_out[1]; color = geom_out[2] + uv = geom_out[1] + color = geom_out[2] dist = -image[uv][1] - bg_color = Vec4f(0f0, 0f0, 0f0, 0f0) - (sdf2color(dist, bg_color, color), ) + bg_color = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) + return (sdf2color(dist, bg_color, color),) end function frag_particles(geom_out, uniforms) - uv = geom_out[1]; color = geom_out[2] + uv = geom_out[1] + color = geom_out[2] dist = uniforms.distance_func(uv) - bg_color = Vec4f(0f0, 0f0, 0f0, 0f0) + bg_color = Vec4f(0.0f0, 0.0f0, 0.0f0, 0.0f0) # col = Vec4f(norm(uv .- 0.5), 0, 0, 1) - (sdf2color(dist, bg_color, color), ) + return (sdf2color(dist, bg_color, color),) end resolution = (1024, 1024) -proj = Makie.orthographicprojection(Rect2(0, 0, resolution...), -10_000f0, 10_000f0) - -circle(uv::Vec{2, T}) where {T} = -T(norm(uv .- 0.5) - 0.5) +proj = Makie.orthographicprojection(Rect2(0, 0, resolution...), -10_000.0f0, 10_000.0f0) -uniforms = Uniforms( - proj, - Vec4f(1, 0, 0, 1), - Vec4f(1, 0, 1, 1), - circle -) +circle(uv::Vec{2,T}) where {T} = -T(norm(uv .- 0.5) - 0.5) +uniforms = Uniforms(proj, Vec4f(1, 0, 0, 1), Vec4f(1, 0, 1, 1), circle) N = 10 -middle = Vec2f(resolution) / 2f0 -radius = (min(resolution...) / 2f0) - 50 -vertices = [(VertexCS( - Vec2f((sin(2pi * (i / N)) , cos(2pi * (i / N))) .* radius) .+ middle, - Vec4f(1, i/N, 0, 1), - Vec2f(40, 40) -),) for i = 1:N] - +middle = Vec2f(resolution) / 2.0f0 +radius = (min(resolution...) / 2.0f0) - 50 +vertices = [ + ( + VertexCS( + Vec2f((sin(2pi * (i / N)), cos(2pi * (i / N))) .* radius) .+ middle, + Vec4f(1, i / N, 0, 1), + Vec2f(40, 40), + ), + ) for i in 1:N +] raster, rest = rasterizer( vertices, (uniforms,), vert_particles, frag_particles; - geometryshader = geom_particles, - max_primitives = 4, - primitive_in = :points, - primitive_out = :triangle_strip, + geometryshader=geom_particles, + max_primitives=4, + primitive_in=:points, + primitive_out=:triangle_strip, ) struct Canvas{N} - color::NTuple{N, Matrix{RGBA{Float32}}} + color::NTuple{N,Matrix{RGBA{Float32}}} depth::Matrix{Float32} end function Canvas(xdim::Integer, ydim::Integer) - color = fill(RGBA{Float32}(0,0,0,0), xdim, ydim) + color = fill(RGBA{Float32}(0, 0, 0, 0), xdim, ydim) depth = ones(Float32, xdim, ydim) return Canvas((color,), depth) end diff --git a/src/layouting/boundingbox.jl b/src/layouting/boundingbox.jl index 18757dcb7a5..f1a180dc62a 100644 --- a/src/layouting/boundingbox.jl +++ b/src/layouting/boundingbox.jl @@ -1,11 +1,9 @@ function parent_transform(x) p = parent(transformation(x)) - isnothing(p) ? Mat4f(I) : p.model[] + return isnothing(p) ? Mat4f(I) : p.model[] end -function boundingbox(x, exclude = (p)-> false) - return parent_transform(x) * data_limits(x, exclude) -end +boundingbox(x, exclude=(p) -> false) = parent_transform(x) * data_limits(x, exclude) function project_widths(matrix, vec) pr = project(matrix, vec) @@ -15,7 +13,7 @@ end function rotate_bbox(bb::Rect3f, rot) points = decompose(Point3f, bb) - Rect3f(Ref(rot) .* points) + return Rect3f(Ref(rot) .* points) end function gl_bboxes(gl::GlyphCollection) @@ -23,10 +21,7 @@ function gl_bboxes(gl::GlyphCollection) map(gl.glyphs, gl.extents, scales) do c, ext, scale hi_bb = height_insensitive_boundingbox_with_advance(ext) # TODO c != 0 filters out all non renderables, which is not always desired - Rect2f( - Makie.origin(hi_bb) * scale, - (c != 0) * widths(hi_bb) * scale - ) + return Rect2f(Makie.origin(hi_bb) * scale, (c != 0) * widths(hi_bb) * scale) end end @@ -39,7 +34,7 @@ function height_insensitive_boundingbox(ext::GlyphExtent) end function height_insensitive_boundingbox_with_advance(ext::GlyphExtent) - l = 0f0 + l = 0.0f0 r = ext.hadvance b = ext.descender h = ext.ascender @@ -130,11 +125,22 @@ _is_latex_string(x::LaTeXString) = true _is_latex_string(other) = false function text_bb(str, font, size) - rot = Quaternionf(0,0,0,1) + rot = Quaternionf(0, 0, 0, 1) fonts = nothing # TODO: remove the arg if possible layout = layout_text( - str, size, font, fonts, Vec2f(0), rot, 0.5, 1.0, - RGBAf(0, 0, 0, 0), RGBAf(0, 0, 0, 0), 0f0, 0f0) + str, + size, + font, + fonts, + Vec2f(0), + rot, + 0.5, + 1.0, + RGBAf(0, 0, 0, 0), + RGBAf(0, 0, 0, 0), + 0.0f0, + 0.0f0, + ) return boundingbox(layout, Point3f(0), rot) end @@ -142,19 +148,11 @@ end Calculate an approximation of a tight rectangle around a 2D rectangle rotated by `angle` radians. This is not perfect but works well enough. Check an A vs X to see the difference. """ -function rotatedrect(rect::Rect{2, T}, angle)::Rect{2, T} where T +function rotatedrect(rect::Rect{2,T}, angle)::Rect{2,T} where {T} ox, oy = rect.origin wx, wy = rect.widths - points = Mat{2, 4, T}( - ox, oy, - ox, oy+wy, - ox+wx, oy, - ox+wx, oy+wy - ) - mrot = Mat{2, 2, T}( - cos(angle), -sin(angle), - sin(angle), cos(angle) - ) + points = Mat{2,4,T}(ox, oy, ox, oy + wy, ox + wx, oy, ox + wx, oy + wy) + mrot = Mat{2,2,T}(cos(angle), -sin(angle), sin(angle), cos(angle)) rotated = mrot * points rmins = minimum(rotated; dims=2) diff --git a/src/layouting/data_limits.jl b/src/layouting/data_limits.jl index 4d3e624d2a5..3f816a94f4e 100644 --- a/src/layouting/data_limits.jl +++ b/src/layouting/data_limits.jl @@ -1,9 +1,9 @@ _isfinite(x) = isfinite(x) _isfinite(x::VecTypes) = all(isfinite, x) -isfinite_rect(x::Rect) = all(isfinite, x.origin) && all(isfinite, x.widths) -scalarmax(x::Union{Tuple, AbstractArray}, y::Union{Tuple, AbstractArray}) = max.(x, y) +isfinite_rect(x::Rect) = all(isfinite, x.origin) && all(isfinite, x.widths) +scalarmax(x::Union{Tuple,AbstractArray}, y::Union{Tuple,AbstractArray}) = max.(x, y) scalarmax(x, y) = max(x, y) -scalarmin(x::Union{Tuple, AbstractArray}, y::Union{Tuple, AbstractArray}) = min.(x, y) +scalarmin(x::Union{Tuple,AbstractArray}, y::Union{Tuple,AbstractArray}) = min.(x, y) scalarmin(x, y) = min(x, y) extrema_nan(itr::Pair) = (itr[1], itr[2]) @@ -32,15 +32,13 @@ end function distinct_extrema_nan(x) lo, hi = extrema_nan(x) - lo == hi ? (lo - 0.5f0, hi + 0.5f0) : (lo, hi) + return lo == hi ? (lo - 0.5f0, hi + 0.5f0) : (lo, hi) end -function point_iterator(plot::Union{Scatter, MeshScatter, Lines, LineSegments}) - return plot.positions[] -end +point_iterator(plot::Union{Scatter,MeshScatter,Lines,LineSegments}) = plot.positions[] # TODO? -function point_iterator(text::Text{<: Tuple{<: Union{GlyphCollection, AbstractVector{GlyphCollection}}}}) +function point_iterator(text::Text{<:Tuple{<:Union{GlyphCollection,AbstractVector{GlyphCollection}}}}) if is_data_space(text.markerspace[]) return decompose(Point, boundingbox(text)) else @@ -52,27 +50,19 @@ function point_iterator(text::Text{<: Tuple{<: Union{GlyphCollection, AbstractVe end end -function point_iterator(text::Text) - return point_iterator(text.plots[1]) -end +point_iterator(text::Text) = point_iterator(text.plots[1]) point_iterator(mesh::GeometryBasics.Mesh) = decompose(Point, mesh) -function point_iterator(list::AbstractVector) - Iterators.flatten((point_iterator(elem) for elem in list)) -end +point_iterator(list::AbstractVector) = Iterators.flatten((point_iterator(elem) for elem in list)) point_iterator(plot::Combined) = point_iterator(plot.plots) point_iterator(plot::Mesh) = point_iterator(plot.mesh[]) -function br_getindex(vector::AbstractVector, idx::CartesianIndex, dim::Int) - return vector[Tuple(idx)[dim]] -end +br_getindex(vector::AbstractVector, idx::CartesianIndex, dim::Int) = vector[Tuple(idx)[dim]] -function br_getindex(matrix::AbstractMatrix, idx::CartesianIndex, dim::Int) - return matrix[idx] -end +br_getindex(matrix::AbstractMatrix, idx::CartesianIndex, dim::Int) = matrix[idx] function get_point_xyz(linear_indx::Int, indices, X, Y, Z) idx = indices[linear_indx] @@ -117,7 +107,7 @@ end function point_iterator(x::Volume) axes = (x[1], x[2], x[3]) - extremata = map(extrema∘to_value, axes) + extremata = map(extrema ∘ to_value, axes) minpoint = Point3f(first.(extremata)...) widths = last.(extremata) .- first.(extremata) rect = Rect3f(minpoint, Vec3f(widths)) @@ -126,19 +116,18 @@ end function foreach_plot(f, s::Scene) foreach_plot(f, s.plots) - foreach(sub-> foreach_plot(f, sub), s.children) + return foreach(sub -> foreach_plot(f, sub), s.children) end foreach_plot(f, s::Figure) = foreach_plot(f, s.scene) foreach_plot(f, s::FigureAxisPlot) = foreach_plot(f, s.figure) foreach_plot(f, list::AbstractVector) = foreach(f, list) -function foreach_plot(f, plot::Combined) +foreach_plot(f, plot::Combined) = if isempty(plot.plots) f(plot) else foreach_plot(f, plot.plots) end -end function foreach_transformed(f, point_iterator, model, trans_func) for point in point_iterator @@ -155,7 +144,7 @@ function foreach_transformed(f, plot) model = model_transform(t) trans_func = t.transform_func[] # use function barrier since trans_func is Any - foreach_transformed(f, points, model, identity) + return foreach_transformed(f, points, model, identity) end function iterate_transformed(plot) @@ -165,19 +154,18 @@ function iterate_transformed(plot) # TODO: For some reason this was identity before and limit calculations in Axis with log scale are wrong if not, because they're already log transformed. What's the right behavior? # trans_func = t.transform_func[] trans_func = identity - iterate_transformed(points, model, trans_func) + return iterate_transformed(points, model, trans_func) end function iterate_transformed(points, model, trans_func) - (to_ndim(Point3f, project(model, apply_transform(trans_func, point)), 0f0) for point in points) + return (to_ndim(Point3f, project(model, apply_transform(trans_func, point)), 0.0f0) for point in points) end -function update_boundingbox!(bb_ref, point) +update_boundingbox!(bb_ref, point) = if all(isfinite, point) vec = to_ndim(Vec3f, point, 0.0) bb_ref[] = update(bb_ref[], vec) end -end function update_boundingbox!(bb_ref, bb::Rect) # ref is uninitialized, so just set it to the first bb @@ -192,31 +180,29 @@ function update_boundingbox!(bb_ref, bb::Rect) return end -function data_limits(plot::AbstractPlot) - limits_from_transformed_points(iterate_transformed(plot)) -end +data_limits(plot::AbstractPlot) = limits_from_transformed_points(iterate_transformed(plot)) -function _update_rect(rect::Rect{N, T}, point::Point{N, T}) where {N, T} +function _update_rect(rect::Rect{N,T}, point::Point{N,T}) where {N,T} mi = minimum(rect) ma = maximum(rect) mis_mas = map(mi, ma, point) do _mi, _ma, _p - (isnan(_mi) ? _p : _p < _mi ? _p : _mi), (isnan(_ma) ? _p : _p > _ma ? _p : _ma) + return (isnan(_mi) ? _p : _p < _mi ? _p : _mi), (isnan(_ma) ? _p : _p > _ma ? _p : _ma) end new_o = map(first, mis_mas) new_w = map(mis_mas) do (mi, ma) - ma - mi + return ma - mi end - typeof(rect)(new_o, new_w) + return typeof(rect)(new_o, new_w) end function limits_from_transformed_points(points_iterator) isempty(points_iterator) && return Rect3f() first, rest = Iterators.peel(points_iterator) - bb = foldl(_update_rect, rest, init = Rect3f(first, zero(first))) + bb = foldl(_update_rect, rest, init=Rect3f(first, zero(first))) return bb end -function data_limits(scenelike, exclude=(p)-> false) +function data_limits(scenelike, exclude=(p) -> false) bb_ref = Base.RefValue(Rect3f()) foreach_plot(scenelike) do plot if !exclude(plot) diff --git a/src/layouting/layouting.jl b/src/layouting/layouting.jl index 024500aecc2..2c0323fea54 100644 --- a/src/layouting/layouting.jl +++ b/src/layouting/layouting.jl @@ -2,9 +2,7 @@ using FreeTypeAbstraction: hadvance, leftinkbound, inkwidth, get_extent, ascende one_attribute_per_char(attribute, string) = (attribute for char in string) -function one_attribute_per_char(font::NativeFont, string) - return (find_font_for_char(char, font) for char in string) -end +one_attribute_per_char(font::NativeFont, string) = (find_font_for_char(char, font) for char in string) function attribute_per_char(string, attribute) n_words = 0 @@ -25,11 +23,11 @@ function attribute_per_char(string, attribute) else return one_attribute_per_char(attribute, string) end - error("A vector of attributes with $(length(attribute)) elements was given but this fits neither the length of '$string' ($(length(string))) nor the number of words ($(n_words))") + return error( + "A vector of attributes with $(length(attribute)) elements was given but this fits neither the length of '$string' ($(length(string))) nor the number of words ($(n_words))", + ) end - - """ layout_text( string::AbstractString, fontsize::Union{AbstractVector, Number}, @@ -39,11 +37,19 @@ end Compute a GlyphCollection for a `string` given fontsize, font, align, rotation, model, justification, and lineheight. """ function layout_text( - string::AbstractString, fontsize::Union{AbstractVector, Number}, - font, fonts, align, rotation, justification, lineheight, color, - strokecolor, strokewidth, word_wrap_width - ) - + string::AbstractString, + fontsize::Union{AbstractVector,Number}, + font, + fonts, + align, + rotation, + justification, + lineheight, + color, + strokecolor, + strokewidth, + word_wrap_width, +) ft_font = to_font(font) rscale = to_fontsize(fontsize) rot = to_rotation(rotation) @@ -52,9 +58,18 @@ function layout_text( fontsizeperchar = attribute_per_char(string, rscale) glyphcollection = glyph_collection( - string, fontperchar, fontsizeperchar, align[1], align[2], - lineheight, justification, rot, color, - strokecolor, strokewidth, word_wrap_width + string, + fontperchar, + fontsizeperchar, + align[1], + align[2], + lineheight, + justification, + rot, + color, + strokecolor, + strokewidth, + word_wrap_width, ) return glyphcollection @@ -68,23 +83,39 @@ This layout in text coordinates, relative to the anchor point [0,0] can then be rotated to wherever it is needed in the plot. """ function glyph_collection( - str::AbstractString, font_per_char, fontscale_px, halign, valign, - lineheight_factor, justification, rotation, color, - strokecolor, strokewidth, word_wrap_width - ) - + str::AbstractString, + font_per_char, + fontscale_px, + halign, + valign, + lineheight_factor, + justification, + rotation, + color, + strokecolor, + strokewidth, + word_wrap_width, +) isempty(str) && return GlyphCollection( - [], [], Point3f[],FreeTypeAbstraction.FontExtent{Float32}[], - Vec2f[], Float32[], RGBAf[], RGBAf[], Float32[]) + [], + [], + Point3f[], + FreeTypeAbstraction.FontExtent{Float32}[], + Vec2f[], + Float32[], + RGBAf[], + RGBAf[], + Float32[], + ) # collect information about every character in the string charinfos = broadcast((c for c in str), font_per_char, fontscale_px) do char, font, scale - ( - char = char, - font = font, - scale = scale, - lineheight = Float32(font.height / font.units_per_EM * lineheight_factor * scale), - extent = GlyphExtent(font, char) + return ( + char=char, + font=font, + scale=scale, + lineheight=Float32(font.height / font.units_per_EM * lineheight_factor * scale), + extent=GlyphExtent(font, char), ) end @@ -95,8 +126,8 @@ function glyph_collection( last_space_local_idx = 0 last_space_global_idx = 0 - newline_offset = 0f0 - x = 0f0 + newline_offset = 0.0f0 + x = 0.0f0 xs = [Float32[]] # If word_wrap_width > 0: @@ -113,21 +144,20 @@ function glyph_collection( push!(xs[end], x) x += ci.extent.hadvance * ci.scale - if 0 < word_wrap_width < x && last_space_local_idx != 0 && - ((ci.char in (' ', '\n')) || i == length(charinfos)) - + if 0 < word_wrap_width < x && + last_space_local_idx != 0 && + ((ci.char in (' ', '\n')) || i == length(charinfos)) newline_offset = xs[end][last_space_local_idx + 1] - push!(xs, xs[end][last_space_local_idx+1:end] .- newline_offset) - xs[end-1] = xs[end-1][1:last_space_local_idx] + push!(xs, xs[end][(last_space_local_idx + 1):end] .- newline_offset) + xs[end - 1] = xs[end - 1][1:last_space_local_idx] push!(lineinfos, view(charinfos, last_line_start:last_space_global_idx)) - last_line_start = last_space_global_idx+1 + last_line_start = last_space_global_idx + 1 x = xs[end][end] + ci.extent.hadvance * ci.scale # TODO Do we need to redo the metrics for newlines? charinfos[last_space_global_idx] = let _, font, scale, lineheight, extent = charinfos[last_space_global_idx] - (char = '\n', font = font, scale = scale, - lineheight = lineheight, extent = extent) + (char='\n', font=font, scale=scale, lineheight=lineheight, extent=extent) end end @@ -135,8 +165,8 @@ function glyph_collection( push!(xs, Float32[]) push!(lineinfos, view(charinfos, last_line_start:i)) last_space_local_idx = 0 - last_line_start = i+1 - x = 0f0 + last_line_start = i + 1 + x = 0.0f0 elseif i == length(charinfos) push!(lineinfos, view(charinfos, last_line_start:i)) end @@ -156,7 +186,7 @@ function glyph_collection( # if the last and not the only character is \n, take the previous one # to compute the width i = (nchars > 1 && line[end].char == '\n') ? nchars - 1 : nchars - xx[i] + line[i].extent.hadvance * line[i].scale + return xx[i] + line[i].extent.hadvance * line[i].scale end # the maximum width is needed for justification @@ -188,13 +218,13 @@ function glyph_collection( end xs_justified = map(xs, width_differences) do xsgroup, wd - xsgroup .+ wd * float_justification + return xsgroup .+ wd * float_justification end # each character carries a "lineheight" metric given its font and scale and a lineheight scaling factor # make each line's height the maximum of these values in the line lineheights = map(lineinfos) do line - maximum(l -> l.lineheight, line) + return maximum(l -> l.lineheight, line) end # compute y values by adding up lineheights in negative y direction @@ -217,11 +247,11 @@ function glyph_collection( # for y alignment, we need the largest ascender of the first line # and the largest descender of the last line first_line_ascender = maximum(lineinfos[1]) do l - l.scale * l.extent.ascender + return l.scale * l.extent.ascender end last_line_descender = minimum(lineinfos[end]) do l - l.scale * l.extent.descender + return l.scale * l.extent.descender end # compute the height of all lines together @@ -234,9 +264,9 @@ function glyph_collection( va = if valign isa Number Float32(valign) elseif valign == :top - 1f0 + 1.0f0 elseif valign == :bottom - 0f0 + 0.0f0 elseif valign == :center 0.5f0 else @@ -265,12 +295,12 @@ function glyph_collection( per_char(rotation), # rotations is used as one rotation per string above. TODO, allow one rotation per char per_char(color), per_char(strokecolor), - per_char(strokewidth) + per_char(strokewidth), ) end # function to concatenate vectors with a value between every pair -function padded_vcat(arrs::AbstractVector{T}, fillvalue) where T <: AbstractVector{S} where S +function padded_vcat(arrs::AbstractVector{T}, fillvalue) where {T<:AbstractVector{S}} where {S} n = sum(length.(arrs)) arr = fill(convert(S, fillvalue), n + length(arrs) - 1) @@ -282,7 +312,7 @@ function padded_vcat(arrs::AbstractVector{T}, fillvalue) where T <: AbstractVect end counter += 1 end - arr + return arr end function alignment2num(x::Symbol) @@ -292,7 +322,6 @@ function alignment2num(x::Symbol) return 0.0f0 # 0 default, or better to error? end - # Backend data _offset_to_vec(o::VecTypes) = to_ndim(Vec3f, o, 0) @@ -315,9 +344,7 @@ function text_quads(atlas::TextureAtlas, position::VecTypes, gc::GlyphCollection uvs = Vector{Vec4f}(undef, length(pos)) for i in eachindex(pos) - glyph_bb, extent = FreeTypeAbstraction.metrics_bb( - gc.glyphs[i], gc.fonts[i], gc.scales[i] - ) + glyph_bb, extent = FreeTypeAbstraction.metrics_bb(gc.glyphs[i], gc.fonts[i], gc.scales[i]) uvs[i] = glyph_uv_width!(atlas, gc.glyphs[i], gc.fonts[i]) scales[i] = widths(glyph_bb) .+ gc.scales[i] .* 2pad char_offsets[i] = gc.origins[i] .+ _offset_at(off, i) @@ -335,7 +362,14 @@ function text_quads(atlas::TextureAtlas, position::VecTypes, gc::GlyphCollection return pos, char_offsets, quad_offsets, uvs, scales end -function text_quads(atlas::TextureAtlas, position::Vector, gcs::Vector{<: GlyphCollection}, offset, transfunc, space) +function text_quads( + atlas::TextureAtlas, + position::Vector, + gcs::Vector{<:GlyphCollection}, + offset, + transfunc, + space, +) ps = apply_transform(transfunc, position, space) pos = [to_ndim(Point3f, p, 0) for (p, gc) in zip(ps, gcs) for _ in gc.origins] @@ -344,8 +378,9 @@ function text_quads(atlas::TextureAtlas, position::Vector, gcs::Vector{<: GlyphC # To avoid errors due to asynchronous updates of text attributes M = min( - length(gcs), length(position), - ifelse(off isa StaticVector || length(off) == 1, typemax(Int), length(off)) + length(gcs), + length(position), + ifelse(off isa StaticVector || length(off) == 1, typemax(Int), length(off)), ) char_offsets = Vector{Vec3f}(undef, length(pos)) # TODO can this be Vec2f? @@ -357,9 +392,7 @@ function text_quads(atlas::TextureAtlas, position::Vector, gcs::Vector{<: GlyphC for j in 1:M gc = gcs[j] for i in eachindex(gc.origins) - glyph_bb, extent = FreeTypeAbstraction.metrics_bb( - gc.glyphs[i], gc.fonts[i], gc.scales[i] - ) + glyph_bb, extent = FreeTypeAbstraction.metrics_bb(gc.glyphs[i], gc.fonts[i], gc.scales[i]) uvs[k] = glyph_uv_width!(atlas, gc.glyphs[i], gc.fonts[i]) scales[k] = widths(glyph_bb) .+ gc.scales[i] * 2pad char_offsets[k] = gc.origins[i] .+ _offset_at(off, j) diff --git a/src/layouting/transformation.jl b/src/layouting/transformation.jl index 98af0448537..664efc970ff 100644 --- a/src/layouting/transformation.jl +++ b/src/layouting/transformation.jl @@ -1,28 +1,24 @@ Base.parent(t::Transformation) = isassigned(t.parent) ? t.parent[] : nothing -function Transformation(transform_func=identity; - scale=Vec3f(1), - translation=Vec3f(0), - rotation=Quaternionf(0, 0, 0, 1)) - +function Transformation( + transform_func=identity; + scale=Vec3f(1), + translation=Vec3f(0), + rotation=Quaternionf(0, 0, 0, 1), +) scale_o = convert(Observable{Vec3f}, scale) translation_o = convert(Observable{Vec3f}, translation) rotation_o = convert(Observable{Quaternionf}, rotation) model = map(transformationmatrix, translation_o, scale_o, rotation_o) - return Transformation( - translation_o, - scale_o, - rotation_o, - model, - convert(Observable{Any}, transform_func) - ) + return Transformation(translation_o, scale_o, rotation_o, model, convert(Observable{Any}, transform_func)) end -function Transformation(transformable::Transformable; - scale=Vec3f(1), - translation=Vec3f(0), - rotation=Quaternionf(0, 0, 0, 1)) - +function Transformation( + transformable::Transformable; + scale=Vec3f(1), + translation=Vec3f(0), + rotation=Quaternionf(0, 0, 0, 1), +) scale_o = convert(Observable{Vec3f}, scale) translation_o = convert(Observable{Vec3f}, translation) rotation_o = convert(Observable{Quaternionf}, rotation) @@ -33,49 +29,40 @@ function Transformation(transformable::Transformable; return p * transformationmatrix(t, s, r) end - trans = Transformation( - translation_o, - scale_o, - rotation_o, - model, - copy(parent_transform.transform_func) - ) + trans = Transformation(translation_o, scale_o, rotation_o, model, copy(parent_transform.transform_func)) trans.parent[] = parent_transform return trans end function model_transform(transformation::Transformation) - return transformationmatrix(transformation.translation[], transformation.scale[], transformation.rotation[]) + return transformationmatrix( + transformation.translation[], + transformation.scale[], + transformation.rotation[], + ) end function translated(scene::Scene, translation...) - tscene = Scene(scene, transformation = Transformation()) + tscene = Scene(scene, transformation=Transformation()) transform!(tscene, translation...) - tscene + return tscene end function translated(scene::Scene; kw_args...) - tscene = Scene(scene, transformation = Transformation()) + tscene = Scene(scene, transformation=Transformation()) transform!(tscene; kw_args...) - tscene + return tscene end -function transform!( - scene::Transformable; - translation = Vec3f(0), - scale = Vec3f(1), - rotation = 0.0, - ) +function transform!(scene::Transformable; translation=Vec3f(0), scale=Vec3f(1), rotation=0.0) translate!(scene, to_value(translation)) scale!(scene, to_value(scale)) - rotate!(scene, to_value(rotation)) + return rotate!(scene, to_value(rotation)) end -function transform!( - scene::Transformable, attributes::Union{Attributes, AbstractDict} - ) - transform!(scene; attributes...) +function transform!(scene::Transformable, attributes::Union{Attributes,AbstractDict}) + return transform!(scene; attributes...) end transformation(t::Scene) = t.transformation @@ -100,7 +87,7 @@ scale!(t::Transformable, xyz...) = scale!(t, xyz) rotation(scene::Transformable) = transformation(scene).rotation -function rotate!(::Type{T}, scene::Transformable, q) where T +function rotate!(::Type{T}, scene::Transformable, q) where {T} rot = convert_attribute(q, key"rotation"()) if T === Accum rot1 = rotation(scene)[] @@ -117,7 +104,7 @@ end Apply a relative rotation to the Scene, by multiplying by the current rotation. """ -rotate!(::Type{T}, scene::Transformable, axis_rot...) where T = rotate!(T, scene, axis_rot) +rotate!(::Type{T}, scene::Transformable, axis_rot...) where {T} = rotate!(T, scene, axis_rot) """ rotate!(t::Transformable, axis_rot::Quaternion) @@ -145,7 +132,7 @@ This is the default setting. """ struct Absolute end -function translate!(::Type{T}, scene::Transformable, t) where T +function translate!(::Type{T}, scene::Transformable, t) where {T} offset = to_ndim(Vec3f, Float32.(t), 0) if T === Accum translation(scene)[] = translation(scene)[] .+ offset @@ -169,25 +156,27 @@ translate!(scene::Transformable, xyz...) = translate!(Absolute, scene, xyz) Translate the scene relative to its current position. """ -translate!(::Type{T}, scene::Transformable, xyz...) where T = translate!(T, scene, xyz) +translate!(::Type{T}, scene::Transformable, xyz...) where {T} = translate!(T, scene, xyz) -function transform!(scene::Transformable, x::Tuple{Symbol, <: Number}) +function transform!(scene::Transformable, x::Tuple{Symbol,<:Number}) plane, dimval = string(x[1]), Float32(x[2]) - if length(plane) != 2 || (!all(x-> x in ('x', 'y', 'z'), plane)) - error("plane needs to define a 2D plane in xyz. It should only contain 2 symbols out of (:x, :y, :z). Found: $plane") + if length(plane) != 2 || (!all(x -> x in ('x', 'y', 'z'), plane)) + error( + "plane needs to define a 2D plane in xyz. It should only contain 2 symbols out of (:x, :y, :z). Found: $plane", + ) end - if all(x-> x in ('x', 'y'), plane) # xy plane + if all(x -> x in ('x', 'y'), plane) # xy plane translate!(scene, 0, 0, dimval) - elseif all(x-> x in ('x', 'z'), plane) # xz plane + elseif all(x -> x in ('x', 'z'), plane) # xz plane rotate!(scene, Vec3f(1, 0, 0), 0.5pi) translate!(scene, 0, dimval, 0) else #yz plane r1 = qrotation(Vec3f(0, 1, 0), 0.5pi) r2 = qrotation(Vec3f(1, 0, 0), 0.5pi) - rotate!(scene, r2 * r1) + rotate!(scene, r2 * r1) translate!(scene, dimval, 0, 0) end - scene + return scene end transformationmatrix(x) = transformation(x).model @@ -200,10 +189,10 @@ transform_func_obs(x) = transformation(x).transform_func Apply the data transform func to the data if the space matches one of the the transformation spaces (currently only :data is transformed) """ -apply_transform(f, data, space) = space == :data ? apply_transform(f, data) : data -function apply_transform(f::Observable, data::Observable, space::Observable) - return lift((f, d, s)-> apply_transform(f, d, s), f, data, space) -end +apply_transform(f, data, space) = space == :data ? apply_transform(f, data) : data +function apply_transform(f::Observable, data::Observable, space::Observable) + return lift((f, d, s) -> apply_transform(f, d, s), f, data, space) +end """ apply_transform(f, data) @@ -216,83 +205,63 @@ apply_transform(f::typeof(identity), x::VecTypes) = x apply_transform(f::typeof(identity), x::Number) = x apply_transform(f::typeof(identity), x::ClosedInterval) = x -apply_transform(f::NTuple{2, typeof(identity)}, x) = x -apply_transform(f::NTuple{2, typeof(identity)}, x::AbstractArray) = x -apply_transform(f::NTuple{2, typeof(identity)}, x::VecTypes) = x -apply_transform(f::NTuple{2, typeof(identity)}, x::Number) = x -apply_transform(f::NTuple{2, typeof(identity)}, x::ClosedInterval) = x - -apply_transform(f::NTuple{3, typeof(identity)}, x) = x -apply_transform(f::NTuple{3, typeof(identity)}, x::AbstractArray) = x -apply_transform(f::NTuple{3, typeof(identity)}, x::VecTypes) = x -apply_transform(f::NTuple{3, typeof(identity)}, x::Number) = x -apply_transform(f::NTuple{3, typeof(identity)}, x::ClosedInterval) = x +apply_transform(f::NTuple{2,typeof(identity)}, x) = x +apply_transform(f::NTuple{2,typeof(identity)}, x::AbstractArray) = x +apply_transform(f::NTuple{2,typeof(identity)}, x::VecTypes) = x +apply_transform(f::NTuple{2,typeof(identity)}, x::Number) = x +apply_transform(f::NTuple{2,typeof(identity)}, x::ClosedInterval) = x +apply_transform(f::NTuple{3,typeof(identity)}, x) = x +apply_transform(f::NTuple{3,typeof(identity)}, x::AbstractArray) = x +apply_transform(f::NTuple{3,typeof(identity)}, x::VecTypes) = x +apply_transform(f::NTuple{3,typeof(identity)}, x::Number) = x +apply_transform(f::NTuple{3,typeof(identity)}, x::ClosedInterval) = x -struct PointTrans{N, F} +struct PointTrans{N,F} f::F - function PointTrans{N}(f::F) where {N, F} + function PointTrans{N}(f::F) where {N,F} if !hasmethod(f, Tuple{Point{N}}) error("PointTrans with parameter N = $N must be applicable to an argument of type Point{$N}.") end - new{N, F}(f) + return new{N,F}(f) end end # PointTrans{N}(func::F) where {N, F} = PointTrans{N, F}(func) Base.broadcastable(x::PointTrans) = (x,) -function apply_transform(f::PointTrans{N}, point::Point{N}) where N - return f.f(point) -end +apply_transform(f::PointTrans{N}, point::Point{N}) where {N} = f.f(point) -function apply_transform(f::PointTrans{N1}, point::Point{N2}) where {N1, N2} - p_dim = to_ndim(Point{N1, Float32}, point, 0.0) +function apply_transform(f::PointTrans{N1}, point::Point{N2}) where {N1,N2} + p_dim = to_ndim(Point{N1,Float32}, point, 0.0) p_trans = f.f(p_dim) if N1 < N2 - p_large = ntuple(i-> i <= N1 ? p_trans[i] : point[i], N2) - return Point{N2, Float32}(p_large) + p_large = ntuple(i -> i <= N1 ? p_trans[i] : point[i], N2) + return Point{N2,Float32}(p_large) else - return to_ndim(Point{N2, Float32}, p_trans, 0.0) + return to_ndim(Point{N2,Float32}, p_trans, 0.0) end end -function apply_transform(f, data::AbstractArray) - map(point-> apply_transform(f, point), data) -end +apply_transform(f, data::AbstractArray) = map(point -> apply_transform(f, point), data) -function apply_transform(f::Tuple{Any, Any}, point::VecTypes{2}) - Point2{Float32}( - f[1](point[1]), - f[2](point[2]), - ) -end +apply_transform(f::Tuple{Any,Any}, point::VecTypes{2}) = Point2{Float32}(f[1](point[1]), f[2](point[2])) # ambiguity fix -apply_transform(f::NTuple{2, typeof(identity)}, point::VecTypes{2}) = point +apply_transform(f::NTuple{2,typeof(identity)}, point::VecTypes{2}) = point - -function apply_transform(f::Tuple{Any, Any}, point::VecTypes{3}) - apply_transform((f..., identity), point) -end +apply_transform(f::Tuple{Any,Any}, point::VecTypes{3}) = apply_transform((f..., identity), point) # ambiguity fix -apply_transform(f::NTuple{2, typeof(identity)}, point::VecTypes{3}) = point +apply_transform(f::NTuple{2,typeof(identity)}, point::VecTypes{3}) = point -function apply_transform(f::Tuple{Any, Any, Any}, point::VecTypes{3}) - Point3{Float32}( - f[1](point[1]), - f[2](point[2]), - f[3](point[3]), - ) +function apply_transform(f::Tuple{Any,Any,Any}, point::VecTypes{3}) + return Point3{Float32}(f[1](point[1]), f[2](point[2]), f[3](point[3])) end # ambiguity fix -apply_transform(f::NTuple{3, typeof(identity)}, point::VecTypes{3}) = point - +apply_transform(f::NTuple{3,typeof(identity)}, point::VecTypes{3}) = point apply_transform(f, number::Number) = f(number) -function apply_transform(f::Observable, data::Observable) - return lift((f, d)-> apply_transform(f, d), f, data) -end +apply_transform(f::Observable, data::Observable) = lift((f, d) -> apply_transform(f, d), f, data) apply_transform(f, itr::Pair) = apply_transform(f, itr[1]) => apply_transform(f, itr[2]) function apply_transform(f, itr::ClosedInterval) @@ -300,27 +269,25 @@ function apply_transform(f, itr::ClosedInterval) return apply_transform(f, mini) .. apply_transform(f, maxi) end - function apply_transform(f, r::Rect) mi = minimum(r) ma = maximum(r) mi_t = apply_transform(f, mi) ma_t = apply_transform(f, ma) - Rect(Vec(mi_t), Vec(ma_t .- mi_t)) + return Rect(Vec(mi_t), Vec(ma_t .- mi_t)) end function apply_transform(f::PointTrans, r::Rect) mi = minimum(r) ma = maximum(r) mi_t = apply_transform(f, Point(mi)) ma_t = apply_transform(f, Point(ma)) - Rect(Vec(mi_t), Vec(ma_t .- mi_t)) + return Rect(Vec(mi_t), Vec(ma_t .- mi_t)) end # ambiguity fix apply_transform(f::typeof(identity), r::Rect) = r -apply_transform(f::NTuple{2, typeof(identity)}, r::Rect) = r -apply_transform(f::NTuple{3, typeof(identity)}, r::Rect) = r - +apply_transform(f::NTuple{2,typeof(identity)}, r::Rect) = r +apply_transform(f::NTuple{3,typeof(identity)}, r::Rect) = r pseudolog10(x) = sign(x) * log10(abs(x) + 1) inv_pseudolog10(x) = sign(x) * (exp10(abs(x)) - 1) @@ -332,13 +299,13 @@ struct Symlog10 if !(low < 0 && high > 0) error("Low bound needs to be smaller than 0 and high bound larger than 0. You gave $low, $high.") end - new(Float64(low), Float64(high)) + return new(Float64(low), Float64(high)) end end Symlog10(x) = Symlog10(-x, x) -function (s::Symlog10)(x) +(s::Symlog10)(x) = if x > 0 x <= s.high ? x / s.high * log10(s.high) : log10(x) elseif x < 0 @@ -346,9 +313,8 @@ function (s::Symlog10)(x) else x end -end -function inv_symlog10(x, low, high) +inv_symlog10(x, low, high) = if x > 0 l = log10(high) x <= l ? x / l * high : exp10(x) @@ -358,23 +324,19 @@ function inv_symlog10(x, low, high) else x end -end inverse_transform(::typeof(identity)) = identity inverse_transform(::typeof(log10)) = exp10 inverse_transform(::typeof(log)) = exp inverse_transform(::typeof(log2)) = exp2 -inverse_transform(::typeof(sqrt)) = x -> x ^ 2 +inverse_transform(::typeof(sqrt)) = x -> x^2 inverse_transform(::typeof(pseudolog10)) = inv_pseudolog10 inverse_transform(F::Tuple) = map(inverse_transform, F) inverse_transform(::typeof(logit)) = logistic inverse_transform(s::Symlog10) = x -> inv_symlog10(x, s.low, s.high) inverse_transform(s) = nothing -function is_identity_transform(t) - return t === identity || t isa Tuple && all(x-> x === identity, t) -end - +is_identity_transform(t) = t === identity || t isa Tuple && all(x -> x === identity, t) # this is a simplification which will only really work with non-rotated or # scaled scene transformations, but for 2D scenes this should work well enough. @@ -382,6 +344,4 @@ end # by translating e.g. the axis spines forward so they are not obscured halfway # by heatmaps or images zvalue2d(x)::Float32 = Makie.translation(x)[][3] + zvalue2d(x.parent) -zvalue2d(::Nothing)::Float32 = 0f0 - - +zvalue2d(::Nothing)::Float32 = 0.0f0 diff --git a/src/makielayout/MakieLayout.jl b/src/makielayout/MakieLayout.jl index 83f7d061f2c..969beb31f6e 100644 --- a/src/makielayout/MakieLayout.jl +++ b/src/makielayout/MakieLayout.jl @@ -58,7 +58,8 @@ export tight_xticklabel_spacing!, tight_yticklabel_spacing!, tight_ticklabel_spa export set_close_to! export labelslider!, labelslidergrid! export addmouseevents! -export interactions, register_interaction!, deregister_interaction!, activate_interaction!, deactivate_interaction! +export interactions, + register_interaction!, deregister_interaction!, activate_interaction!, deactivate_interaction! export MouseEventTypes, MouseEvent, ScrollEvent, KeysEvent # export hlines!, vlines!, abline!, hspan!, vspan! export Cycle diff --git a/src/makielayout/blocks.jl b/src/makielayout/blocks.jl index a3f709aceb7..e076d33adea 100644 --- a/src/makielayout/blocks.jl +++ b/src/makielayout/blocks.jl @@ -6,16 +6,14 @@ function attribute_default_expressions end function _attribute_docs end function has_forwarded_layout end - -macro Block(name::Symbol, body::Expr = Expr(:block)) - +macro Block(name::Symbol, body::Expr=Expr(:block)) if !(body.head == :block) error("A Block needs to be defined within a `begin end` block") end structdef = quote mutable struct $name <: Makie.Block - parent::Union{Figure, Scene, Nothing} + parent::Union{Figure,Scene,Nothing} layoutobservables::Makie.LayoutObservables{GridLayout} blockscene::Scene end @@ -27,9 +25,8 @@ macro Block(name::Symbol, body::Expr = Expr(:block)) attrs = extract_attributes!(body) i_forwarded_layout = findfirst( - x -> x isa Expr && x.head == :macrocall && - x.args[1] == Symbol("@forwarded_layout"), - body.args + x -> x isa Expr && x.head == :macrocall && x.args[1] == Symbol("@forwarded_layout"), + body.args, ) has_forwarded_layout = i_forwarded_layout !== nothing @@ -42,15 +39,13 @@ macro Block(name::Symbol, body::Expr = Expr(:block)) if attrs !== nothing attribute_fields = map(attrs) do a - :($(a.symbol)::Observable{$(a.type)}) + return :($(a.symbol)::Observable{$(a.type)}) end append!(fields_vector, attribute_fields) end constructor = quote - function $name($(basefields...)) - new($(basefields...)) - end + $name($(basefields...)) = new($(basefields...)) end push!(fields_vector, constructor) @@ -64,48 +59,47 @@ macro Block(name::Symbol, body::Expr = Expr(:block)) export $name function Makie.is_attribute(::Type{$(name)}, sym::Symbol) - sym in ($((attrs !== nothing ? [QuoteNode(a.symbol) for a in attrs] : [])...),) + return sym in ($((attrs !== nothing ? [QuoteNode(a.symbol) for a in attrs] : [])...),) end - function Makie.default_attribute_values(::Type{$(name)}, scene::Union{Scene, Nothing}) + function Makie.default_attribute_values(::Type{$(name)}, scene::Union{Scene,Nothing}) sceneattrs = scene === nothing ? Attributes() : theme(scene) curdeftheme = Makie.current_default_theme() - $(make_attr_dict_expr(attrs, :sceneattrs, :curdeftheme)) + return $(make_attr_dict_expr(attrs, :sceneattrs, :curdeftheme)) end function Makie.attribute_default_expressions(::Type{$name}) - $( + return $( if attrs === nothing - Dict{Symbol, String}() + Dict{Symbol,String}() else - Dict{Symbol, String}([a.symbol => _defaultstring(a.default) for a in attrs]) + Dict{Symbol,String}([a.symbol => _defaultstring(a.default) for a in attrs]) end ) end function Makie._attribute_docs(::Type{$(name)}) - Dict( + return Dict( $( - (attrs !== nothing ? - [Expr(:call, :(=>), QuoteNode(a.symbol), a.docs) for a in attrs] : - [])... - ) + ( + attrs !== nothing ? + [Expr(:call, :(=>), QuoteNode(a.symbol), a.docs) for a in attrs] : [] + )... + ), ) end Makie.has_forwarded_layout(::Type{$name}) = $has_forwarded_layout end - esc(q) + return esc(q) end _defaultstring(x) = string(x) _defaultstring(x::String) = repr(x) -function make_attr_dict_expr(::Nothing, sceneattrsym, curthemesym) - :(Dict()) -end +make_attr_dict_expr(::Nothing, sceneattrsym, curthemesym) = :(Dict()) block_docs(x) = "" @@ -136,24 +130,21 @@ end function _attribute_list(T) ks = sort(collect(keys(default_attribute_values(T, nothing)))) default_exprs = attribute_default_expressions(T) - layout_attrs = Set([:tellheight, :tellwidth, :height, :width, - :valign, :halign, :alignmode]) - """ + layout_attrs = Set([:tellheight, :tellwidth, :height, :width, :valign, :halign, :alignmode]) + return """ - **$T attributes**: + **$T attributes**: - $(join([" - `$k`: $(_attribute_docs(T)[k]) Default: `$(default_exprs[k])`" for k in ks if k ∉ layout_attrs], "\n")) + $(join([" - `$k`: $(_attribute_docs(T)[k]) Default: `$(default_exprs[k])`" for k in ks if k ∉ layout_attrs], "\n")) - **Layout attributes**: + **Layout attributes**: - $(join([" - `$k`: $(_attribute_docs(T)[k]) Default: `$(default_exprs[k])`" for k in ks if k in layout_attrs], "\n")) - """ + $(join([" - `$k`: $(_attribute_docs(T)[k]) Default: `$(default_exprs[k])`" for k in ks if k in layout_attrs], "\n")) + """ end function make_attr_dict_expr(attrs, sceneattrsym, curthemesym) - pairs = map(attrs) do a - d = a.default if d isa Expr && d.head == :macrocall && d.args[1] == Symbol("@inherit") if length(d.args) != 4 @@ -177,28 +168,32 @@ function make_attr_dict_expr(attrs, sceneattrsym, curthemesym) end end - Expr(:call, :(=>), QuoteNode(a.symbol), d) + return Expr(:call, :(=>), QuoteNode(a.symbol), d) end - :(Dict($(pairs...))) + return :(Dict($(pairs...))) end function attribute_help(T) println("Available attributes for $T (use attribute_help($T, key) for more information):") foreach(sort(collect(keys(_attribute_docs(T))))) do key - println(key) + return println(key) end end -function attribute_help(T, key) - println(_attribute_docs(T)[key]) -end +attribute_help(T, key) = println(_attribute_docs(T)[key]) function extract_attributes!(body) i = findfirst( - (x -> x isa Expr && x.head == :macrocall && x.args[1] == Symbol("@attributes") && - x.args[3] isa Expr && x.args[3].head == :block), - body.args + ( + x -> + x isa Expr && + x.head == :macrocall && + x.args[1] == Symbol("@attributes") && + x.args[3] isa Expr && + x.args[3].head == :block + ), + body.args, ) if i === nothing return nothing @@ -223,10 +218,7 @@ function extract_attributes!(body) "The align mode of the block in its parent GridLayout." alignmode = Inside() end - layout_related_attributes = filter( - x -> !(x isa LineNumberNode), - layout_related_attribute_block.args - ) + layout_related_attributes = filter(x -> !(x isa LineNumberNode), layout_related_attribute_block.args) args = filter(x -> !(x isa LineNumberNode), attrs_block.args) @@ -257,7 +249,7 @@ function extract_attributes!(body) type = left.args[2] end - (docs = docs, symbol = attr_symbol, type = type, default = default) + return (docs=docs, symbol=attr_symbol, type=type, default=default) end attrs = map(extract_attr, args) @@ -271,41 +263,42 @@ function extract_attributes!(body) end end - attrs + return attrs end # intercept all block constructors and divert to _block(T, ...) -function (::Type{T})(args...; kwargs...) where {T<:Block} - _block(T, args...; kwargs...) -end +(::Type{T})(args...; kwargs...) where {T<:Block} = _block(T, args...; kwargs...) can_be_current_axis(x) = false get_top_parent(gp::GridPosition) = GridLayoutBase.top_parent(gp.layout) get_top_parent(gp::GridSubposition) = get_top_parent(gp.parent) -function _block(T::Type{<:Block}, - gp::Union{GridPosition, GridSubposition}, args...; kwargs...) - +function _block(T::Type{<:Block}, gp::Union{GridPosition,GridSubposition}, args...; kwargs...) top_parent = get_top_parent(gp) if top_parent === nothing - error("Found nothing as the top parent of this GridPosition. A GridPosition or GridSubposition needs to be connected to the top layout of a Figure, Scene or comparable object, either directly or through nested GridLayouts in order to plot into it.") + error( + "Found nothing as the top parent of this GridPosition. A GridPosition or GridSubposition needs to be connected to the top layout of a Figure, Scene or comparable object, either directly or through nested GridLayouts in order to plot into it.", + ) end b = gp[] = _block(T, top_parent, args...; kwargs...) - b + return b end -function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, - args...; bbox = nothing, kwargs...) +function _block(T::Type{<:Block}, fig_or_scene::Union{Figure,Scene}, args...; bbox=nothing, kwargs...) # first sort out all user kwargs that correspond to block attributes kwdict = Dict(kwargs) - + if haskey(kwdict, :textsize) - throw(ArgumentError("The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.")) + throw( + ArgumentError( + "The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.", + ), + ) end - attribute_kwargs = Dict{Symbol, Any}() + attribute_kwargs = Dict{Symbol,Any}() for (key, value) in kwdict if is_attribute(T, key) attribute_kwargs[key] = pop!(kwdict, key) @@ -323,18 +316,18 @@ function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, # make a final attribute dictionary using different priorities # for the different themes - attributes = Dict{Symbol, Any}() + attributes = Dict{Symbol,Any}() for (key, val) in default_attrs # give kwargs priority if haskey(attribute_kwargs, key) attributes[key] = attribute_kwargs[key] - # otherwise scene theme + # otherwise scene theme elseif haskey(typekey_scene_attrs, key) attributes[key] = typekey_scene_attrs[key] - # otherwise global theme + # otherwise global theme elseif haskey(typekey_attrs, key) attributes[key] = typekey_attrs[key] - # otherwise its the value from the type default theme + # otherwise its the value from the type default theme else attributes[key] = val end @@ -359,7 +352,7 @@ function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, layout_halign, layout_valign, layout_alignmode, - suggestedbbox = bbox + suggestedbbox=bbox, ) blockscene = Scene( @@ -368,7 +361,7 @@ function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, # for this it seems to be necessary to zero-out a possible non-zero # origin of the parent lift(Makie.zero_origin, topscene.px_area), - camera = campixel! + camera=campixel!, ) # create base block with otherwise undefined fields @@ -394,7 +387,7 @@ function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, # this is needed so that the update mechanism works, because the gridlayout's # suggestedbbox is not connected to anything on(b.layout.layoutobservables.suggestedbbox) do _ - notify(lobservables.suggestedbbox) + return notify(lobservables.suggestedbbox) end # disable the GridLayout's own computedbbox's effect empty!(b.layout.layoutobservables.computedbbox.listeners) @@ -416,15 +409,23 @@ function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, rethrow(e) end end - false + return false end if !isempty(unassigned_fields) error("The following fields of $T were not assigned after `initialize_block!`: $unassigned_fields") end # forward all layout attributes to the block's layoutobservables - connect_block_layoutobservables!(b, layout_width, layout_height, layout_tellwidth, - layout_tellheight, layout_halign, layout_valign, layout_alignmode) + connect_block_layoutobservables!( + b, + layout_width, + layout_height, + layout_tellwidth, + layout_tellheight, + layout_halign, + layout_valign, + layout_alignmode, + ) if fig_or_scene isa Figure register_in_figure!(fig_or_scene, b) @@ -432,10 +433,9 @@ function _block(T::Type{<:Block}, fig_or_scene::Union{Figure, Scene}, Makie.current_axis!(fig_or_scene, b) end end - b + return b end - """ Get the scene which blocks need from their parent to plot stuff into """ @@ -444,7 +444,7 @@ function get_topscene(s::Scene) if !(Makie.cameracontrols(s) isa Makie.PixelCamera) error("Can only use scenes with PixelCamera as topscene") end - s + return s end function register_in_figure!(fig::Figure, @nospecialize block::Block) @@ -454,12 +454,21 @@ function register_in_figure!(fig::Figure, @nospecialize block::Block) if !(block in fig.content) push!(fig.content, block) end - nothing + return nothing end zshift!(b::Block, z) = translate!(b.blockscene, 0, 0, z) -function connect_block_layoutobservables!(@nospecialize(block), layout_width, layout_height, layout_tellwidth, layout_tellheight, layout_halign, layout_valign, layout_alignmode) +function connect_block_layoutobservables!( + @nospecialize(block), + layout_width, + layout_height, + layout_tellwidth, + layout_tellheight, + layout_halign, + layout_valign, + layout_alignmode, +) connect!(layout_width, block.width) connect!(layout_height, block.height) connect!(layout_tellwidth, block.tellwidth) @@ -470,16 +479,18 @@ function connect_block_layoutobservables!(@nospecialize(block), layout_width, la return end -@inline function Base.setproperty!(x::T, key::Symbol, value) where T <: Block +@inline function Base.setproperty!(x::T, key::Symbol, value) where {T<:Block} if hasfield(T, key) if fieldtype(T, key) <: Observable if value isa Observable - error("It is disallowed to set `$key`, an Observable field of the $T struct, to an Observable with dot notation (`setproperty!`), because this would replace the existing Observable. If you really want to do this, use `setfield!` instead.") + error( + "It is disallowed to set `$key`, an Observable field of the $T struct, to an Observable with dot notation (`setproperty!`), because this would replace the existing Observable. If you really want to do this, use `setfield!` instead.", + ) end obs = fieldtype(T, key) getfield(x, key)[] = convert_for_attribute(observable_type(obs), value) else - setfield!(x, key, value) + setfield!(x, key, value) end else # this will throw correctly @@ -490,18 +501,13 @@ end # treat all blocks as scalars when broadcasting Base.Broadcast.broadcastable(l::Block) = Ref(l) -function Base.show(io::IO, ::T) where T <: Block - print(io, "$T()") -end +Base.show(io::IO, ::T) where {T<:Block} = print(io, "$T()") function Base.delete!(block::Block) block.parent === nothing && return s = get_topscene(block.parent) - deleteat!( - s.children, - findfirst(x -> x === block.blockscene, s.children) - ) + deleteat!(s.children, findfirst(x -> x === block.blockscene, s.children)) # TODO: what about the lift of the parent scene's # `px_area`, should this be cleaned up as well? @@ -515,45 +521,36 @@ function Base.delete!(block::Block) end # do nothing for scene and nothing -function delete_from_parent!(parent, block::Block) -end +function delete_from_parent!(parent, block::Block) end function delete_from_parent!(figure::Figure, block::Block) filter!(x -> x !== block, figure.content) if current_axis(figure) === block current_axis!(figure, nothing) end - nothing + return nothing end """ Overload to execute cleanup actions for specific blocks that go beyond deleting elements and removing from gridlayout """ -function on_delete(block) -end +function on_delete(block) end -function remove_element(x) - delete!(x) -end +remove_element(x) = delete!(x) -function remove_element(x::AbstractPlot) - delete!(x.parent, x) -end +remove_element(x::AbstractPlot) = delete!(x.parent, x) -function remove_element(xs::AbstractArray) - foreach(remove_element, xs) -end +remove_element(xs::AbstractArray) = foreach(remove_element, xs) -function remove_element(::Nothing) -end +function remove_element(::Nothing) end function delete_scene!(s::Scene) for p in copy(s.plots) delete!(s, p) end deleteat!(s.parent.children, findfirst(x -> x === s, s.parent.children)) - nothing + return nothing end # if a non-observable is passed, its value is converted and placed into an observable of @@ -570,13 +567,13 @@ function init_observable!(@nospecialize(x), key, @nospecialize(OT), @nospecializ obstype = observable_type(OT) o = Observable{obstype}() map!(o, value) do v - convert_for_attribute(obstype, v) + return convert_for_attribute(obstype, v) end setfield!(x, key, o) return x end -observable_type(x::Type{Observable{T}}) where T = T +observable_type(x::Type{Observable{T}}) where {T} = T convert_for_attribute(t::Any, x) = x convert_for_attribute(t::Type{Float64}, x) = convert(Float64, x) diff --git a/src/makielayout/blocks/axis.jl b/src/makielayout/blocks/axis.jl index 7c8f881f39d..d28f58de379 100644 --- a/src/makielayout/blocks/axis.jl +++ b/src/makielayout/blocks/axis.jl @@ -1,22 +1,24 @@ -function block_docs(::Type{Axis}) - """ - A 2D axis which can be plotted into. +block_docs(::Type{Axis}) = """ + A 2D axis which can be plotted into. - ## Constructors + ## Constructors - ```julia - Axis(fig_or_scene; palette = nothing, kwargs...) - ``` + ```julia + Axis(fig_or_scene; palette = nothing, kwargs...) + ``` - ## Examples + ## Examples - ```julia - ax = Axis(fig[1, 1]) - ``` - """ -end + ```julia + ax = Axis(fig[1, 1]) + ``` + """ -function update_gridlines!(grid_obs::Observable{Vector{Point2f}}, offset::Point2f, tickpositions::Vector{Point2f}) +function update_gridlines!( + grid_obs::Observable{Vector{Point2f}}, + offset::Point2f, + tickpositions::Vector{Point2f}, +) result = grid_obs[] empty!(result) # reuse array for less allocations for gridstart in tickpositions @@ -38,7 +40,6 @@ function process_axis_event(ax, event) end function register_events!(ax, scene) - mouseeventhandle = addmouseevents!(scene) setfield!(ax, :mouseeventhandle, mouseeventhandle) scrollevents = Observable(ScrollEvent(0, 0)) @@ -60,7 +61,7 @@ function register_events!(ax, scene) return Consume(false) end - interactions = Dict{Symbol, Tuple{Bool, Any}}() + interactions = Dict{Symbol,Tuple{Bool,Any}}() setfield!(ax, :interactions, interactions) onany(process_axis_event, ax, mouseeventhandle.obs) @@ -79,11 +80,11 @@ function register_events!(ax, scene) end function update_axis_camera(camera::Camera, t, lims, xrev::Bool, yrev::Bool) - nearclip = -10_000f0 - farclip = 10_000f0 + nearclip = -10_000.0f0 + farclip = 10_000.0f0 # we are computing transformed camera position, so this isn't space dependent - tlims = Makie.apply_transform(t, lims) + tlims = Makie.apply_transform(t, lims) left, bottom = minimum(tlims) right, top = maximum(tlims) @@ -91,17 +92,23 @@ function update_axis_camera(camera::Camera, t, lims, xrev::Bool, yrev::Bool) leftright = xrev ? (right, left) : (left, right) bottomtop = yrev ? (top, bottom) : (bottom, top) - projection = Makie.orthographicprojection( - Float32, - leftright..., - bottomtop..., nearclip, farclip) + projection = Makie.orthographicprojection(Float32, leftright..., bottomtop..., nearclip, farclip) Makie.set_proj_view!(camera, projection, Makie.Mat4f(Makie.I)) return end - -function calculate_title_position(area, titlegap, subtitlegap, align, xaxisposition, xaxisprotrusion, _, ax, subtitlet) +function calculate_title_position( + area, + titlegap, + subtitlegap, + align, + xaxisposition, + xaxisprotrusion, + _, + ax, + subtitlet, +) local x::Float32 = if align === :center area.origin[1] + area.widths[1] / 2 elseif align === :left @@ -115,22 +122,39 @@ function calculate_title_position(area, titlegap, subtitlegap, align, xaxisposit local subtitlespace::Float32 = if ax.subtitlevisible[] && !iswhitespace(ax.subtitle[]) boundingbox(subtitlet).widths[2] + subtitlegap else - 0f0 + 0.0f0 end - local yoffset::Float32 = top(area) + titlegap + (xaxisposition === :top ? xaxisprotrusion : 0f0) + - subtitlespace + local yoffset::Float32 = + top(area) + titlegap + (xaxisposition === :top ? xaxisprotrusion : 0.0f0) + subtitlespace return Point2f(x, yoffset) end -function compute_protrusions(title, titlesize, titlegap, titlevisible, spinewidth, - topspinevisible, bottomspinevisible, leftspinevisible, rightspinevisible, - xaxisprotrusion, yaxisprotrusion, xaxisposition, yaxisposition, - subtitle, subtitlevisible, subtitlesize, subtitlegap, titlelineheight, subtitlelineheight, - subtitlet, titlet) - - local left::Float32, right::Float32, bottom::Float32, top::Float32 = 0f0, 0f0, 0f0, 0f0 +function compute_protrusions( + title, + titlesize, + titlegap, + titlevisible, + spinewidth, + topspinevisible, + bottomspinevisible, + leftspinevisible, + rightspinevisible, + xaxisprotrusion, + yaxisprotrusion, + xaxisposition, + yaxisposition, + subtitle, + subtitlevisible, + subtitlesize, + subtitlegap, + titlelineheight, + subtitlelineheight, + subtitlet, + titlet, +) + local left::Float32, right::Float32, bottom::Float32, top::Float32 = 0.0f0, 0.0f0, 0.0f0, 0.0f0 if xaxisposition === :bottom bottom = xaxisprotrusion @@ -142,12 +166,12 @@ function compute_protrusions(title, titlesize, titlegap, titlevisible, spinewidt subtitleheight = boundingbox(subtitlet).widths[2] + subtitlegap titlespace = if !titlevisible || iswhitespace(title) - 0f0 + 0.0f0 else titleheight end subtitlespace = if !subtitlevisible || iswhitespace(subtitle) - 0f0 + 0.0f0 else subtitleheight end @@ -163,14 +187,15 @@ function compute_protrusions(title, titlesize, titlegap, titlevisible, spinewidt return GridLayoutBase.RectSides{Float32}(left, right, bottom, top) end -function initialize_block!(ax::Axis; palette = nothing) - +function initialize_block!(ax::Axis; palette=nothing) topscene = ax.blockscene - decorations = Dict{Symbol, Any}() + decorations = Dict{Symbol,Any}() if palette === nothing - palette = haskey(topscene.theme, :palette) ? deepcopy(topscene.theme[:palette]) : copy(Makie.default_palettes) + palette = + haskey(topscene.theme, :palette) ? deepcopy(topscene.theme[:palette]) : + copy(Makie.default_palettes) end ax.palette = palette isa Attributes ? palette : Attributes(palette) @@ -186,7 +211,7 @@ function initialize_block!(ax::Axis; palette = nothing) # the first thing to do when setting a new scale is # resetting the limits because simply through expanding they might be invalid for log onany(ax.xscale, ax.yscale) do _, _ - reset_limits!(ax) + return reset_limits!(ax) end on(targetlimits) do lims @@ -196,7 +221,7 @@ function initialize_block!(ax::Axis; palette = nothing) # already shouldn't set invalid targetlimits (even if they could # theoretically be adjusted to fit somehow later?) # and this way we can error pretty early - validate_limits_for_scales(lims, ax.xscale[], ax.yscale[]) + return validate_limits_for_scales(lims, ax.xscale[], ax.yscale[]) end scenearea = sceneareanode!(ax.layoutobservables.computedbbox, finallimits, ax.aspect) @@ -206,7 +231,14 @@ function initialize_block!(ax::Axis; palette = nothing) # TODO: replace with mesh, however, CairoMakie needs a poly path for this signature # so it doesn't rasterize the scene - background = poly!(topscene, scenearea; color=ax.backgroundcolor, inspectable=false, shading=false, strokecolor=:transparent) + background = poly!( + topscene, + scenearea; + color=ax.backgroundcolor, + inspectable=false, + shading=false, + strokecolor=:transparent, + ) translate!(background, 0, 0, -100) decorations[:background] = background @@ -218,8 +250,13 @@ function initialize_block!(ax::Axis; palette = nothing) xgridnode = Observable(Point2f[]; ignore_equal_values=true) xgridlines = linesegments!( - topscene, xgridnode, linewidth = ax.xgridwidth, visible = ax.xgridvisible, - color = ax.xgridcolor, linestyle = ax.xgridstyle, inspectable = false + topscene, + xgridnode, + linewidth=ax.xgridwidth, + visible=ax.xgridvisible, + color=ax.xgridcolor, + linestyle=ax.xgridstyle, + inspectable=false, ) # put gridlines behind the zero plane so they don't overlay plots translate!(xgridlines, 0, 0, -10) @@ -227,8 +264,13 @@ function initialize_block!(ax::Axis; palette = nothing) xminorgridnode = Observable(Point2f[]; ignore_equal_values=true) xminorgridlines = linesegments!( - topscene, xminorgridnode, linewidth = ax.xminorgridwidth, visible = ax.xminorgridvisible, - color = ax.xminorgridcolor, linestyle = ax.xminorgridstyle, inspectable = false + topscene, + xminorgridnode, + linewidth=ax.xminorgridwidth, + visible=ax.xminorgridvisible, + color=ax.xminorgridcolor, + linestyle=ax.xminorgridstyle, + inspectable=false, ) # put gridlines behind the zero plane so they don't overlay plots translate!(xminorgridlines, 0, 0, -10) @@ -236,8 +278,13 @@ function initialize_block!(ax::Axis; palette = nothing) ygridnode = Observable(Point2f[]; ignore_equal_values=true) ygridlines = linesegments!( - topscene, ygridnode, linewidth = ax.ygridwidth, visible = ax.ygridvisible, - color = ax.ygridcolor, linestyle = ax.ygridstyle, inspectable = false + topscene, + ygridnode, + linewidth=ax.ygridwidth, + visible=ax.ygridvisible, + color=ax.ygridcolor, + linestyle=ax.ygridstyle, + inspectable=false, ) # put gridlines behind the zero plane so they don't overlay plots translate!(ygridlines, 0, 0, -10) @@ -245,8 +292,13 @@ function initialize_block!(ax::Axis; palette = nothing) yminorgridnode = Observable(Point2f[]; ignore_equal_values=true) yminorgridlines = linesegments!( - topscene, yminorgridnode, linewidth = ax.yminorgridwidth, visible = ax.yminorgridvisible, - color = ax.yminorgridcolor, linestyle = ax.yminorgridstyle, inspectable = false + topscene, + yminorgridnode, + linewidth=ax.yminorgridwidth, + visible=ax.yminorgridvisible, + color=ax.yminorgridcolor, + linestyle=ax.yminorgridstyle, + inspectable=false, ) # put gridlines behind the zero plane so they don't overlay plots translate!(yminorgridlines, 0, 0, -10) @@ -259,7 +311,14 @@ function initialize_block!(ax::Axis; palette = nothing) notify(ax.xscale) - onany(update_axis_camera, camera(scene), scene.transformation.transform_func, finallimits, ax.xreversed, ax.yreversed) + onany( + update_axis_camera, + camera(scene), + scene.transformation.transform_func, + finallimits, + ax.xreversed, + ax.yreversed, + ) xaxis_endpoints = lift(ax.xaxisposition, scene.px_area; ignore_equal_values=true) do xaxisposition, area if xaxisposition == :bottom @@ -281,148 +340,302 @@ function initialize_block!(ax::Axis; palette = nothing) end end - xaxis_flipped = lift(x->x == :top, ax.xaxisposition; ignore_equal_values=true) - yaxis_flipped = lift(x->x == :right, ax.yaxisposition; ignore_equal_values=true) - - xspinevisible = lift(xaxis_flipped, ax.bottomspinevisible, ax.topspinevisible; ignore_equal_values=true) do xflip, bv, tv - xflip ? tv : bv - end - xoppositespinevisible = lift(xaxis_flipped, ax.bottomspinevisible, ax.topspinevisible; ignore_equal_values=true) do xflip, bv, tv - xflip ? bv : tv - end - yspinevisible = lift(yaxis_flipped, ax.leftspinevisible, ax.rightspinevisible; ignore_equal_values=true) do yflip, lv, rv - yflip ? rv : lv - end - yoppositespinevisible = lift(yaxis_flipped, ax.leftspinevisible, ax.rightspinevisible; ignore_equal_values=true) do yflip, lv, rv - yflip ? lv : rv - end - xspinecolor = lift(xaxis_flipped, ax.bottomspinecolor, ax.topspinecolor; ignore_equal_values=true) do xflip, bc, tc - xflip ? tc : bc - end - xoppositespinecolor = lift(xaxis_flipped, ax.bottomspinecolor, ax.topspinecolor; ignore_equal_values=true) do xflip, bc, tc - xflip ? bc : tc - end - yspinecolor = lift(yaxis_flipped, ax.leftspinecolor, ax.rightspinecolor; ignore_equal_values=true) do yflip, lc, rc - yflip ? rc : lc - end - yoppositespinecolor = lift(yaxis_flipped, ax.leftspinecolor, ax.rightspinecolor; ignore_equal_values=true) do yflip, lc, rc - yflip ? lc : rc - end + xaxis_flipped = lift(x -> x == :top, ax.xaxisposition; ignore_equal_values=true) + yaxis_flipped = lift(x -> x == :right, ax.yaxisposition; ignore_equal_values=true) + + xspinevisible = lift( + xaxis_flipped, + ax.bottomspinevisible, + ax.topspinevisible; + ignore_equal_values=true, + ) do xflip, bv, tv + return xflip ? tv : bv + end + xoppositespinevisible = lift( + xaxis_flipped, + ax.bottomspinevisible, + ax.topspinevisible; + ignore_equal_values=true, + ) do xflip, bv, tv + return xflip ? bv : tv + end + yspinevisible = lift( + yaxis_flipped, + ax.leftspinevisible, + ax.rightspinevisible; + ignore_equal_values=true, + ) do yflip, lv, rv + return yflip ? rv : lv + end + yoppositespinevisible = lift( + yaxis_flipped, + ax.leftspinevisible, + ax.rightspinevisible; + ignore_equal_values=true, + ) do yflip, lv, rv + return yflip ? lv : rv + end + xspinecolor = + lift(xaxis_flipped, ax.bottomspinecolor, ax.topspinecolor; ignore_equal_values=true) do xflip, bc, tc + return xflip ? tc : bc + end + xoppositespinecolor = + lift(xaxis_flipped, ax.bottomspinecolor, ax.topspinecolor; ignore_equal_values=true) do xflip, bc, tc + return xflip ? bc : tc + end + yspinecolor = + lift(yaxis_flipped, ax.leftspinecolor, ax.rightspinecolor; ignore_equal_values=true) do yflip, lc, rc + return yflip ? rc : lc + end + yoppositespinecolor = + lift(yaxis_flipped, ax.leftspinecolor, ax.rightspinecolor; ignore_equal_values=true) do yflip, lc, rc + return yflip ? lc : rc + end xlims = lift(xlimits, finallimits; ignore_equal_values=true) ylims = lift(ylimits, finallimits; ignore_equal_values=true) - xaxis = LineAxis(topscene, endpoints = xaxis_endpoints, limits = xlims, - flipped = xaxis_flipped, ticklabelrotation = ax.xticklabelrotation, - ticklabelalign = ax.xticklabelalign, labelsize = ax.xlabelsize, - labelpadding = ax.xlabelpadding, ticklabelpad = ax.xticklabelpad, labelvisible = ax.xlabelvisible, - label = ax.xlabel, labelfont = ax.xlabelfont, labelrotation = ax.xlabelrotation, ticklabelfont = ax.xticklabelfont, ticklabelcolor = ax.xticklabelcolor, labelcolor = ax.xlabelcolor, tickalign = ax.xtickalign, - ticklabelspace = ax.xticklabelspace, ticks = ax.xticks, tickformat = ax.xtickformat, ticklabelsvisible = ax.xticklabelsvisible, - ticksvisible = ax.xticksvisible, spinevisible = xspinevisible, spinecolor = xspinecolor, spinewidth = ax.spinewidth, - ticklabelsize = ax.xticklabelsize, trimspine = ax.xtrimspine, ticksize = ax.xticksize, - reversed = ax.xreversed, tickwidth = ax.xtickwidth, tickcolor = ax.xtickcolor, - minorticksvisible = ax.xminorticksvisible, minortickalign = ax.xminortickalign, minorticksize = ax.xminorticksize, minortickwidth = ax.xminortickwidth, minortickcolor = ax.xminortickcolor, minorticks = ax.xminorticks, scale = ax.xscale, - ) + xaxis = LineAxis( + topscene, + endpoints=xaxis_endpoints, + limits=xlims, + flipped=xaxis_flipped, + ticklabelrotation=ax.xticklabelrotation, + ticklabelalign=ax.xticklabelalign, + labelsize=ax.xlabelsize, + labelpadding=ax.xlabelpadding, + ticklabelpad=ax.xticklabelpad, + labelvisible=ax.xlabelvisible, + label=ax.xlabel, + labelfont=ax.xlabelfont, + labelrotation=ax.xlabelrotation, + ticklabelfont=ax.xticklabelfont, + ticklabelcolor=ax.xticklabelcolor, + labelcolor=ax.xlabelcolor, + tickalign=ax.xtickalign, + ticklabelspace=ax.xticklabelspace, + ticks=ax.xticks, + tickformat=ax.xtickformat, + ticklabelsvisible=ax.xticklabelsvisible, + ticksvisible=ax.xticksvisible, + spinevisible=xspinevisible, + spinecolor=xspinecolor, + spinewidth=ax.spinewidth, + ticklabelsize=ax.xticklabelsize, + trimspine=ax.xtrimspine, + ticksize=ax.xticksize, + reversed=ax.xreversed, + tickwidth=ax.xtickwidth, + tickcolor=ax.xtickcolor, + minorticksvisible=ax.xminorticksvisible, + minortickalign=ax.xminortickalign, + minorticksize=ax.xminorticksize, + minortickwidth=ax.xminortickwidth, + minortickcolor=ax.xminortickcolor, + minorticks=ax.xminorticks, + scale=ax.xscale, + ) ax.xaxis = xaxis - yaxis = LineAxis(topscene, endpoints = yaxis_endpoints, limits = ylims, - flipped = yaxis_flipped, ticklabelrotation = ax.yticklabelrotation, - ticklabelalign = ax.yticklabelalign, labelsize = ax.ylabelsize, - labelpadding = ax.ylabelpadding, ticklabelpad = ax.yticklabelpad, labelvisible = ax.ylabelvisible, - label = ax.ylabel, labelfont = ax.ylabelfont, labelrotation = ax.ylabelrotation, ticklabelfont = ax.yticklabelfont, ticklabelcolor = ax.yticklabelcolor, labelcolor = ax.ylabelcolor, tickalign = ax.ytickalign, - ticklabelspace = ax.yticklabelspace, ticks = ax.yticks, tickformat = ax.ytickformat, ticklabelsvisible = ax.yticklabelsvisible, - ticksvisible = ax.yticksvisible, spinevisible = yspinevisible, spinecolor = yspinecolor, spinewidth = ax.spinewidth, - trimspine = ax.ytrimspine, ticklabelsize = ax.yticklabelsize, ticksize = ax.yticksize, flip_vertical_label = ax.flip_ylabel, reversed = ax.yreversed, tickwidth = ax.ytickwidth, - tickcolor = ax.ytickcolor, - minorticksvisible = ax.yminorticksvisible, minortickalign = ax.yminortickalign, minorticksize = ax.yminorticksize, minortickwidth = ax.yminortickwidth, minortickcolor = ax.yminortickcolor, minorticks = ax.yminorticks, scale = ax.yscale, - ) + yaxis = LineAxis( + topscene, + endpoints=yaxis_endpoints, + limits=ylims, + flipped=yaxis_flipped, + ticklabelrotation=ax.yticklabelrotation, + ticklabelalign=ax.yticklabelalign, + labelsize=ax.ylabelsize, + labelpadding=ax.ylabelpadding, + ticklabelpad=ax.yticklabelpad, + labelvisible=ax.ylabelvisible, + label=ax.ylabel, + labelfont=ax.ylabelfont, + labelrotation=ax.ylabelrotation, + ticklabelfont=ax.yticklabelfont, + ticklabelcolor=ax.yticklabelcolor, + labelcolor=ax.ylabelcolor, + tickalign=ax.ytickalign, + ticklabelspace=ax.yticklabelspace, + ticks=ax.yticks, + tickformat=ax.ytickformat, + ticklabelsvisible=ax.yticklabelsvisible, + ticksvisible=ax.yticksvisible, + spinevisible=yspinevisible, + spinecolor=yspinecolor, + spinewidth=ax.spinewidth, + trimspine=ax.ytrimspine, + ticklabelsize=ax.yticklabelsize, + ticksize=ax.yticksize, + flip_vertical_label=ax.flip_ylabel, + reversed=ax.yreversed, + tickwidth=ax.ytickwidth, + tickcolor=ax.ytickcolor, + minorticksvisible=ax.yminorticksvisible, + minortickalign=ax.yminortickalign, + minorticksize=ax.yminorticksize, + minortickwidth=ax.yminortickwidth, + minortickcolor=ax.yminortickcolor, + minorticks=ax.yminorticks, + scale=ax.yscale, + ) ax.yaxis = yaxis - xoppositelinepoints = lift(scene.px_area, ax.spinewidth, ax.xaxisposition; ignore_equal_values=true) do r, sw, xaxpos - if xaxpos == :top - y = bottom(r) - p1 = Point2f(left(r) - 0.5sw, y) - p2 = Point2f(right(r) + 0.5sw, y) - return [p1, p2] - else - y = top(r) - p1 = Point2f(left(r) - 0.5sw, y) - p2 = Point2f(right(r) + 0.5sw, y) - return [p1, p2] + xoppositelinepoints = + lift(scene.px_area, ax.spinewidth, ax.xaxisposition; ignore_equal_values=true) do r, sw, xaxpos + if xaxpos == :top + y = bottom(r) + p1 = Point2f(left(r) - 0.5sw, y) + p2 = Point2f(right(r) + 0.5sw, y) + return [p1, p2] + else + y = top(r) + p1 = Point2f(left(r) - 0.5sw, y) + p2 = Point2f(right(r) + 0.5sw, y) + return [p1, p2] + end end - end - yoppositelinepoints = lift(scene.px_area, ax.spinewidth, ax.yaxisposition; ignore_equal_values=true) do r, sw, yaxpos - if yaxpos == :right - x = left(r) - p1 = Point2f(x, bottom(r) - 0.5sw) - p2 = Point2f(x, top(r) + 0.5sw) - return [p1, p2] - else - x = right(r) - p1 = Point2f(x, bottom(r) - 0.5sw) - p2 = Point2f(x, top(r) + 0.5sw) - return [p1, p2] + yoppositelinepoints = + lift(scene.px_area, ax.spinewidth, ax.yaxisposition; ignore_equal_values=true) do r, sw, yaxpos + if yaxpos == :right + x = left(r) + p1 = Point2f(x, bottom(r) - 0.5sw) + p2 = Point2f(x, top(r) + 0.5sw) + return [p1, p2] + else + x = right(r) + p1 = Point2f(x, bottom(r) - 0.5sw) + p2 = Point2f(x, top(r) + 0.5sw) + return [p1, p2] + end end - end - xticksmirrored = lift(mirror_ticks, xaxis.tickpositions, ax.xticksize, ax.xtickalign, Ref(scene.px_area), :x, ax.xaxisposition[]) - xticksmirrored_lines = linesegments!(topscene, xticksmirrored, visible = @lift($(ax.xticksmirrored) && $(ax.xticksvisible)), - linewidth = ax.xtickwidth, color = ax.xtickcolor) + xticksmirrored = lift( + mirror_ticks, + xaxis.tickpositions, + ax.xticksize, + ax.xtickalign, + Ref(scene.px_area), + :x, + ax.xaxisposition[], + ) + xticksmirrored_lines = linesegments!( + topscene, + xticksmirrored, + visible=@lift($(ax.xticksmirrored) && $(ax.xticksvisible)), + linewidth=ax.xtickwidth, + color=ax.xtickcolor, + ) translate!(xticksmirrored_lines, 0, 0, 10) - yticksmirrored = lift(mirror_ticks, yaxis.tickpositions, ax.yticksize, ax.ytickalign, Ref(scene.px_area), :y, ax.yaxisposition[]) - yticksmirrored_lines = linesegments!(topscene, yticksmirrored, visible = @lift($(ax.yticksmirrored) && $(ax.yticksvisible)), - linewidth = ax.ytickwidth, color = ax.ytickcolor) + yticksmirrored = lift( + mirror_ticks, + yaxis.tickpositions, + ax.yticksize, + ax.ytickalign, + Ref(scene.px_area), + :y, + ax.yaxisposition[], + ) + yticksmirrored_lines = linesegments!( + topscene, + yticksmirrored, + visible=@lift($(ax.yticksmirrored) && $(ax.yticksvisible)), + linewidth=ax.ytickwidth, + color=ax.ytickcolor, + ) translate!(yticksmirrored_lines, 0, 0, 10) - xminorticksmirrored = lift(mirror_ticks, xaxis.minortickpositions, ax.xminorticksize, ax.xminortickalign, Ref(scene.px_area), :x, ax.xaxisposition[]) - xminorticksmirrored_lines = linesegments!(topscene, xminorticksmirrored, visible = @lift($(ax.xticksmirrored) && $(ax.xminorticksvisible)), - linewidth = ax.xminortickwidth, color = ax.xminortickcolor) + xminorticksmirrored = lift( + mirror_ticks, + xaxis.minortickpositions, + ax.xminorticksize, + ax.xminortickalign, + Ref(scene.px_area), + :x, + ax.xaxisposition[], + ) + xminorticksmirrored_lines = linesegments!( + topscene, + xminorticksmirrored, + visible=@lift($(ax.xticksmirrored) && $(ax.xminorticksvisible)), + linewidth=ax.xminortickwidth, + color=ax.xminortickcolor, + ) translate!(xminorticksmirrored_lines, 0, 0, 10) - yminorticksmirrored = lift(mirror_ticks, yaxis.minortickpositions, ax.yminorticksize, ax.yminortickalign, Ref(scene.px_area), :y, ax.yaxisposition[]) - yminorticksmirrored_lines = linesegments!(topscene, yminorticksmirrored, visible = @lift($(ax.yticksmirrored) && $(ax.yminorticksvisible)), - linewidth = ax.yminortickwidth, color = ax.yminortickcolor) + yminorticksmirrored = lift( + mirror_ticks, + yaxis.minortickpositions, + ax.yminorticksize, + ax.yminortickalign, + Ref(scene.px_area), + :y, + ax.yaxisposition[], + ) + yminorticksmirrored_lines = linesegments!( + topscene, + yminorticksmirrored, + visible=@lift($(ax.yticksmirrored) && $(ax.yminorticksvisible)), + linewidth=ax.yminortickwidth, + color=ax.yminortickcolor, + ) translate!(yminorticksmirrored_lines, 0, 0, 10) - xoppositeline = linesegments!(topscene, xoppositelinepoints, linewidth = ax.spinewidth, - visible = xoppositespinevisible, color = xoppositespinecolor, inspectable = false, - linestyle = nothing) + xoppositeline = linesegments!( + topscene, + xoppositelinepoints, + linewidth=ax.spinewidth, + visible=xoppositespinevisible, + color=xoppositespinecolor, + inspectable=false, + linestyle=nothing, + ) decorations[:xoppositeline] = xoppositeline translate!(xoppositeline, 0, 0, 20) - yoppositeline = linesegments!(topscene, yoppositelinepoints, linewidth = ax.spinewidth, - visible = yoppositespinevisible, color = yoppositespinecolor, inspectable = false, - linestyle = nothing) + yoppositeline = linesegments!( + topscene, + yoppositelinepoints, + linewidth=ax.spinewidth, + visible=yoppositespinevisible, + color=yoppositespinecolor, + inspectable=false, + linestyle=nothing, + ) decorations[:yoppositeline] = yoppositeline translate!(yoppositeline, 0, 0, 20) onany(xaxis.tickpositions, scene.px_area) do tickpos, area local pxheight::Float32 = height(area) local offset::Float32 = ax.xaxisposition[] === :bottom ? pxheight : -pxheight - update_gridlines!(xgridnode, Point2f(0, offset), tickpos) + return update_gridlines!(xgridnode, Point2f(0, offset), tickpos) end onany(yaxis.tickpositions, scene.px_area) do tickpos, area local pxwidth::Float32 = width(area) local offset::Float32 = ax.yaxisposition[] === :left ? pxwidth : -pxwidth - update_gridlines!(ygridnode, Point2f(offset, 0), tickpos) + return update_gridlines!(ygridnode, Point2f(offset, 0), tickpos) end onany(xaxis.minortickpositions, scene.px_area) do tickpos, area local pxheight::Float32 = height(scene.px_area[]) local offset::Float32 = ax.xaxisposition[] == :bottom ? pxheight : -pxheight - update_gridlines!(xminorgridnode, Point2f(0, offset), tickpos) + return update_gridlines!(xminorgridnode, Point2f(0, offset), tickpos) end onany(yaxis.minortickpositions, scene.px_area) do tickpos, area local pxwidth::Float32 = width(scene.px_area[]) local offset::Float32 = ax.yaxisposition[] == :left ? pxwidth : -pxwidth - update_gridlines!(yminorgridnode, Point2f(offset, 0), tickpos) + return update_gridlines!(yminorgridnode, Point2f(offset, 0), tickpos) end - subtitlepos = lift(scene.px_area, ax.titlegap, ax.titlealign, ax.xaxisposition, xaxis.protrusion; ignore_equal_values=true) do a, - titlegap, align, xaxisposition, xaxisprotrusion - + subtitlepos = lift( + scene.px_area, + ax.titlegap, + ax.titlealign, + ax.xaxisposition, + xaxis.protrusion; + ignore_equal_values=true, + ) do a, titlegap, align, xaxisposition, xaxisprotrusion x = if align == :center a.origin[1] + a.widths[1] / 2 elseif align == :left @@ -433,48 +646,83 @@ function initialize_block!(ax::Axis; palette = nothing) error("Title align $align not supported.") end - yoffset = top(a) + titlegap + (xaxisposition == :top ? xaxisprotrusion : 0f0) + yoffset = top(a) + titlegap + (xaxisposition == :top ? xaxisprotrusion : 0.0f0) return Point2f(x, yoffset) end titlealignnode = lift(ax.titlealign; ignore_equal_values=true) do align - (align, :bottom) + return (align, :bottom) end subtitlet = text!( - topscene, subtitlepos, - text = ax.subtitle, - visible = ax.subtitlevisible, - fontsize = ax.subtitlesize, - align = titlealignnode, - font = ax.subtitlefont, - color = ax.subtitlecolor, - lineheight = ax.subtitlelineheight, - markerspace = :data, - inspectable = false) - - titlepos = lift(calculate_title_position, scene.px_area, ax.titlegap, ax.subtitlegap, - ax.titlealign, ax.xaxisposition, xaxis.protrusion, ax.subtitlelineheight, ax, subtitlet; ignore_equal_values=true) + topscene, + subtitlepos, + text=ax.subtitle, + visible=ax.subtitlevisible, + fontsize=ax.subtitlesize, + align=titlealignnode, + font=ax.subtitlefont, + color=ax.subtitlecolor, + lineheight=ax.subtitlelineheight, + markerspace=:data, + inspectable=false, + ) + + titlepos = lift( + calculate_title_position, + scene.px_area, + ax.titlegap, + ax.subtitlegap, + ax.titlealign, + ax.xaxisposition, + xaxis.protrusion, + ax.subtitlelineheight, + ax, + subtitlet; + ignore_equal_values=true, + ) titlet = text!( - topscene, titlepos, - text = ax.title, - visible = ax.titlevisible, - fontsize = ax.titlesize, - align = titlealignnode, - font = ax.titlefont, - color = ax.titlecolor, - lineheight = ax.titlelineheight, - markerspace = :data, - inspectable = false) + topscene, + titlepos, + text=ax.title, + visible=ax.titlevisible, + fontsize=ax.titlesize, + align=titlealignnode, + font=ax.titlefont, + color=ax.titlecolor, + lineheight=ax.titlelineheight, + markerspace=:data, + inspectable=false, + ) decorations[:title] = titlet - map!(compute_protrusions, ax.layoutobservables.protrusions, ax.title, ax.titlesize, ax.titlegap, ax.titlevisible, ax.spinewidth, - ax.topspinevisible, ax.bottomspinevisible, ax.leftspinevisible, ax.rightspinevisible, - xaxis.protrusion, yaxis.protrusion, ax.xaxisposition, ax.yaxisposition, - ax.subtitle, ax.subtitlevisible, ax.subtitlesize, ax.subtitlegap, - ax.titlelineheight, ax.subtitlelineheight, subtitlet, titlet) + map!( + compute_protrusions, + ax.layoutobservables.protrusions, + ax.title, + ax.titlesize, + ax.titlegap, + ax.titlevisible, + ax.spinewidth, + ax.topspinevisible, + ax.bottomspinevisible, + ax.leftspinevisible, + ax.rightspinevisible, + xaxis.protrusion, + yaxis.protrusion, + ax.xaxisposition, + ax.yaxisposition, + ax.subtitle, + ax.subtitlevisible, + ax.subtitlesize, + ax.subtitlegap, + ax.titlelineheight, + ax.subtitlelineheight, + subtitlet, + titlet, + ) # trigger first protrusions with one of the observables notify(ax.title) @@ -486,18 +734,18 @@ function initialize_block!(ax::Axis; palette = nothing) # these are the user defined limits on(ax.limits) do mlims - reset_limits!(ax) + return reset_limits!(ax) end # these are the limits that we try to target, but they can be changed for correct aspects on(targetlimits) do tlims - update_linked_limits!(block_limit_linking, ax.xaxislinks, ax.yaxislinks, tlims) + return update_linked_limits!(block_limit_linking, ax.xaxislinks, ax.yaxislinks, tlims) end # compute limits that adhere to the limit aspect ratio whenever the targeted # limits or the scene size change, because both influence the displayed ratio onany(scene.px_area, targetlimits) do pxa, lims - adjustlimits!(ax) + return adjustlimits!(ax) end # trigger limit pipeline once, with manual finallimits if they haven't changed from @@ -516,21 +764,21 @@ function mirror_ticks(tickpositions, ticksize, tickalign, px_area, side, axispos a = px_area[][] if side == :x opp = axisposition == :bottom ? top(a) : bottom(a) - sign = axisposition == :bottom ? 1 : -1 + sign = axisposition == :bottom ? 1 : -1 else opp = axisposition == :left ? right(a) : left(a) sign = axisposition == :left ? 1 : -1 end d = ticksize * sign - points = Vector{Point2f}(undef, 2*length(tickpositions)) + points = Vector{Point2f}(undef, 2 * length(tickpositions)) if side == :x for (i, (x, _)) in enumerate(tickpositions) - points[2i-1] = Point2f(x, opp - d * tickalign) + points[2i - 1] = Point2f(x, opp - d * tickalign) points[2i] = Point2f(x, opp + d - d * tickalign) end else for (i, (_, y)) in enumerate(tickpositions) - points[2i-1] = Point2f(opp - d * tickalign, y) + points[2i - 1] = Point2f(opp - d * tickalign, y) points[2i] = Point2f(opp + d - d * tickalign, y) end end @@ -546,13 +794,13 @@ that value is either copied from the targetlimits if `xauto` or `yauto` is false respectively, or it is determined automatically from the plots in the axis. If one of the components is a tuple of two numbers, those are used directly. """ -function reset_limits!(ax; xauto = true, yauto = true, zauto = true) +function reset_limits!(ax; xauto=true, yauto=true, zauto=true) mlims = convert_limit_attribute(ax.limits[]) if ax isa Axis - mxlims, mylims = mlims::Tuple{Any, Any} + mxlims, mylims = mlims::Tuple{Any,Any} elseif ax isa Axis3 - mxlims, mylims, mzlims = mlims::Tuple{Any, Any, Any} + mxlims, mylims, mzlims = mlims::Tuple{Any,Any,Any} else error() end @@ -571,7 +819,7 @@ function reset_limits!(ax; xauto = true, yauto = true, zauto = true) (lo, hi) end else - convert(Tuple{Float32, Float32}, tuple(mxlims...)) + convert(Tuple{Float32,Float32}, tuple(mxlims...)) end ylims = if isnothing(mylims) || mylims[1] === nothing || mylims[2] === nothing l = if yauto @@ -587,7 +835,7 @@ function reset_limits!(ax; xauto = true, yauto = true, zauto = true) (lo, hi) end else - convert(Tuple{Float32, Float32}, tuple(mylims...)) + convert(Tuple{Float32,Float32}, tuple(mylims...)) end if ax isa Axis3 @@ -605,7 +853,7 @@ function reset_limits!(ax; xauto = true, yauto = true, zauto = true) (lo, hi) end else - convert(Tuple{Float32, Float32}, tuple(mzlims...)) + convert(Tuple{Float32,Float32}, tuple(mzlims...)) end end @@ -629,17 +877,13 @@ function reset_limits!(ax; xauto = true, yauto = true, zauto = true) Vec3f(xlims[2] - xlims[1], ylims[2] - ylims[1], zlims[2] - zlims[1]), ) end - nothing + return nothing end # this is so users can do limits = (left, right, bottom, top) -function convert_limit_attribute(lims::Tuple{Any, Any, Any, Any}) - (lims[1:2], lims[3:4]) -end +convert_limit_attribute(lims::Tuple{Any,Any,Any,Any}) = (lims[1:2], lims[3:4]) -function convert_limit_attribute(lims::Tuple{Any, Any}) - lims -end +convert_limit_attribute(lims::Tuple{Any,Any}) = lims can_be_current_axis(ax::Axis) = true function validate_limits_for_scales(lims::Rect, xsc, ysc) @@ -649,12 +893,16 @@ function validate_limits_for_scales(lims::Rect, xsc, ysc) ylims = (mi[2], ma[2]) if !validate_limits_for_scale(xlims, xsc) - error("Invalid x-limits $xlims for scale $xsc which is defined on the interval $(defined_interval(xsc))") + error( + "Invalid x-limits $xlims for scale $xsc which is defined on the interval $(defined_interval(xsc))", + ) end if !validate_limits_for_scale(ylims, ysc) - error("Invalid y-limits $ylims for scale $ysc which is defined on the interval $(defined_interval(ysc))") + error( + "Invalid y-limits $ylims for scale $ysc which is defined on the interval $(defined_interval(ysc))", + ) end - nothing + return nothing end validate_limits_for_scale(lims, scale) = all(x -> x in defined_interval(scale), lims) @@ -662,13 +910,12 @@ validate_limits_for_scale(lims, scale) = all(x -> x in defined_interval(scale), palettesyms(cycle::Cycle) = [c[2] for c in cycle.cycle] attrsyms(cycle::Cycle) = [c[1] for c in cycle.cycle] -function get_cycler_index!(c::Cycler, P::Type) +get_cycler_index!(c::Cycler, P::Type) = if !haskey(c.counters, P) c.counters[P] = 1 else c.counters[P] += 1 end -end function get_cycle_for_plottype(allattrs, P)::Cycle psym = MakieCore.plotsym(P) @@ -698,14 +945,14 @@ function add_cycle_attributes!(allattrs, P, cycle::Cycle, cycler::Cycler, palett # were passed manually, because we don't use the cycler # if any of the cycled attributes were specified manually no_cycle_attribute_passed = !any(keys(allattrs)) do key - any(syms -> key in syms, attrsyms(cycle)) + return any(syms -> key in syms, attrsyms(cycle)) end # check if any attributes were passed as `Cycled` entries # because if there were any, these are looked up directly # in the cycler without advancing the counter etc. manually_cycled_attributes = filter(keys(allattrs)) do key - to_value(allattrs[key]) isa Cycled + return to_value(allattrs[key]) isa Cycled end # if there are any manually cycled attributes, we don't do the normal @@ -716,7 +963,9 @@ function add_cycle_attributes!(allattrs, P, cycle::Cycle, cycler::Cycler, palett # otherwise there's no cycle in which to look up a value for k in manually_cycled_attributes if !any(x -> k in x, cycle_attrsyms) - error("Attribute `$k` was passed with an explicit `Cycled` value, but $k is not specified in the cycler for this plot type $P.") + error( + "Attribute `$k` was passed with an explicit `Cycled` value, but $k is not specified in the cycler for this plot type $P.", + ) end end @@ -759,11 +1008,7 @@ function add_cycle_attributes!(allattrs, P, cycle::Cycle, cycler::Cycler, palett end end -function Makie.plot!( - la::Axis, P::Makie.PlotFunc, - attributes::Makie.Attributes, args...; - kw_attributes...) - +function Makie.plot!(la::Axis, P::Makie.PlotFunc, attributes::Makie.Attributes, args...; kw_attributes...) allattrs = merge(attributes, Attributes(kw_attributes)) _disallow_keyword(:axis, allattrs) @@ -781,7 +1026,7 @@ function Makie.plot!( if is_open_or_any_parent(la.scene) reset_limits!(la) end - plot + return plot end is_open_or_any_parent(s::Scene) = isopen(s) || is_open_or_any_parent(s.parent) @@ -789,11 +1034,11 @@ is_open_or_any_parent(::Nothing) = false function Makie.plot!(P::Makie.PlotFunc, ax::Axis, args...; kw_attributes...) attributes = Makie.Attributes(kw_attributes) - Makie.plot!(ax, P, attributes, args...) + return Makie.plot!(ax, P, attributes, args...) end needs_tight_limits(@nospecialize any) = false -needs_tight_limits(::Union{Heatmap, Image}) = true +needs_tight_limits(::Union{Heatmap,Image}) = true function needs_tight_limits(c::Contourf) # we know that all values are included and the contourf is rectangular # otherwise here it could be in an arbitrary shape @@ -801,7 +1046,7 @@ function needs_tight_limits(c::Contourf) end function expandbboxwithfractionalmargins(bb, margins) - newwidths = bb.widths .* (1f0 .+ margins) + newwidths = bb.widths .* (1.0f0 .+ margins) diffs = newwidths .- bb.widths neworigin = bb.origin .- (0.5f0 .* diffs) return Rect2f(neworigin, newwidths) @@ -836,7 +1081,7 @@ function expandlimits(lims, margin_low, margin_high, scale) lims = inverse.(scale.(lims) .+ (-zerodist, zerodist)) end end - lims + return lims end function getlimits(la::Axis, dim) @@ -868,14 +1113,12 @@ getxlimits(la::Axis) = getlimits(la, 1) getylimits(la::Axis) = getlimits(la, 2) function update_linked_limits!(block_limit_linking, xaxislinks, yaxislinks, tlims) - thisxlims = xlimits(tlims) thisylims = ylimits(tlims) # only change linked axis if not prohibited from doing so because # we're currently being updated by another axis' link if !block_limit_linking[] - bothlinks = intersect(xaxislinks, yaxislinks) xlinks = setdiff(xaxislinks, yaxislinks) ylinks = setdiff(yaxislinks, xaxislinks) @@ -944,7 +1187,9 @@ function autolimits(ax::Axis, dim::Integer) margin = getproperty(ax, Symbol(dimsym, :autolimitmargin))[] if !isnothing(lims) if !validate_limits_for_scale(lims, scale) - error("Found invalid x-limits $lims for scale $(scale) which is defined on the interval $(defined_interval(scale))") + error( + "Found invalid x-limits $lims for scale $(scale) which is defined on the interval $(defined_interval(scale))", + ) end lims = expandlimits(lims, margin[1], margin[2], scale) end @@ -966,7 +1211,7 @@ Link both x and y axes of all given `Axis` so that they stay synchronized. """ function linkaxes!(a::Axis, others...) linkxaxes!(a, others...) - linkyaxes!(a, others...) + return linkyaxes!(a, others...) end function adjustlimits!(la) @@ -1018,7 +1263,7 @@ function adjustlimits!(la) return end -function linkaxes!(dir::Union{Val{:x}, Val{:y}}, a::Axis, others...) +function linkaxes!(dir::Union{Val{:x},Val{:y}}, a::Axis, others...) axes = Axis[a; others...] all_links = Set{Axis}(axes) @@ -1037,7 +1282,7 @@ function linkaxes!(dir::Union{Val{:x}, Val{:y}}, a::Axis, others...) end end end - reset_limits!(a) + return reset_limits!(a) end """ @@ -1060,9 +1305,13 @@ value. If that value is Makie.automatic, the reset will trigger new protrusions for the axis and the layout will adjust. This is so the layout doesn't immediately readjust during interaction, which would let the whole layout jitter around. """ -function timed_ticklabelspace_reset(ax::Axis, reset_timer::Ref, - prev_xticklabelspace::Ref, prev_yticklabelspace::Ref, threshold_sec::Real) - +function timed_ticklabelspace_reset( + ax::Axis, + reset_timer::Ref, + prev_xticklabelspace::Ref, + prev_yticklabelspace::Ref, + threshold_sec::Real, +) if !isnothing(reset_timer[]) close(reset_timer[]) else @@ -1077,20 +1326,25 @@ function timed_ticklabelspace_reset(ax::Axis, reset_timer::Ref, reset_timer[] = nothing ax.xticklabelspace = prev_xticklabelspace[] - ax.yticklabelspace = prev_yticklabelspace[] + return ax.yticklabelspace = prev_yticklabelspace[] end - end - """ hidexdecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, minorgrid = true, minorticks = true) Hide decorations of the x-axis: label, ticklabels, ticks and grid. """ -function hidexdecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, - minorgrid = true, minorticks = true) +function hidexdecorations!( + la::Axis; + label=true, + ticklabels=true, + ticks=true, + grid=true, + minorgrid=true, + minorticks=true, +) if label la.xlabelvisible = false end @@ -1117,8 +1371,15 @@ end Hide decorations of the y-axis: label, ticklabels, ticks and grid. """ -function hideydecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, - minorgrid = true, minorticks = true) +function hideydecorations!( + la::Axis; + label=true, + ticklabels=true, + ticks=true, + grid=true, + minorgrid=true, + minorticks=true, +) if label la.ylabelvisible = false end @@ -1144,12 +1405,33 @@ end Hide decorations of both x and y-axis: label, ticklabels, ticks and grid. """ -function hidedecorations!(la::Axis; label = true, ticklabels = true, ticks = true, grid = true, - minorgrid = true, minorticks = true) - hidexdecorations!(la; label = label, ticklabels = ticklabels, ticks = ticks, grid = grid, - minorgrid = minorgrid, minorticks = minorticks) - hideydecorations!(la; label = label, ticklabels = ticklabels, ticks = ticks, grid = grid, - minorgrid = minorgrid, minorticks = minorticks) +function hidedecorations!( + la::Axis; + label=true, + ticklabels=true, + ticks=true, + grid=true, + minorgrid=true, + minorticks=true, +) + hidexdecorations!( + la; + label=label, + ticklabels=ticklabels, + ticks=ticks, + grid=grid, + minorgrid=minorgrid, + minorticks=minorticks, + ) + return hideydecorations!( + la; + label=label, + ticklabels=ticklabels, + ticks=ticks, + grid=grid, + minorgrid=minorgrid, + minorticks=minorticks, + ) end """ @@ -1158,7 +1440,7 @@ end Hide all specified axis spines. Hides all spines by default, otherwise choose with the symbols :l, :r, :b and :t. """ -function hidespines!(la::Axis, spines::Symbol... = (:l, :r, :b, :t)...) +function hidespines!(la::Axis, spines::Symbol...=(:l, :r, :b, :t)...) for s in spines @match s begin :l => (la.leftspinevisible = false) @@ -1210,7 +1492,7 @@ end function Base.show(io::IO, ax::Axis) nplots = length(ax.scene.plots) - print(io, "Axis ($nplots plots)") + return print(io, "Axis ($nplots plots)") end function Makie.xlims!(ax::Axis, xlims) @@ -1226,8 +1508,8 @@ function Makie.xlims!(ax::Axis, xlims) end ax.limits.val = (xlims, ax.limits[][2]) - reset_limits!(ax, yauto = false) - nothing + reset_limits!(ax, yauto=false) + return nothing end function Makie.ylims!(ax::Axis, ylims) @@ -1243,8 +1525,8 @@ function Makie.ylims!(ax::Axis, ylims) end ax.limits.val = (ax.limits[][1], ylims) - reset_limits!(ax, xauto = false) - nothing + reset_limits!(ax, xauto=false) + return nothing end Makie.xlims!(ax, low, high) = Makie.xlims!(ax, (low, high)) @@ -1255,9 +1537,9 @@ Makie.xlims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.xlims!(curre Makie.ylims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.ylims!(current_axis(), low, high) Makie.zlims!(low::Optional{<:Real}, high::Optional{<:Real}) = Makie.zlims!(current_axis(), low, high) -Makie.xlims!(ax = current_axis(); low = nothing, high = nothing) = Makie.xlims!(ax, low, high) -Makie.ylims!(ax = current_axis(); low = nothing, high = nothing) = Makie.ylims!(ax, low, high) -Makie.zlims!(ax = current_axis(); low = nothing, high = nothing) = Makie.zlims!(ax, low, high) +Makie.xlims!(ax=current_axis(); low=nothing, high=nothing) = Makie.xlims!(ax, low, high) +Makie.ylims!(ax=current_axis(); low=nothing, high=nothing) = Makie.ylims!(ax, low, high) +Makie.zlims!(ax=current_axis(); low=nothing, high=nothing) = Makie.zlims!(ax, low, high) """ limits!(ax::Axis, xlims, ylims) @@ -1267,7 +1549,7 @@ If limits are ordered high-low, this reverses the axis orientation. """ function limits!(ax::Axis, xlims, ylims) Makie.xlims!(ax, xlims) - Makie.ylims!(ax, ylims) + return Makie.ylims!(ax, ylims) end """ @@ -1278,7 +1560,7 @@ If limits are ordered high-low, this reverses the axis orientation. """ function limits!(ax::Axis, x1, x2, y1, y2) Makie.xlims!(ax, x1, x2) - Makie.ylims!(ax, y1, y2) + return Makie.ylims!(ax, y1, y2) end """ @@ -1291,47 +1573,44 @@ function limits!(ax::Axis, rect::Rect2) xmin, ymin = minimum(rect) xmax, ymax = maximum(rect) Makie.xlims!(ax, xmin, xmax) - Makie.ylims!(ax, ymin, ymax) + return Makie.ylims!(ax, ymin, ymax) end -function limits!(args...) - limits!(current_axis(), args...) -end +limits!(args...) = limits!(current_axis(), args...) function Base.delete!(ax::Axis, plot::AbstractPlot) delete!(ax.scene, plot) - ax + return ax end function Base.empty!(ax::Axis) while !isempty(ax.scene.plots) delete!(ax, ax.scene.plots[end]) end - ax + return ax end Makie.transform_func(ax::Axis) = Makie.transform_func(ax.scene) # these functions pick limits for different x and y scales, so that # we don't pick values that are invalid, such as 0 for log etc. -function defaultlimits(userlimits::Tuple{Real, Real, Real, Real}, xscale, yscale) - BBox(userlimits...) -end +defaultlimits(userlimits::Tuple{Real,Real,Real,Real}, xscale, yscale) = BBox(userlimits...) -defaultlimits(l::Tuple{Any, Any, Any, Any}, xscale, yscale) = defaultlimits(((l[1], l[2]), (l[3], l[4])), xscale, yscale) +function defaultlimits(l::Tuple{Any,Any,Any,Any}, xscale, yscale) + return defaultlimits(((l[1], l[2]), (l[3], l[4])), xscale, yscale) +end -function defaultlimits(userlimits::Tuple{Any, Any}, xscale, yscale) +function defaultlimits(userlimits::Tuple{Any,Any}, xscale, yscale) xl = defaultlimits(userlimits[1], xscale) yl = defaultlimits(userlimits[2], yscale) - BBox(xl..., yl...) + return BBox(xl..., yl...) end defaultlimits(limits::Nothing, scale) = defaultlimits(scale) -defaultlimits(limits::Tuple{Real, Real}, scale) = limits -defaultlimits(limits::Tuple{Real, Nothing}, scale) = (limits[1], defaultlimits(scale)[2]) -defaultlimits(limits::Tuple{Nothing, Real}, scale) = (defaultlimits(scale)[1], limits[2]) -defaultlimits(limits::Tuple{Nothing, Nothing}, scale) = defaultlimits(scale) - +defaultlimits(limits::Tuple{Real,Real}, scale) = limits +defaultlimits(limits::Tuple{Real,Nothing}, scale) = (limits[1], defaultlimits(scale)[2]) +defaultlimits(limits::Tuple{Nothing,Real}, scale) = (defaultlimits(scale)[1], limits[2]) +defaultlimits(limits::Tuple{Nothing,Nothing}, scale) = defaultlimits(scale) defaultlimits(::typeof(log10)) = (1.0, 1000.0) defaultlimits(::typeof(log2)) = (1.0, 8.0) @@ -1343,7 +1622,7 @@ defaultlimits(::typeof(Makie.pseudolog10)) = (0.0, 100.0) defaultlimits(::Makie.Symlog10) = (0.0, 100.0) defined_interval(::typeof(identity)) = OpenInterval(-Inf, Inf) -defined_interval(::Union{typeof(log2), typeof(log10), typeof(log)}) = OpenInterval(0.0, Inf) +defined_interval(::Union{typeof(log2),typeof(log10),typeof(log)}) = OpenInterval(0.0, Inf) defined_interval(::typeof(sqrt)) = Interval{:closed,:open}(0, Inf) defined_interval(::typeof(Makie.logit)) = OpenInterval(0.0, 1.0) defined_interval(::typeof(Makie.pseudolog10)) = OpenInterval(-Inf, Inf) diff --git a/src/makielayout/blocks/axis3d.jl b/src/makielayout/blocks/axis3d.jl index bad81bdc8c8..763eef9cb39 100644 --- a/src/makielayout/blocks/axis3d.jl +++ b/src/makielayout/blocks/axis3d.jl @@ -1,30 +1,29 @@ struct OrthographicCamera <: AbstractCamera end function initialize_block!(ax::Axis3) - blockscene = ax.blockscene on(ax.protrusions) do prot - ax.layoutobservables.protrusions[] = to_protrusions(prot) + return ax.layoutobservables.protrusions[] = to_protrusions(prot) end notify(ax.protrusions) - finallimits = Observable(Rect3f(Vec3f(0f0, 0f0, 0f0), Vec3f(100f0, 100f0, 100f0))) + finallimits = Observable(Rect3f(Vec3f(0.0f0, 0.0f0, 0.0f0), Vec3f(100.0f0, 100.0f0, 100.0f0))) setfield!(ax, :finallimits, finallimits) scenearea = lift(round_to_IRect2D, ax.layoutobservables.computedbbox) - scene = Scene(blockscene, scenearea, clear = false, backgroundcolor = ax.backgroundcolor) + scene = Scene(blockscene, scenearea, clear=false, backgroundcolor=ax.backgroundcolor) ax.scene = scene cam = OrthographicCamera() cameracontrols!(scene, cam) - mi1 = Observable(!(pi/2 <= mod1(ax.azimuth[], 2pi) < 3pi/2)) + mi1 = Observable(!(pi / 2 <= mod1(ax.azimuth[], 2pi) < 3pi / 2)) mi2 = Observable(0 <= mod1(ax.azimuth[], 2pi) < pi) mi3 = Observable(ax.elevation[] > 0) on(ax.azimuth) do x - b = !(pi/2 <= mod1(x, 2pi) < 3pi/2) + b = !(pi / 2 <= mod1(x, 2pi) < 3pi / 2) mi1.val == b || (mi1[] = b) return end @@ -38,24 +37,33 @@ function initialize_block!(ax::Axis3) return end - matrices = lift(calculate_matrices, finallimits, scene.px_area, ax.elevation, ax.azimuth, ax.perspectiveness, ax.aspect, ax.viewmode) + matrices = lift( + calculate_matrices, + finallimits, + scene.px_area, + ax.elevation, + ax.azimuth, + ax.perspectiveness, + ax.aspect, + ax.viewmode, + ) on(matrices) do (view, proj, eyepos) cam = camera(scene) Makie.set_proj_view!(cam, proj, view) - cam.eyeposition[] = eyepos + return cam.eyeposition[] = eyepos end ticknode_1 = lift(finallimits, ax.xticks, ax.xtickformat) do lims, ticks, format - tl = get_ticks(ticks, identity, format, minimum(lims)[1], maximum(lims)[1]) + return tl = get_ticks(ticks, identity, format, minimum(lims)[1], maximum(lims)[1]) end ticknode_2 = lift(finallimits, ax.yticks, ax.ytickformat) do lims, ticks, format - tl = get_ticks(ticks, identity, format, minimum(lims)[2], maximum(lims)[2]) + return tl = get_ticks(ticks, identity, format, minimum(lims)[2], maximum(lims)[2]) end ticknode_3 = lift(finallimits, ax.zticks, ax.ztickformat) do lims, ticks, format - tl = get_ticks(ticks, identity, format, minimum(lims)[3], maximum(lims)[3]) + return tl = get_ticks(ticks, identity, format, minimum(lims)[3], maximum(lims)[3]) end add_panel!(scene, ax, 1, 2, 3, finallimits, mi3) @@ -69,15 +77,44 @@ function initialize_block!(ax::Axis3) zgridline1, zgridline2, zframelines = add_gridlines_and_frames!(blockscene, scene, ax, 3, finallimits, ticknode_3, mi3, mi1, mi2) - xticks, xticklabels, xlabel = - add_ticks_and_ticklabels!(blockscene, scene, ax, 1, finallimits, ticknode_1, mi1, mi2, mi3, ax.azimuth) - yticks, yticklabels, ylabel = - add_ticks_and_ticklabels!(blockscene, scene, ax, 2, finallimits, ticknode_2, mi2, mi1, mi3, ax.azimuth) - zticks, zticklabels, zlabel = - add_ticks_and_ticklabels!(blockscene, scene, ax, 3, finallimits, ticknode_3, mi3, mi1, mi2, ax.azimuth) + xticks, xticklabels, xlabel = add_ticks_and_ticklabels!( + blockscene, + scene, + ax, + 1, + finallimits, + ticknode_1, + mi1, + mi2, + mi3, + ax.azimuth, + ) + yticks, yticklabels, ylabel = add_ticks_and_ticklabels!( + blockscene, + scene, + ax, + 2, + finallimits, + ticknode_2, + mi2, + mi1, + mi3, + ax.azimuth, + ) + zticks, zticklabels, zlabel = add_ticks_and_ticklabels!( + blockscene, + scene, + ax, + 3, + finallimits, + ticknode_3, + mi3, + mi1, + mi2, + ax.azimuth, + ) titlepos = lift(scene.px_area, ax.titlegap, ax.titlealign) do a, titlegap, align - x = if align == :center a.origin[1] + a.widths[1] / 2 elseif align == :left @@ -90,23 +127,25 @@ function initialize_block!(ax::Axis3) yoffset = top(a) + titlegap - Point2(x, yoffset) + return Point2(x, yoffset) end titlealignnode = lift(ax.titlealign) do align - (align, :bottom) + return (align, :bottom) end titlet = text!( - blockscene, ax.title, - position = titlepos, - visible = ax.titlevisible, - fontsize = ax.titlesize, - align = titlealignnode, - font = ax.titlefont, - color = ax.titlecolor, - markerspace = :data, - inspectable = false) + blockscene, + ax.title, + position=titlepos, + visible=ax.titlevisible, + fontsize=ax.titlesize, + align=titlealignnode, + font=ax.titlefont, + color=ax.titlecolor, + markerspace=:data, + inspectable=false, + ) ax.cycler = Cycler() ax.palette = copy(Makie.default_palettes) @@ -130,16 +169,16 @@ function initialize_block!(ax::Axis3) return Consume(false) end - ax.interactions = Dict{Symbol, Tuple{Bool, Any}}() + ax.interactions = Dict{Symbol,Tuple{Bool,Any}}() on(ax.limits) do lims - reset_limits!(ax) + return reset_limits!(ax) end on(ax.targetlimits) do lims # adjustlimits!(ax) # we have no aspect constraints here currently, so just update final limits - ax.finallimits[] = lims + return ax.finallimits[] = lims end function process_event(event) @@ -156,10 +195,7 @@ function initialize_block!(ax::Axis3) on(process_event, ax.scrollevents) on(process_event, ax.keysevents) - register_interaction!(ax, - :dragrotate, - DragRotate()) - + register_interaction!(ax, :dragrotate, DragRotate()) # in case the user set limits already notify(ax.limits) @@ -169,13 +205,11 @@ end can_be_current_axis(ax3::Axis3) = true -function calculate_matrices(limits, px_area, elev, azim, perspectiveness, aspect, - viewmode) +function calculate_matrices(limits, px_area, elev, azim, perspectiveness, aspect, viewmode) ws = widths(limits) - t = Makie.translationmatrix(-Float64.(limits.origin)) - s = if aspect == :equal + s = Makie.scalematrix(if aspect == :equal scales = 2 ./ Float64.(ws) elseif aspect == :data scales = 2 ./ max.(maximum(ws), Float64.(ws)) @@ -183,7 +217,7 @@ function calculate_matrices(limits, px_area, elev, azim, perspectiveness, aspect scales = 2 ./ Float64.(ws) .* Float64.(aspect) ./ maximum(aspect) else error("Invalid aspect $aspect") - end |> Makie.scalematrix + end) t2 = Makie.translationmatrix(-0.5 .* ws .* scales) scale_matrix = t2 * s * t @@ -207,32 +241,42 @@ function calculate_matrices(limits, px_area, elev, azim, perspectiveness, aspect eyepos = Vec3{Float64}(x, y, z) - lookat_matrix = Makie.lookat( - eyepos, - Vec3{Float64}(0, 0, 0), - Vec3{Float64}(0, 0, 1)) + lookat_matrix = Makie.lookat(eyepos, Vec3{Float64}(0, 0, 0), Vec3{Float64}(0, 0, 1)) w = width(px_area) h = height(px_area) view_matrix = lookat_matrix * scale_matrix - projection_matrix = projectionmatrix(view_matrix, limits, eyepos, radius, azim, elev, angle, w, h, scales, viewmode) + projection_matrix = + projectionmatrix(view_matrix, limits, eyepos, radius, azim, elev, angle, w, h, scales, viewmode) # for eyeposition dependent algorithms, we need to present the position as if # there was no scaling applied eyeposition = Vec3f(inv(scale_matrix) * Vec4f(eyepos..., 1)) - view_matrix, projection_matrix, eyeposition -end - -function projectionmatrix(viewmatrix, limits, eyepos, radius, azim, elev, angle, width, height, scales, viewmode) + return view_matrix, projection_matrix, eyeposition +end + +function projectionmatrix( + viewmatrix, + limits, + eyepos, + radius, + azim, + elev, + angle, + width, + height, + scales, + viewmode, +) near = 0.5 * (radius - sqrt(3)) far = radius + 2 * sqrt(3) aspect_ratio = width / height - projection_matrix = if viewmode in (:fit, :fitzoom, :stretch) + return projection_matrix = if viewmode in (:fit, :fitzoom, :stretch) if height > width angle = angle / aspect_ratio end @@ -251,12 +295,12 @@ function projectionmatrix(viewmatrix, limits, eyepos, radius, azim, elev, angle, if viewmode == :fitzoom if ratio_y > ratio_x - pm = Makie.scalematrix(Vec3(1/ratio_y, 1/ratio_y, 1)) * pm + pm = Makie.scalematrix(Vec3(1 / ratio_y, 1 / ratio_y, 1)) * pm else - pm = Makie.scalematrix(Vec3(1/ratio_x, 1/ratio_x, 1)) * pm + pm = Makie.scalematrix(Vec3(1 / ratio_x, 1 / ratio_x, 1)) * pm end else - pm = Makie.scalematrix(Vec3(1/ratio_x, 1/ratio_y, 1)) * pm + pm = Makie.scalematrix(Vec3(1 / ratio_x, 1 / ratio_y, 1)) * pm end end pm @@ -265,12 +309,7 @@ function projectionmatrix(viewmatrix, limits, eyepos, radius, azim, elev, angle, end end - -function Makie.plot!( - ax::Axis3, P::Makie.PlotFunc, - attributes::Makie.Attributes, args...; - kw_attributes...) - +function Makie.plot!(ax::Axis3, P::Makie.PlotFunc, attributes::Makie.Attributes, args...; kw_attributes...) allattrs = merge(attributes, Attributes(kw_attributes)) _disallow_keyword(:axis, allattrs) @@ -284,12 +323,12 @@ function Makie.plot!( if is_open_or_any_parent(ax.scene) reset_limits!(ax) end - plot + return plot end function Makie.plot!(P::Makie.PlotFunc, ax::Axis3, args...; kw_attributes...) attributes = Makie.Attributes(kw_attributes) - Makie.plot!(ax, P, attributes, args...) + return Makie.plot!(ax, P, attributes, args...) end function update_state_before_display!(ax::Axis3) @@ -313,22 +352,22 @@ function autolimits!(ax::Axis3) lims = Rect3f(nori, nwidths) ax.finallimits[] = lims - nothing + return nothing end to_protrusions(x::Number) = GridLayoutBase.RectSides{Float32}(x, x, x, x) -to_protrusions(x::Tuple{Any, Any, Any, Any}) = GridLayoutBase.RectSides{Float32}(x...) +to_protrusions(x::Tuple{Any,Any,Any,Any}) = GridLayoutBase.RectSides{Float32}(x...) function getlimits(ax::Axis3, dim) dim in (1, 2, 3) || error("Dimension $dim not allowed. Only 1, 2 or 3.") filtered_plots = filter(ax.scene.plots) do p attr = p.attributes - to_value(get(attr, :visible, true)) && - is_data_space(to_value(get(attr, :space, :data))) && - ifelse(dim == 1, to_value(get(attr, :xautolimits, true)), true) && - ifelse(dim == 2, to_value(get(attr, :yautolimits, true)), true) && - ifelse(dim == 3, to_value(get(attr, :zautolimits, true)), true) + return to_value(get(attr, :visible, true)) && + is_data_space(to_value(get(attr, :space, :data))) && + ifelse(dim == 1, to_value(get(attr, :xautolimits, true)), true) && + ifelse(dim == 2, to_value(get(attr, :yautolimits, true)), true) && + ifelse(dim == 3, to_value(get(attr, :zautolimits, true)), true) end bboxes = Makie.data_limits.(filtered_plots) @@ -342,14 +381,14 @@ function getlimits(ax::Axis3, dim) templim = limitunion(templim, (bb.origin[dim], bb.origin[dim] + bb.widths[dim])) end - templim + return templim end # mutable struct LineAxis3D # end -function dimpoint(dim, v, v1, v2) +dimpoint(dim, v, v1, v2) = if dim == 1 Point(v, v1, v2) elseif dim == 2 @@ -357,9 +396,8 @@ function dimpoint(dim, v, v1, v2) elseif dim == 3 Point(v1, v2, v) end -end -function dim1(dim) +dim1(dim) = if dim == 1 2 elseif dim == 2 @@ -367,9 +405,8 @@ function dim1(dim) elseif dim == 3 1 end -end -function dim2(dim) +dim2(dim) = if dim == 1 3 elseif dim == 2 @@ -377,10 +414,8 @@ function dim2(dim) elseif dim == 3 2 end -end function add_gridlines_and_frames!(topscene, scene, ax, dim::Int, limits, ticknode, miv, min1, min2) - dimsym(sym) = Symbol(string((:x, :y, :z)[dim]) * string(sym)) attr(sym) = getproperty(ax, dimsym(sym)) @@ -397,13 +432,21 @@ function add_gridlines_and_frames!(topscene, scene, ax, dim::Int, limits, tickno mi = minimum(lims) ma = maximum(lims) map(filter(x -> !any(y -> x ≈ y[dim], extrema(lims)), ticks)) do t - dpoint(t, f1, mi[d2]), dpoint(t, f1, ma[d2]) + return dpoint(t, f1, mi[d2]), dpoint(t, f1, ma[d2]) end end - gridline1 = linesegments!(scene, endpoints, color = attr(:gridcolor), - linewidth = attr(:gridwidth), - xautolimits = false, yautolimits = false, zautolimits = false, transparency = true, - visible = attr(:gridvisible), inspectable = false) + gridline1 = linesegments!( + scene, + endpoints, + color=attr(:gridcolor), + linewidth=attr(:gridwidth), + xautolimits=false, + yautolimits=false, + zautolimits=false, + transparency=true, + visible=attr(:gridvisible), + inspectable=false, + ) endpoints2 = lift(limits, tickvalues, min1, min2) do lims, ticks, min1, min2 f1 = min1 ? minimum(lims)[d1] : maximum(lims)[d1] @@ -412,39 +455,52 @@ function add_gridlines_and_frames!(topscene, scene, ax, dim::Int, limits, tickno mi = minimum(lims) ma = maximum(lims) map(filter(x -> !any(y -> x ≈ y[dim], extrema(lims)), ticks)) do t - dpoint(t, mi[d1], f2), dpoint(t, ma[d1], f2) + return dpoint(t, mi[d1], f2), dpoint(t, ma[d1], f2) end end - gridline2 = linesegments!(scene, endpoints2, color = attr(:gridcolor), - linewidth = attr(:gridwidth), - xautolimits = false, yautolimits = false, zautolimits = false, transparency = true, - visible = attr(:gridvisible), inspectable = false) - - - framepoints = lift(limits, scene.camera.projectionview, scene.px_area, min1, min2 - ) do lims, _, pxa, mi1, mi2 - o = pxa.origin + gridline2 = linesegments!( + scene, + endpoints2, + color=attr(:gridcolor), + linewidth=attr(:gridwidth), + xautolimits=false, + yautolimits=false, + zautolimits=false, + transparency=true, + visible=attr(:gridvisible), + inspectable=false, + ) - f(mi) = mi ? minimum : maximum - p1 = dpoint(minimum(lims)[dim], f(!mi1)(lims)[d1], f(mi2)(lims)[d2]) - p2 = dpoint(maximum(lims)[dim], f(!mi1)(lims)[d1], f(mi2)(lims)[d2]) - p3 = dpoint(minimum(lims)[dim], f(mi1)(lims)[d1], f(mi2)(lims)[d2]) - p4 = dpoint(maximum(lims)[dim], f(mi1)(lims)[d1], f(mi2)(lims)[d2]) - p5 = dpoint(minimum(lims)[dim], f(mi1)(lims)[d1], f(!mi2)(lims)[d2]) - p6 = dpoint(maximum(lims)[dim], f(mi1)(lims)[d1], f(!mi2)(lims)[d2]) - # p7 = dpoint(minimum(lims)[dim], f(!mi1)(lims)[d1], f(!mi2)(lims)[d2]) - # p8 = dpoint(maximum(lims)[dim], f(!mi1)(lims)[d1], f(!mi2)(lims)[d2]) - - # we are going to transform the 3d frame points into 2d of the topscene - # because otherwise the frame lines can - # be cut when they lie directly on the scene boundary - to_topscene_z_2d.([p1, p2, p3, p4, p5, p6], Ref(scene)) - end + framepoints = + lift(limits, scene.camera.projectionview, scene.px_area, min1, min2) do lims, _, pxa, mi1, mi2 + o = pxa.origin + + f(mi) = mi ? minimum : maximum + p1 = dpoint(minimum(lims)[dim], f(!mi1)(lims)[d1], f(mi2)(lims)[d2]) + p2 = dpoint(maximum(lims)[dim], f(!mi1)(lims)[d1], f(mi2)(lims)[d2]) + p3 = dpoint(minimum(lims)[dim], f(mi1)(lims)[d1], f(mi2)(lims)[d2]) + p4 = dpoint(maximum(lims)[dim], f(mi1)(lims)[d1], f(mi2)(lims)[d2]) + p5 = dpoint(minimum(lims)[dim], f(mi1)(lims)[d1], f(!mi2)(lims)[d2]) + p6 = dpoint(maximum(lims)[dim], f(mi1)(lims)[d1], f(!mi2)(lims)[d2]) + # p7 = dpoint(minimum(lims)[dim], f(!mi1)(lims)[d1], f(!mi2)(lims)[d2]) + # p8 = dpoint(maximum(lims)[dim], f(!mi1)(lims)[d1], f(!mi2)(lims)[d2]) + + # we are going to transform the 3d frame points into 2d of the topscene + # because otherwise the frame lines can + # be cut when they lie directly on the scene boundary + return to_topscene_z_2d.([p1, p2, p3, p4, p5, p6], Ref(scene)) + end colors = Observable{Any}() map!(vcat, colors, attr(:spinecolor_1), attr(:spinecolor_2), attr(:spinecolor_3)) - framelines = linesegments!(topscene, framepoints, color = colors, linewidth = attr(:spinewidth), + framelines = linesegments!( + topscene, + framepoints, + color=colors, + linewidth=attr(:spinewidth), # transparency = true, - visible = attr(:spinesvisible), inspectable = false) + visible=attr(:spinesvisible), + inspectable=false, + ) return gridline1, gridline2, framelines end @@ -456,11 +512,10 @@ function to_topscene_z_2d(p3d, scene) p2d = Point2f(o + Makie.project(scene, p3d)) # -10000 is an arbitrary weird constant that in preliminary testing didn't seem # to clip into plot objects anymore - Point3f(p2d..., -10000) + return Point3f(p2d..., -10000) end function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, ticknode, miv, min1, min2, azimuth) - dimsym(sym) = Symbol(string((:x, :y, :z)[dim]) * string(sym)) attr(sym) = getproperty(ax, dimsym(sym)) @@ -471,9 +526,15 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno tickvalues = @lift($ticknode[1]) ticklabels = @lift($ticknode[2]) - tick_segments = lift(limits, tickvalues, miv, min1, min2, - scene.camera.projectionview, scene.px_area) do lims, ticks, miv, min1, min2, - pview, pxa + tick_segments = lift( + limits, + tickvalues, + miv, + min1, + min2, + scene.camera.projectionview, + scene.px_area, + ) do lims, ticks, miv, min1, min2, pview, pxa f1 = !min1 ? minimum(lims)[d1] : maximum(lims)[d1] f2 = min2 ? minimum(lims)[d2] : maximum(lims)[d2] @@ -496,7 +557,7 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno dpoint(t, f1 + 0.03 * diff_f1, f2) end - (p1, p2) + return (p1, p2) end end @@ -505,32 +566,43 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno # be cut when they extend beyond the scene boundary tick_segments_2dz = lift(tick_segments, scene.camera.projectionview, scene.px_area) do ts, _, _ map(ts) do p1_p2 - to_topscene_z_2d.(p1_p2, Ref(scene)) + return to_topscene_z_2d.(p1_p2, Ref(scene)) end end - ticks = linesegments!(topscene, tick_segments_2dz, - xautolimits = false, yautolimits = false, zautolimits = false, - transparency = true, inspectable = false, - color = attr(:tickcolor), linewidth = attr(:tickwidth), visible = attr(:ticksvisible)) - - labels_positions = lift(scene.px_area, scene.camera.projectionview, - tick_segments, ticklabels, attr(:ticklabelpad)) do pxa, pv, ticksegs, ticklabs, pad + ticks = linesegments!( + topscene, + tick_segments_2dz, + xautolimits=false, + yautolimits=false, + zautolimits=false, + transparency=true, + inspectable=false, + color=attr(:tickcolor), + linewidth=attr(:tickwidth), + visible=attr(:ticksvisible), + ) + labels_positions = lift( + scene.px_area, + scene.camera.projectionview, + tick_segments, + ticklabels, + attr(:ticklabelpad), + ) do pxa, pv, ticksegs, ticklabs, pad o = pxa.origin points = map(ticksegs) do (tstart, tend) tstartp = Point2f(o + Makie.project(scene, tstart)) tendp = Point2f(o + Makie.project(scene, tend)) - offset = pad * Makie.GeometryBasics.normalize( - Point2f(tendp - tstartp)) - tendp + offset + offset = pad * Makie.GeometryBasics.normalize(Point2f(tendp - tstartp)) + return tendp + offset end N = min(length(ticklabs), length(points)) v = [(ticklabs[i], points[i]) for i in 1:N] - v::Vector{Tuple{String, Point2f}} + return v::Vector{Tuple{String,Point2f}} end align = lift(miv, min1, min2) do mv, m1, m2 @@ -543,22 +615,34 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno end end - ticklabels = text!(topscene, labels_positions, align = align, - color = attr(:ticklabelcolor), fontsize = attr(:ticklabelsize), - font = attr(:ticklabelfont), visible = attr(:ticklabelsvisible), inspectable = false + ticklabels = text!( + topscene, + labels_positions, + align=align, + color=attr(:ticklabelcolor), + fontsize=attr(:ticklabelsize), + font=attr(:ticklabelfont), + visible=attr(:ticklabelsvisible), + inspectable=false, ) translate!(ticklabels, 0, 0, 1000) label_position = Observable(Point2f(0)) - label_rotation = Observable(0f0) + label_rotation = Observable(0.0f0) label_align = Observable((:center, :top)) onany( - scene.px_area, scene.camera.projectionview, limits, miv, min1, min2, - attr(:labeloffset), attr(:labelrotation), attr(:labelalign) - ) do pxa, pv, lims, miv, min1, min2, labeloffset, lrotation, lalign - + scene.px_area, + scene.camera.projectionview, + limits, + miv, + min1, + min2, + attr(:labeloffset), + attr(:labelrotation), + attr(:labelalign), + ) do pxa, pv, lims, miv, min1, min2, labeloffset, lrotation, lalign o = pxa.origin f1 = !min1 ? minimum(lims)[d1] : maximum(lims)[d1] @@ -584,18 +668,18 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno (min1 ⊻ min2) ? 1 : -1 end - a = pi/2 + a = pi / 2 # get the vector pointing from the axis in the direction of the label anchor - offset_vec = (Makie.Mat2f(cos(a), sin(a), -sin(a), cos(a)) * - Makie.GeometryBasics.normalize(diffsign * diff)) + offset_vec = + (Makie.Mat2f(cos(a), sin(a), -sin(a), cos(a)) * Makie.GeometryBasics.normalize(diffsign * diff)) # calculate the label offset from the axis midpoint plus_offset = midpoint + labeloffset * offset_vec offset_ang = atan(offset_vec[2], offset_vec[1]) - offset_ang_90deg = offset_ang + pi/2 - offset_ang_90deg_alwaysup = ((offset_ang + pi/2 + pi/2) % pi) - pi/2 + offset_ang_90deg = offset_ang + pi / 2 + offset_ang_90deg_alwaysup = ((offset_ang + pi / 2 + pi / 2) % pi) - pi / 2 # # prefer rotated left 90deg to rotated right 90deg slight_flip = offset_ang_90deg_alwaysup < -deg2rad(88) @@ -625,22 +709,23 @@ function add_ticks_and_ticklabels!(topscene, scene, ax, dim::Int, limits, tickno end notify(attr(:labelalign)) - label = text!(topscene, attr(:label), - color = attr(:labelcolor), - fontsize = attr(:labelsize), - font = attr(:labelfont), - position = label_position, - rotation = label_rotation, - align = label_align, - visible = attr(:labelvisible), - inspectable = false + label = text!( + topscene, + attr(:label), + color=attr(:labelcolor), + fontsize=attr(:labelsize), + font=attr(:labelfont), + position=label_position, + rotation=label_rotation, + align=label_align, + visible=attr(:labelvisible), + inspectable=false, ) - return ticks, ticklabels, label end -function dim3point(dim1, dim2, dim3, v1, v2, v3) +dim3point(dim1, dim2, dim3, v1, v2, v3) = if (dim1, dim2, dim3) == (1, 2, 3) Point(v1, v2, v3) elseif (dim1, dim2, dim3) == (2, 3, 1) @@ -650,16 +735,12 @@ function dim3point(dim1, dim2, dim3, v1, v2, v3) else error("Invalid dim order $dim1, $dim2, $dim3") end -end function add_panel!(scene, ax, dim1, dim2, dim3, limits, min3) - - dimsym(sym) = Symbol(string((:x, :y, :z)[dim1]) * - string((:x, :y, :z)[dim2]) * string(sym)) + dimsym(sym) = Symbol(string((:x, :y, :z)[dim1]) * string((:x, :y, :z)[dim2]) * string(sym)) attr(sym) = getproperty(ax, dimsym(sym)) vertices = lift(limits, min3) do lims, mi3 - mi = minimum(lims) ma = maximum(lims) @@ -673,20 +754,27 @@ function add_panel!(scene, ax, dim1, dim2, dim3, limits, min3) p2 = dim3point(dim1, dim2, dim3, mi[dim1], ma[dim2], v3) p3 = dim3point(dim1, dim2, dim3, ma[dim1], ma[dim2], v3) p4 = dim3point(dim1, dim2, dim3, ma[dim1], mi[dim2], v3) - [p1, p2, p3, p4] + return [p1, p2, p3, p4] end faces = [1 2 3; 3 4 1] - panel = mesh!(scene, vertices, faces, shading = false, inspectable = false, - xautolimits = false, yautolimits = false, zautolimits = false, - color = attr(:panelcolor), visible = attr(:panelvisible)) + panel = mesh!( + scene, + vertices, + faces, + shading=false, + inspectable=false, + xautolimits=false, + yautolimits=false, + zautolimits=false, + color=attr(:panelcolor), + visible=attr(:panelvisible), + ) return panel end -function hidexdecorations!(ax::Axis3; - label = true, ticklabels = true, ticks = true, grid = true) - +function hidexdecorations!(ax::Axis3; label=true, ticklabels=true, ticks=true, grid=true) if label ax.xlabelvisible = false end @@ -706,12 +794,10 @@ function hidexdecorations!(ax::Axis3; # ax.xminorticksvisible = false # end - ax + return ax end -function hideydecorations!(ax::Axis3; - label = true, ticklabels = true, ticks = true, grid = true) - +function hideydecorations!(ax::Axis3; label=true, ticklabels=true, ticks=true, grid=true) if label ax.ylabelvisible = false end @@ -731,12 +817,10 @@ function hideydecorations!(ax::Axis3; # ax.yminorticksvisible = false # end - ax + return ax end -function hidezdecorations!(ax::Axis3; - label = true, ticklabels = true, ticks = true, grid = true) - +function hidezdecorations!(ax::Axis3; label=true, ticklabels=true, ticks=true, grid=true) if label ax.zlabelvisible = false end @@ -756,40 +840,28 @@ function hidezdecorations!(ax::Axis3; # ax.zminorticksvisible = false # end - ax + return ax end -function hidedecorations!(ax::Axis3; - label = true, ticklabels = true, ticks = true, grid = true) - - hidexdecorations!(ax; label = label, ticklabels = ticklabels, - ticks = ticks, grid = grid) - hideydecorations!(ax; label = label, ticklabels = ticklabels, - ticks = ticks, grid = grid) - hidezdecorations!(ax; label = label, ticklabels = ticklabels, - ticks = ticks, grid = grid) +function hidedecorations!(ax::Axis3; label=true, ticklabels=true, ticks=true, grid=true) + hidexdecorations!(ax; label=label, ticklabels=ticklabels, ticks=ticks, grid=grid) + hideydecorations!(ax; label=label, ticklabels=ticklabels, ticks=ticks, grid=grid) + hidezdecorations!(ax; label=label, ticklabels=ticklabels, ticks=ticks, grid=grid) - ax + return ax end function hidespines!(ax::Axis3) ax.xspinesvisible = false ax.yspinesvisible = false ax.zspinesvisible = false - ax + return ax end - - # this is so users can do limits = (x1, x2, y1, y2, z1, z2) -function convert_limit_attribute(lims::Tuple{Any, Any, Any, Any, Any, Any}) - (lims[1:2], lims[3:4], lims[5:6]) -end - -function convert_limit_attribute(lims::Tuple{Any, Any, Any}) - lims -end +convert_limit_attribute(lims::Tuple{Any,Any,Any,Any,Any,Any}) = (lims[1:2], lims[3:4], lims[5:6]) +convert_limit_attribute(lims::Tuple{Any,Any,Any}) = lims function xautolimits(ax::Axis3) xlims = getlimits(ax, 1) @@ -797,12 +869,9 @@ function xautolimits(ax::Axis3) if isnothing(xlims) xlims = (ax.targetlimits[].origin[1], ax.targetlimits[].origin[1] + ax.targetlimits[].widths[1]) else - xlims = expandlimits(xlims, - ax.xautolimitmargin[][1], - ax.xautolimitmargin[][2], - identity) + xlims = expandlimits(xlims, ax.xautolimitmargin[][1], ax.xautolimitmargin[][2], identity) end - xlims + return xlims end function yautolimits(ax::Axis3) @@ -811,12 +880,9 @@ function yautolimits(ax::Axis3) if isnothing(ylims) ylims = (ax.targetlimits[].origin[2], ax.targetlimits[].origin[2] + ax.targetlimits[].widths[2]) else - ylims = expandlimits(ylims, - ax.yautolimitmargin[][1], - ax.yautolimitmargin[][2], - identity) + ylims = expandlimits(ylims, ax.yautolimitmargin[][1], ax.yautolimitmargin[][2], identity) end - ylims + return ylims end function zautolimits(ax::Axis3) @@ -825,46 +891,43 @@ function zautolimits(ax::Axis3) if isnothing(zlims) zlims = (ax.targetlimits[].origin[3], ax.targetlimits[].origin[3] + ax.targetlimits[].widths[3]) else - zlims = expandlimits(zlims, - ax.zautolimitmargin[][1], - ax.zautolimitmargin[][2], - identity) + zlims = expandlimits(zlims, ax.zautolimitmargin[][1], ax.zautolimitmargin[][2], identity) end - zlims + return zlims end -function Makie.xlims!(ax::Axis3, xlims::Tuple{Union{Real, Nothing}, Union{Real, Nothing}}) +function Makie.xlims!(ax::Axis3, xlims::Tuple{Union{Real,Nothing},Union{Real,Nothing}}) if length(xlims) != 2 error("Invalid xlims length of $(length(xlims)), must be 2.") elseif xlims[1] == xlims[2] error("Can't set x limits to the same value $(xlims[1]).") - # elseif all(x -> x isa Real, xlims) && xlims[1] > xlims[2] - # xlims = reverse(xlims) - # ax.xreversed[] = true - # else - # ax.xreversed[] = false + # elseif all(x -> x isa Real, xlims) && xlims[1] > xlims[2] + # xlims = reverse(xlims) + # ax.xreversed[] = true + # else + # ax.xreversed[] = false end ax.limits.val = (xlims, ax.limits[][2], ax.limits[][3]) - reset_limits!(ax, yauto = false, zauto = false) - nothing + reset_limits!(ax, yauto=false, zauto=false) + return nothing end -function Makie.ylims!(ax::Axis3, ylims::Tuple{Union{Real, Nothing}, Union{Real, Nothing}}) +function Makie.ylims!(ax::Axis3, ylims::Tuple{Union{Real,Nothing},Union{Real,Nothing}}) if length(ylims) != 2 error("Invalid ylims length of $(length(ylims)), must be 2.") elseif ylims[1] == ylims[2] error("Can't set y limits to the same value $(ylims[1]).") - # elseif all(x -> x isa Real, ylims) && ylims[1] > ylims[2] - # ylims = reverse(ylims) - # ax.yreversed[] = true - # else - # ax.yreversed[] = false + # elseif all(x -> x isa Real, ylims) && ylims[1] > ylims[2] + # ylims = reverse(ylims) + # ax.yreversed[] = true + # else + # ax.yreversed[] = false end ax.limits.val = (ax.limits[][1], ylims, ax.limits[][3]) - reset_limits!(ax, xauto = false, zauto = false) - nothing + reset_limits!(ax, xauto=false, zauto=false) + return nothing end function Makie.zlims!(ax::Axis3, zlims) @@ -872,19 +935,18 @@ function Makie.zlims!(ax::Axis3, zlims) error("Invalid zlims length of $(length(zlims)), must be 2.") elseif zlims[1] == zlims[2] error("Can't set y limits to the same value $(zlims[1]).") - # elseif all(x -> x isa Real, zlims) && zlims[1] > zlims[2] - # zlims = reverse(zlims) - # ax.zreversed[] = true - # else - # ax.zreversed[] = false + # elseif all(x -> x isa Real, zlims) && zlims[1] > zlims[2] + # zlims = reverse(zlims) + # ax.zreversed[] = true + # else + # ax.zreversed[] = false end ax.limits.val = (ax.limits[][1], ax.limits[][2], zlims) - reset_limits!(ax, xauto = false, yauto = false) - nothing + reset_limits!(ax, xauto=false, yauto=false) + return nothing end - """ limits!(ax::Axis3, xlims, ylims) @@ -894,7 +956,7 @@ If limits are ordered high-low, this reverses the axis orientation. function limits!(ax::Axis3, xlims, ylims, zlims) Makie.xlims!(ax, xlims) Makie.ylims!(ax, ylims) - Makie.zlims!(ax, zlims) + return Makie.zlims!(ax, zlims) end """ @@ -906,7 +968,7 @@ If limits are ordered high-low, this reverses the axis orientation. function limits!(ax::Axis3, x1, x2, y1, y2, z1, z2) Makie.xlims!(ax, x1, x2) Makie.ylims!(ax, y1, y2) - Makie.zlims!(ax, z1, z2) + return Makie.zlims!(ax, z1, z2) end """ @@ -920,5 +982,5 @@ function limits!(ax::Axis3, rect::Rect3) xmax, ymax, zmax = maximum(rect) Makie.xlims!(ax, xmin, xmax) Makie.ylims!(ax, ymin, ymax) - Makie.zlims!(ax, zmin, zmax) + return Makie.zlims!(ax, zmin, zmax) end diff --git a/src/makielayout/blocks/box.jl b/src/makielayout/blocks/box.jl index db7acad6a8e..759c123413f 100644 --- a/src/makielayout/blocks/box.jl +++ b/src/makielayout/blocks/box.jl @@ -1,16 +1,21 @@ function initialize_block!(box::Box) - blockscene = box.blockscene strokecolor_with_visibility = lift(box.strokecolor, box.strokevisible) do col, vis - vis ? col : RGBAf(0, 0, 0, 0) + return vis ? col : RGBAf(0, 0, 0, 0) end ibbox = @lift(round_to_IRect2D($(box.layoutobservables.computedbbox))) - poly!(blockscene, ibbox, color = box.color, visible = box.visible, - strokecolor = strokecolor_with_visibility, strokewidth = box.strokewidth, - inspectable = false) + poly!( + blockscene, + ibbox, + color=box.color, + visible=box.visible, + strokecolor=strokecolor_with_visibility, + strokewidth=box.strokewidth, + inspectable=false, + ) # trigger bbox box.layoutobservables.suggestedbbox[] = box.layoutobservables.suggestedbbox[] diff --git a/src/makielayout/blocks/button.jl b/src/makielayout/blocks/button.jl index 59d956bbaf1..0f5bf9e6752 100644 --- a/src/makielayout/blocks/button.jl +++ b/src/makielayout/blocks/button.jl @@ -1,40 +1,54 @@ function initialize_block!(b::Button) - scene = b.blockscene textpos = Observable(Point2f(0, 0)) subarea = lift(b.layoutobservables.computedbbox) do bbox - round_to_IRect2D(bbox) + return round_to_IRect2D(bbox) end subscene = Scene(scene, subarea, camera=campixel!) # buttonrect is without the left bottom offset of the bbox buttonrect = lift(b.layoutobservables.computedbbox) do bbox - BBox(0, width(bbox), 0, height(bbox)) + return BBox(0, width(bbox), 0, height(bbox)) end on(buttonrect) do rect - textpos[] = Point2f(left(rect) + 0.5f0 * width(rect), bottom(rect) + 0.5f0 * height(rect)) + return textpos[] = Point2f(left(rect) + 0.5f0 * width(rect), bottom(rect) + 0.5f0 * height(rect)) end roundedrectpoints = lift(roundedrectvertices, buttonrect, b.cornerradius, b.cornersegments) mousestate = Observable(:out) - bcolors = (; out = b.buttoncolor, active = b.buttoncolor_active, hover = b.buttoncolor_hover) + bcolors = (; out=b.buttoncolor, active=b.buttoncolor_active, hover=b.buttoncolor_hover) bcolor = Observable{RGBColors}() - map!((s,_...)-> to_color(bcolors[s][]), bcolor, mousestate, values(bcolors)...) - - button = poly!(subscene, roundedrectpoints, strokewidth = b.strokewidth, strokecolor = b.strokecolor, - color = bcolor, inspectable = false) - - lcolors = (; out = b.labelcolor, active = b.labelcolor_active, hover = b.labelcolor_hover) + map!((s, _...) -> to_color(bcolors[s][]), bcolor, mousestate, values(bcolors)...) + + button = poly!( + subscene, + roundedrectpoints, + strokewidth=b.strokewidth, + strokecolor=b.strokecolor, + color=bcolor, + inspectable=false, + ) + + lcolors = (; out=b.labelcolor, active=b.labelcolor_active, hover=b.labelcolor_hover) lcolor = Observable{RGBColors}() - map!((s,_...)-> to_color(lcolors[s][]), lcolor, mousestate, values(lcolors)...) - - labeltext = text!(subscene, textpos, text = b.label, fontsize = b.fontsize, font = b.font, - color = lcolor, align = (:center, :center), markerspace = :data, inspectable = false) + map!((s, _...) -> to_color(lcolors[s][]), lcolor, mousestate, values(lcolors)...) + + labeltext = text!( + subscene, + textpos, + text=b.label, + fontsize=b.fontsize, + font=b.font, + color=lcolor, + align=(:center, :center), + markerspace=:data, + inspectable=false, + ) # move text in front of background to be sure it's not occluded translate!(labeltext, 0, 0, 1) @@ -43,7 +57,7 @@ function initialize_block!(b::Button) textbb = Rect2f(boundingbox(labeltext)) autowidth = width(textbb) + padding[1] + padding[2] autoheight = height(textbb) + padding[3] + padding[4] - b.layoutobservables.autosize[] = (autowidth, autoheight) + return b.layoutobservables.autosize[] = (autowidth, autoheight) end mouseevents = addmouseevents!(scene, b.layoutobservables.computedbbox) diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index e29b95e9928..0fbb9f6370b 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -1,88 +1,85 @@ function block_docs(::Type{Colorbar}) - """ - Create a colorbar that shows a continuous or categorical colormap with ticks - chosen according to the colorrange. - - You can set colorrange and colormap manually, or pass a plot object as the second argument - to copy its respective attributes. - - ## Constructors - - ```julia - Colorbar(fig_or_scene; kwargs...) - Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) - Colorbar(fig_or_scene, heatmap::Union{Heatmap, Image}; kwargs...) - Colorbar(fig_or_scene, contourf::Makie.Contourf; kwargs...) - ``` - """ + return """ + Create a colorbar that shows a continuous or categorical colormap with ticks + chosen according to the colorrange. + + You can set colorrange and colormap manually, or pass a plot object as the second argument + to copy its respective attributes. + + ## Constructors + + ```julia + Colorbar(fig_or_scene; kwargs...) + Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) + Colorbar(fig_or_scene, heatmap::Union{Heatmap, Image}; kwargs...) + Colorbar(fig_or_scene, contourf::Makie.Contourf; kwargs...) + ``` + """ end - function Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) - for key in (:colormap, :limits) if key in keys(kwargs) - error("You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.") + error( + "You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.", + ) end end - Colorbar( - fig_or_scene; - colormap = plot.colormap, - limits = plot.colorrange, - kwargs... - ) + return Colorbar(fig_or_scene; colormap=plot.colormap, limits=plot.colorrange, kwargs...) end -function Colorbar(fig_or_scene, heatmap::Union{Heatmap, Image}; kwargs...) - +function Colorbar(fig_or_scene, heatmap::Union{Heatmap,Image}; kwargs...) for key in (:colormap, :limits, :highclip, :lowclip) if key in keys(kwargs) - error("You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.") + error( + "You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.", + ) end end - Colorbar( + return Colorbar( fig_or_scene; - colormap = heatmap.colormap, - limits = heatmap.colorrange, - highclip = heatmap.highclip, - lowclip = heatmap.lowclip, - kwargs... + colormap=heatmap.colormap, + limits=heatmap.colorrange, + highclip=heatmap.highclip, + lowclip=heatmap.lowclip, + kwargs..., ) end -function Colorbar(fig_or_scene, contourf::Union{Contourf, Tricontourf}; kwargs...) - +function Colorbar(fig_or_scene, contourf::Union{Contourf,Tricontourf}; kwargs...) for key in (:colormap, :limits, :highclip, :lowclip) if key in keys(kwargs) - error("You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.") + error( + "You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.", + ) end end steps = contourf._computed_levels limits = lift(steps) do steps - steps[1], steps[end] + return steps[1], steps[end] end - Colorbar( + return Colorbar( fig_or_scene; - colormap = contourf._computed_colormap, - limits = limits, - lowclip = contourf._computed_extendlow, - highclip = contourf._computed_extendhigh, - kwargs... + colormap=contourf._computed_colormap, + limits=limits, + lowclip=contourf._computed_extendlow, + highclip=contourf._computed_extendhigh, + kwargs..., ) - end - function initialize_block!(cb::Colorbar) blockscene = cb.blockscene limits = lift(cb.limits, cb.colorrange) do limits, colorrange if all(!isnothing, (limits, colorrange)) - error("Both colorrange + limits are set, please only set one, they're aliases. colorrange: $(colorrange), limits: $(limits)") + error( + "Both colorrange + limits are set, please only set one, they're aliases. colorrange: $(colorrange), limits: $(limits)", + ) end return something(limits, colorrange, (0, 1)) end @@ -119,15 +116,15 @@ function initialize_block!(cb::Colorbar) return c != compare end - lowclip_tri_visible = lift(isvisible, cb.lowclip, lift(x-> get(x, 0), cgradient)) - highclip_tri_visible = lift(isvisible, cb.highclip, lift(x-> get(x, 1), cgradient)) + lowclip_tri_visible = lift(isvisible, cb.lowclip, lift(x -> get(x, 0), cgradient)) + highclip_tri_visible = lift(isvisible, cb.highclip, lift(x -> get(x, 1), cgradient)) tri_heights = lift(highclip_tri_visible, lowclip_tri_visible, framebox) do hv, lv, box - if cb.vertical[] + return if cb.vertical[] (lv * width(box), hv * width(box)) else (lv * height(box), hv * height(box)) - end .* sin(pi/3) + end .* sin(pi / 3) end barsize = lift(tri_heights) do heights @@ -147,11 +144,10 @@ function initialize_block!(cb::Colorbar) end end - map_is_categorical = lift(x -> x isa PlotUtils.CategoricalColorGradient, cgradient) steps = lift(cgradient, cb.nsteps) do cgradient, n - s = if cgradient isa PlotUtils.CategoricalColorGradient + return s = if cgradient isa PlotUtils.CategoricalColorGradient cgradient.values else collect(LinRange(0, 1, n)) @@ -169,101 +165,110 @@ function initialize_block!(cb::Colorbar) # for categorical colormaps we make a number of rectangle polys - rects_and_colors = lift(barbox, cb.vertical, steps, cgradient, cb.scale, limits) do bbox, v, steps, gradient, scale, lims + rects_and_colors = + lift(barbox, cb.vertical, steps, cgradient, cb.scale, limits) do bbox, v, steps, gradient, scale, lims - # we need to convert the 0 to 1 steps into rescaled 0 to 1 steps given the - # colormap's `scale` attribute + # we need to convert the 0 to 1 steps into rescaled 0 to 1 steps given the + # colormap's `scale` attribute - s_scaled = scaled_steps(steps, scale, lims) + s_scaled = scaled_steps(steps, scale, lims) - xmin, ymin = minimum(bbox) - xmax, ymax = maximum(bbox) + xmin, ymin = minimum(bbox) + xmax, ymax = maximum(bbox) - rects = if v - yvals = s_scaled .* (ymax - ymin) .+ ymin - [BBox(xmin, xmax, b, t) - for (b, t) in zip(yvals[1:end-1], yvals[2:end])] - else - xvals = s_scaled .* (xmax - xmin) .+ xmin - [BBox(l, r, ymin, ymax) - for (l, r) in zip(xvals[1:end-1], xvals[2:end])] - end + rects = if v + yvals = s_scaled .* (ymax - ymin) .+ ymin + [BBox(xmin, xmax, b, t) for (b, t) in zip(yvals[1:(end - 1)], yvals[2:end])] + else + xvals = s_scaled .* (xmax - xmin) .+ xmin + [BBox(l, r, ymin, ymax) for (l, r) in zip(xvals[1:(end - 1)], xvals[2:end])] + end - colors = get.(Ref(gradient), (steps[1:end-1] .+ steps[2:end]) ./2) - rects, colors - end + colors = get.(Ref(gradient), (steps[1:(end - 1)] .+ steps[2:end]) ./ 2) + return rects, colors + end colors = lift(x -> getindex(x, 2), rects_and_colors) - rects = poly!(blockscene, + rects = poly!( + blockscene, lift(x -> getindex(x, 1), rects_and_colors), - color = colors, - visible = map_is_categorical, - inspectable = false + color=colors, + visible=map_is_categorical, + inspectable=false, ) # for continous colormaps we sample a 1d image # to avoid white lines when rendering vector graphics continous_pixels = lift(cb.vertical, cb.nsteps, cgradient, limits, cb.scale) do v, n, grad, lims, scale - s_steps = scaled_steps(LinRange(0, 1, n), scale, lims) px = get.(Ref(grad), s_steps) - v ? reshape(px, 1, n) : reshape(px, n, 1) + return v ? reshape(px, 1, n) : reshape(px, n, 1) end - cont_image = image!(blockscene, - @lift(range(left($barbox), right($barbox), length = 2)), - @lift(range(bottom($barbox), top($barbox), length = 2)), + cont_image = image!( + blockscene, + @lift(range(left($barbox), right($barbox), length=2)), + @lift(range(bottom($barbox), top($barbox), length=2)), continous_pixels, - visible = @lift(!$map_is_categorical), - interpolate = true, - inspectable = false + visible=@lift(!$map_is_categorical), + interpolate=true, + inspectable=false, ) - highclip_tri = lift(barbox, cb.spinewidth) do box, spinewidth if cb.vertical[] lb, rb = topline(box) l = lb r = rb - t = ((l .+ r) ./ 2) .+ Point2f(0, sqrt(sum((r .- l) .^ 2)) * sin(pi/3)) + t = ((l .+ r) ./ 2) .+ Point2f(0, sqrt(sum((r .- l) .^ 2)) * sin(pi / 3)) [l, r, t] else b, t = rightline(box) - r = ((b .+ t) ./ 2) .+ Point2f(sqrt(sum((t .- b) .^ 2)) * sin(pi/3), 0) + r = ((b .+ t) ./ 2) .+ Point2f(sqrt(sum((t .- b) .^ 2)) * sin(pi / 3), 0) [t, b, r] end end highclip_tri_color = Observables.map(cb.highclip) do hc - to_color(isnothing(hc) ? :transparent : hc) + return to_color(isnothing(hc) ? :transparent : hc) end - highclip_tri_poly = poly!(blockscene, highclip_tri, color = highclip_tri_color, - strokecolor = :transparent, - visible = highclip_tri_visible, inspectable = false) + highclip_tri_poly = poly!( + blockscene, + highclip_tri, + color=highclip_tri_color, + strokecolor=:transparent, + visible=highclip_tri_visible, + inspectable=false, + ) lowclip_tri = lift(barbox, cb.spinewidth) do box, spinewidth if cb.vertical[] lb, rb = bottomline(box) l = lb r = rb - t = ((l .+ r) ./ 2) .- Point2f(0, sqrt(sum((r .- l) .^ 2)) * sin(pi/3)) + t = ((l .+ r) ./ 2) .- Point2f(0, sqrt(sum((r .- l) .^ 2)) * sin(pi / 3)) [l, r, t] else b, t = leftline(box) - l = ((b .+ t) ./ 2) .- Point2f(sqrt(sum((t .- b) .^ 2)) * sin(pi/3), 0) + l = ((b .+ t) ./ 2) .- Point2f(sqrt(sum((t .- b) .^ 2)) * sin(pi / 3), 0) [b, t, l] end end lowclip_tri_color = Observables.map(cb.lowclip) do lc - to_color(isnothing(lc) ? :transparent : lc) + return to_color(isnothing(lc) ? :transparent : lc) end - lowclip_tri_poly = poly!(blockscene, lowclip_tri, color = lowclip_tri_color, - strokecolor = :transparent, - visible = lowclip_tri_visible, inspectable = false) + lowclip_tri_poly = poly!( + blockscene, + lowclip_tri, + color=lowclip_tri_color, + strokecolor=:transparent, + visible=lowclip_tri_visible, + inspectable=false, + ) borderpoints = lift(barbox, highclip_tri_visible, lowclip_tri_visible) do bb, hcv, lcv if cb.vertical[] @@ -291,11 +296,9 @@ function initialize_block!(cb::Colorbar) end end - lines!(blockscene, borderpoints, linewidth = cb.spinewidth, color = cb.topspinecolor, inspectable = false) - - axispoints = lift(barbox, cb.vertical, cb.flipaxis) do scenearea, - vertical, flipaxis + lines!(blockscene, borderpoints, linewidth=cb.spinewidth, color=cb.topspinecolor, inspectable=false) + axispoints = lift(barbox, cb.vertical, cb.flipaxis) do scenearea, vertical, flipaxis if vertical if flipaxis (bottomright(scenearea), topright(scenearea)) @@ -309,32 +312,52 @@ function initialize_block!(cb::Colorbar) (bottomleft(scenearea), bottomright(scenearea)) end end - end - axis = LineAxis(blockscene, endpoints = axispoints, flipped = cb.flipaxis, - limits = limits, ticklabelalign = cb.ticklabelalign, label = cb.label, - labelpadding = cb.labelpadding, labelvisible = cb.labelvisible, labelsize = cb.labelsize, - labelcolor = cb.labelcolor, labelrotation = cb.labelrotation, - labelfont = cb.labelfont, ticklabelfont = cb.ticklabelfont, ticks = cb.ticks, tickformat = cb.tickformat, - ticklabelsize = cb.ticklabelsize, ticklabelsvisible = cb.ticklabelsvisible, ticksize = cb.ticksize, - ticksvisible = cb.ticksvisible, ticklabelpad = cb.ticklabelpad, tickalign = cb.tickalign, - ticklabelrotation = cb.ticklabelrotation, - tickwidth = cb.tickwidth, tickcolor = cb.tickcolor, spinewidth = cb.spinewidth, - ticklabelspace = cb.ticklabelspace, ticklabelcolor = cb.ticklabelcolor, - spinecolor = :transparent, spinevisible = :false, flip_vertical_label = cb.flip_vertical_label, - minorticksvisible = cb.minorticksvisible, minortickalign = cb.minortickalign, - minorticksize = cb.minorticksize, minortickwidth = cb.minortickwidth, - minortickcolor = cb.minortickcolor, minorticks = cb.minorticks, scale = cb.scale) + axis = LineAxis( + blockscene, + endpoints=axispoints, + flipped=cb.flipaxis, + limits=limits, + ticklabelalign=cb.ticklabelalign, + label=cb.label, + labelpadding=cb.labelpadding, + labelvisible=cb.labelvisible, + labelsize=cb.labelsize, + labelcolor=cb.labelcolor, + labelrotation=cb.labelrotation, + labelfont=cb.labelfont, + ticklabelfont=cb.ticklabelfont, + ticks=cb.ticks, + tickformat=cb.tickformat, + ticklabelsize=cb.ticklabelsize, + ticklabelsvisible=cb.ticklabelsvisible, + ticksize=cb.ticksize, + ticksvisible=cb.ticksvisible, + ticklabelpad=cb.ticklabelpad, + tickalign=cb.tickalign, + ticklabelrotation=cb.ticklabelrotation, + tickwidth=cb.tickwidth, + tickcolor=cb.tickcolor, + spinewidth=cb.spinewidth, + ticklabelspace=cb.ticklabelspace, + ticklabelcolor=cb.ticklabelcolor, + spinecolor=:transparent, + spinevisible=:false, + flip_vertical_label=cb.flip_vertical_label, + minorticksvisible=cb.minorticksvisible, + minortickalign=cb.minortickalign, + minorticksize=cb.minorticksize, + minortickwidth=cb.minortickwidth, + minortickcolor=cb.minortickcolor, + minorticks=cb.minorticks, + scale=cb.scale, + ) cb.axis = axis - - onany(axis.protrusion, cb.vertical, cb.flipaxis) do axprotrusion, - vertical, flipaxis - - - left, right, top, bottom = 0f0, 0f0, 0f0, 0f0 + onany(axis.protrusion, cb.vertical, cb.flipaxis) do axprotrusion, vertical, flipaxis + left, right, top, bottom = 0.0f0, 0.0f0, 0.0f0, 0.0f0 if vertical if flipaxis @@ -350,7 +373,8 @@ function initialize_block!(cb::Colorbar) end end - cb.layoutobservables.protrusions[] = GridLayoutBase.RectSides{Float32}(left, right, bottom, top) + return cb.layoutobservables.protrusions[] = + GridLayoutBase.RectSides{Float32}(left, right, bottom, top) end # trigger protrusions with one of the attributes @@ -379,5 +403,5 @@ function scaled_steps(steps, scale, lims) # scale with scaling function s_limits_scaled = scale.(s_limits) # then rescale to 0 to 1 - s_scaled = (s_limits_scaled .- s_limits_scaled[1]) ./ (s_limits_scaled[end] - s_limits_scaled[1]) + return s_scaled = (s_limits_scaled .- s_limits_scaled[1]) ./ (s_limits_scaled[end] - s_limits_scaled[1]) end diff --git a/src/makielayout/blocks/intervalslider.jl b/src/makielayout/blocks/intervalslider.jl index a8a50a6366d..4b551c9d060 100644 --- a/src/makielayout/blocks/intervalslider.jl +++ b/src/makielayout/blocks/intervalslider.jl @@ -1,5 +1,4 @@ function initialize_block!(isl::IntervalSlider) - blockscene = isl.blockscene onany(isl.linewidth, isl.horizontal) do lw, horizontal @@ -13,18 +12,15 @@ function initialize_block!(isl::IntervalSlider) sliderbox = lift(identity, isl.layoutobservables.computedbbox) endpoints = lift(sliderbox, isl.horizontal) do bb, horizontal - h = height(bb) w = width(bb) if horizontal y = bottom(bb) + h / 2 - [Point2f(left(bb) + h/2, y), - Point2f(right(bb) - h/2, y)] + [Point2f(left(bb) + h / 2, y), Point2f(right(bb) - h / 2, y)] else x = left(bb) + w / 2 - [Point2f(x, bottom(bb) + w/2), - Point2f(x, top(bb) - w/2)] + [Point2f(x, bottom(bb) + w / 2), Point2f(x, top(bb) - w / 2)] end end @@ -36,7 +32,7 @@ function initialize_block!(isl::IntervalSlider) # this is only used after dragging sliderfractions = lift(isl.selected_indices, isl.range) do is, r map(is) do i - (i - 1) / (length(r) - 1) + return (i - 1) / (length(r) - 1) end end @@ -57,11 +53,11 @@ function initialize_block!(isl::IntervalSlider) # when the range is changed, switch to closest interval on(isl.range) do rng - isl.selected_indices[] = closest_index.(Ref(rng), isl.interval[]) + return isl.selected_indices[] = closest_index.(Ref(rng), isl.interval[]) end on(isl.selected_indices) do is - isl.interval[] = getindex.(Ref(isl.range[]), is) + return isl.interval[] = getindex.(Ref(isl.range[]), is) end # initialize slider value with closest from range @@ -72,26 +68,32 @@ function initialize_block!(isl::IntervalSlider) end middlepoints = lift(endpoints, displayed_sliderfractions) do ep, sfs - [Point2f(ep[1] .+ sf .* (ep[2] .- ep[1])) for sf in sfs] + return [Point2f(ep[1] .+ sf .* (ep[2] .- ep[1])) for sf in sfs] end linepoints = lift(endpoints, middlepoints) do eps, middles - [eps[1], middles[1], middles[1], middles[2], middles[2], eps[2]] + return [eps[1], middles[1], middles[1], middles[2], middles[2], eps[2]] end linecolors = lift(isl.color_active_dimmed, isl.color_inactive) do ca, ci - [ci, ca, ci] + return [ci, ca, ci] end endbuttoncolors = lift(isl.color_active_dimmed, isl.color_inactive) do ca, ci - [ci, ci] + return [ci, ci] end - endbuttons = scatter!(blockscene, endpoints, color = endbuttoncolors, - markersize = isl.linewidth, strokewidth = 0, inspectable = false) + endbuttons = scatter!( + blockscene, + endpoints, + color=endbuttoncolors, + markersize=isl.linewidth, + strokewidth=0, + inspectable=false, + ) - linesegs = linesegments!(blockscene, linepoints, color = linecolors, - linewidth = isl.linewidth, inspectable = false) + linesegs = + linesegments!(blockscene, linepoints, color=linecolors, linewidth=isl.linewidth, inspectable=false) state = Observable(:none) button_magnifications = lift(state) do state @@ -106,8 +108,14 @@ function initialize_block!(isl::IntervalSlider) end end buttonsizes = @lift($(isl.linewidth) .* $button_magnifications) - buttons = scatter!(blockscene, middlepoints, color = isl.color_active, strokewidth = 0, - markersize = buttonsizes, inspectable = false) + buttons = scatter!( + blockscene, + middlepoints, + color=isl.color_active, + strokewidth=0, + markersize=buttonsizes, + inspectable=false, + ) mouseevents = addmouseevents!(blockscene, isl.layoutobservables.computedbbox) @@ -119,7 +127,6 @@ function initialize_block!(isl::IntervalSlider) startindices = Ref((1, 1)) onmouseleftdrag(mouseevents) do event - dragging[] = true fraction = if isl.horizontal[] (event.px[1] - endpoints[][1][1]) / (endpoints[][2][1] - endpoints[][1][1]) @@ -190,14 +197,10 @@ function initialize_block!(isl::IntervalSlider) end onmouseleftdown(mouseevents) do event - pos = event.px dim = isl.horizontal[] ? 1 : 2 - frac = clamp( - (pos[dim] - endpoints[][1][dim]) / (endpoints[][2][dim] - endpoints[][1][dim]), - 0, 1 - ) + frac = clamp((pos[dim] - endpoints[][1][dim]) / (endpoints[][2][dim] - endpoints[][1][dim]), 0, 1) startfraction[] = frac startindices[] = isl.selected_indices[] @@ -219,11 +222,12 @@ function initialize_block!(isl::IntervalSlider) end onmouseleftdoubleclick(mouseevents) do event - isl.selected_indices[] = isl.selected_indices[] = if isl.startvalues[] === Makie.automatic - (1, lastindex(isl.range[])) - else - closest_index.(Ref(isl.range[]), isl.startvalues[]) - end + isl.selected_indices[] = + isl.selected_indices[] = if isl.startvalues[] === Makie.automatic + (1, lastindex(isl.range[])) + else + closest_index.(Ref(isl.range[]), isl.startvalues[]) + end return Consume(true) end @@ -260,7 +264,6 @@ function initialize_block!(isl::IntervalSlider) return end - """ Set the `slider` to the values in the slider's range that are closest to `v1` and `v2`, and return those values ordered min, misl. """ @@ -268,5 +271,5 @@ function set_close_to!(intervalslider::IntervalSlider, v1, v2) mima = minmax(v1, v2) indices = closest_index.(Ref(intervalslider.range[]), mima) intervalslider.selected_indices[] = indices - getindex.(Ref(intervalslider.range[]), indices) + return getindex.(Ref(intervalslider.range[]), indices) end diff --git a/src/makielayout/blocks/label.jl b/src/makielayout/blocks/label.jl index a755cc54e05..09783fac86d 100644 --- a/src/makielayout/blocks/label.jl +++ b/src/makielayout/blocks/label.jl @@ -1,18 +1,28 @@ -Label(x, text; kwargs...) = Label(x; text = text, kwargs...) +Label(x, text; kwargs...) = Label(x; text=text, kwargs...) function initialize_block!(l::Label) - topscene = l.blockscene layoutobservables = l.layoutobservables textpos = Observable(Point3f(0, 0, 0)) - word_wrap_width = Observable(-1f0) + word_wrap_width = Observable(-1.0f0) t = text!( - topscene, textpos, text = l.text, fontsize = l.fontsize, font = l.font, color = l.color, - visible = l.visible, align = (:center, :center), rotation = l.rotation, markerspace = :data, - justification = l.justification, lineheight = l.lineheight, word_wrap_width = word_wrap_width, - inspectable = false) + topscene, + textpos, + text=l.text, + fontsize=l.fontsize, + font=l.font, + color=l.color, + visible=l.visible, + align=(:center, :center), + rotation=l.rotation, + markerspace=:data, + justification=l.justification, + lineheight=l.lineheight, + word_wrap_width=word_wrap_width, + inspectable=false, + ) textbb = Ref(BBox(0, 1, 0, 1)) @@ -51,11 +61,10 @@ function initialize_block!(l::Label) return end - # trigger first update, otherwise bounds are wrong somehow notify(l.text) # trigger bbox layoutobservables.suggestedbbox[] = layoutobservables.suggestedbbox[] - l + return l end diff --git a/src/makielayout/blocks/legend.jl b/src/makielayout/blocks/legend.jl index fa33e25d764..37e8e670a59 100644 --- a/src/makielayout/blocks/legend.jl +++ b/src/makielayout/blocks/legend.jl @@ -1,32 +1,39 @@ -function initialize_block!(leg::Legend, - entry_groups::Observable{Vector{Tuple{Optional{<:AbstractString}, Vector{LegendEntry}}}}) - +function initialize_block!( + leg::Legend, + entry_groups::Observable{Vector{Tuple{Optional{<:AbstractString},Vector{LegendEntry}}}}, +) blockscene = leg.blockscene # by default, `tellwidth = true` and `tellheight = false` for vertical legends # and vice versa for horizontal legends real_tellwidth = @lift $(leg.tellwidth) === automatic ? $(leg.orientation) == :vertical : $(leg.tellwidth) - real_tellheight = @lift $(leg.tellheight) === automatic ? $(leg.orientation) == :horizontal : $(leg.tellheight) + real_tellheight = + @lift $(leg.tellheight) === automatic ? $(leg.orientation) == :horizontal : $(leg.tellheight) setfield!(leg, :_tellheight, real_tellheight) setfield!(leg, :_tellwidth, real_tellwidth) legend_area = lift(round_to_IRect2D, leg.layoutobservables.computedbbox) - scene = Scene(blockscene, blockscene.px_area, camera = campixel!) + scene = Scene(blockscene, blockscene.px_area, camera=campixel!) # the rectangle in which the legend is drawn when margins are removed legendrect = @lift begin enlarge($legend_area, -$(leg.margin)[1], -$(leg.margin)[2], -$(leg.margin)[3], -$(leg.margin)[4]) end - bg = poly!(scene, + bg = poly!( + scene, legendrect, - color = leg.bgcolor, strokewidth = leg.framewidth, visible = leg.framevisible, - strokecolor = leg.framecolor, inspectable = false) + color=leg.bgcolor, + strokewidth=leg.framewidth, + visible=leg.framevisible, + strokecolor=leg.framecolor, + inspectable=false, + ) translate!(bg, 0, 0, -7) # bg behind patches but before content at 0 (legend is at +10) # the grid containing all content - grid = GridLayout(bbox = legendrect, alignmode = Outside(leg.padding[]...)) + grid = GridLayout(bbox=legendrect, alignmode=Outside(leg.padding[]...)) leg.grid = grid # while the entries are being manipulated through code, this Ref value is set to @@ -35,7 +42,7 @@ function initialize_block!(leg::Legend, on(leg.padding) do p grid.alignmode = Outside(p...) - relayout() + return relayout() end update_grid = Observable(true) @@ -74,34 +81,34 @@ function initialize_block!(leg::Legend, subgl = if leg.orientation[] == :vertical if leg.titleposition[] == :left isnothing(title) || (grid[g, 1] = title) - grid[g, 2] = GridLayout(halign = leg.gridshalign[], valign = leg.gridsvalign[]) + grid[g, 2] = GridLayout(halign=leg.gridshalign[], valign=leg.gridsvalign[]) elseif leg.titleposition[] == :top isnothing(title) || (grid[2g - 1, 1] = title) - grid[2g, 1] = GridLayout(halign = leg.gridshalign[], valign = leg.gridsvalign[]) + grid[2g, 1] = GridLayout(halign=leg.gridshalign[], valign=leg.gridsvalign[]) end elseif leg.orientation[] == :horizontal if leg.titleposition[] == :left - isnothing(title) || (grid[1, 2g-1] = title) - grid[1, 2g] = GridLayout(halign = leg.gridshalign[], valign = leg.gridsvalign[]) + isnothing(title) || (grid[1, 2g - 1] = title) + grid[1, 2g] = GridLayout(halign=leg.gridshalign[], valign=leg.gridsvalign[]) elseif leg.titleposition[] == :top isnothing(title) || (grid[1, g] = title) - grid[2, g] = GridLayout(halign = leg.gridshalign[], valign = leg.gridsvalign[]) + grid[2, g] = GridLayout(halign=leg.gridshalign[], valign=leg.gridsvalign[]) end end for (n, (et, er)) in enumerate(zip(etexts, erects)) i, j = leg.orientation[] == :vertical ? rowcol(n) : reverse(rowcol(n)) - subgl[i, 2j-1] = er + subgl[i, 2j - 1] = er subgl[i, 2j] = et end rowgap!(subgl, leg.rowgap[]) - for c in 1:ncols(subgl)-1 + for c in 1:(ncols(subgl) - 1) colgap!(subgl, c, c % 2 == 1 ? leg.patchlabelgap[] : leg.colgap[]) end end - for r in 1:nrows(grid)-1 + for r in 1:(nrows(grid) - 1) if leg.orientation[] == :horizontal if leg.titleposition[] == :left # nothing @@ -116,7 +123,7 @@ function initialize_block!(leg::Legend, end end end - for c in 1:ncols(grid)-1 + for c in 1:(ncols(grid) - 1) if leg.orientation[] == :horizontal if leg.titleposition[] == :left colgap!(grid, c, c % 2 == 1 ? leg.titlegap[] : leg.groupgap[]) @@ -132,23 +139,32 @@ function initialize_block!(leg::Legend, end end - # delete unused rows and columns trim!(grid) - manipulating_grid[] = false notify(update_grid) # translate the legend forward so it is above the standard axis content # which is at zero. this will not really work if the legend should be # above a 3d plot, but for now this hack is ok. - translate!(scene, (0, 0, 10)) + return translate!(scene, (0, 0, 10)) end - onany(leg.nbanks, leg.titleposition, leg.rowgap, leg.colgap, leg.patchlabelgap, leg.groupgap, leg.titlegap, - leg.titlevisible, leg.orientation, leg.gridshalign, leg.gridsvalign) do args... - relayout() + onany( + leg.nbanks, + leg.titleposition, + leg.rowgap, + leg.colgap, + leg.patchlabelgap, + leg.groupgap, + leg.titlegap, + leg.titlevisible, + leg.orientation, + leg.gridshalign, + leg.gridsvalign, + ) do args... + return relayout() end on(entry_groups) do entry_groups @@ -180,13 +196,22 @@ function initialize_block!(leg::Legend, preset_attrs = extractattributes(leg, LegendEntry) for (title, entries) in entry_groups - if isnothing(title) # in case a group has no title push!(titletexts, nothing) else - push!(titletexts, Label(scene, text = title, font = leg.titlefont, color = leg.titlecolor, - fontsize = leg.titlesize, halign = leg.titlehalign, valign = leg.titlevalign)) + push!( + titletexts, + Label( + scene, + text=title, + font=leg.titlefont, + color=leg.titlecolor, + fontsize=leg.titlesize, + halign=leg.titlehalign, + valign=leg.titlevalign, + ), + ) end etexts = [] @@ -202,21 +227,44 @@ function initialize_block!(leg::Legend, justification = map(leg.labeljustification, e.labelhalign) do lj, lha return lj isa Automatic ? lha : lj end - push!(etexts, - Label(scene; text=e.label, fontsize=e.labelsize, font=e.labelfont, justification=justification, - color=e.labelcolor, halign=e.labelhalign, valign=e.labelvalign)) + push!( + etexts, + Label( + scene; + text=e.label, + fontsize=e.labelsize, + font=e.labelfont, + justification=justification, + color=e.labelcolor, + halign=e.labelhalign, + valign=e.labelvalign, + ), + ) # create the patch rectangle - rect = Box(scene; color=e.patchcolor, strokecolor=e.patchstrokecolor, strokewidth=e.patchstrokewidth, - width=lift(x -> x[1], e.patchsize), height=lift(x -> x[2], e.patchsize)) + rect = Box( + scene; + color=e.patchcolor, + strokecolor=e.patchstrokecolor, + strokewidth=e.patchstrokewidth, + width=lift(x -> x[1], e.patchsize), + height=lift(x -> x[2], e.patchsize), + ) push!(erects, rect) translate!(rect.blockscene, 0, 0, -5) # patches before background but behind legend elements (legend is at +10) # plot the symbols belonging to this entry symbolplots = AbstractPlot[] for element in e.elements - append!(symbolplots, - legendelement_plots!(scene, element, rect.layoutobservables.computedbbox, e.attributes)) + append!( + symbolplots, + legendelement_plots!( + scene, + element, + rect.layoutobservables.computedbbox, + e.attributes, + ), + ) end push!(eplots, symbolplots) @@ -225,10 +273,9 @@ function initialize_block!(leg::Legend, push!(entryrects, erects) push!(entryplots, eplots) end - relayout() + return relayout() end - # trigger suggestedbbox notify(leg.layoutobservables.suggestedbbox) @@ -238,7 +285,16 @@ function initialize_block!(leg::Legend, return end -function connect_block_layoutobservables!(leg::Legend, layout_width, layout_height, layout_tellwidth, layout_tellheight, layout_halign, layout_valign, layout_alignmode) +function connect_block_layoutobservables!( + leg::Legend, + layout_width, + layout_height, + layout_tellwidth, + layout_tellheight, + layout_halign, + layout_valign, + layout_alignmode, +) connect!(layout_width, leg.width) connect!(layout_height, leg.height) # Legend has special logic for automatic tellwidth and tellheight @@ -251,18 +307,28 @@ function connect_block_layoutobservables!(leg::Legend, layout_width, layout_heig return end - -function legendelement_plots!(scene, element::MarkerElement, bbox::Observable{Rect2f}, defaultattrs::Attributes) +function legendelement_plots!( + scene, + element::MarkerElement, + bbox::Observable{Rect2f}, + defaultattrs::Attributes, +) merge!(element.attributes, defaultattrs) attrs = element.attributes fracpoints = attrs.markerpoints points = @lift(fractionpoint.(Ref($bbox), $fracpoints)) - scat = scatter!(scene, points, color = attrs.markercolor, marker = attrs.marker, - markersize = attrs.markersize, - strokewidth = attrs.markerstrokewidth, - strokecolor = attrs.markerstrokecolor, inspectable = false) - [scat] + scat = scatter!( + scene, + points, + color=attrs.markercolor, + marker=attrs.marker, + markersize=attrs.markersize, + strokewidth=attrs.markerstrokewidth, + strokecolor=attrs.markerstrokecolor, + inspectable=false, + ) + return [scat] end function legendelement_plots!(scene, element::LineElement, bbox::Observable{Rect2f}, defaultattrs::Attributes) @@ -271,9 +337,15 @@ function legendelement_plots!(scene, element::LineElement, bbox::Observable{Rect fracpoints = attrs.linepoints points = @lift(fractionpoint.(Ref($bbox), $fracpoints)) - lin = lines!(scene, points, linewidth = attrs.linewidth, color = attrs.linecolor, - linestyle = attrs.linestyle, inspectable = false) - [lin] + lin = lines!( + scene, + points, + linewidth=attrs.linewidth, + color=attrs.linecolor, + linestyle=attrs.linestyle, + inspectable=false, + ) + return [lin] end function legendelement_plots!(scene, element::PolyElement, bbox::Observable{Rect2f}, defaultattrs::Attributes) @@ -282,89 +354,84 @@ function legendelement_plots!(scene, element::PolyElement, bbox::Observable{Rect fracpoints = attrs.polypoints points = @lift(fractionpoint.(Ref($bbox), $fracpoints)) - pol = poly!(scene, points, strokewidth = attrs.polystrokewidth, color = attrs.polycolor, - strokecolor = attrs.polystrokecolor, inspectable = false) - [pol] + pol = poly!( + scene, + points, + strokewidth=attrs.polystrokewidth, + color=attrs.polycolor, + strokecolor=attrs.polystrokecolor, + inspectable=false, + ) + return [pol] end -function Base.getproperty(lentry::LegendEntry, s::Symbol) +Base.getproperty(lentry::LegendEntry, s::Symbol) = if s in fieldnames(LegendEntry) getfield(lentry, s) else lentry.attributes[s] end -end -function Base.setproperty!(lentry::LegendEntry, s::Symbol, value) +Base.setproperty!(lentry::LegendEntry, s::Symbol, value) = if s in fieldnames(LegendEntry) setfield!(lentry, s, value) else lentry.attributes[s][] = value end -end -function Base.propertynames(lentry::LegendEntry) - [fieldnames(T)..., keys(lentry.attributes)...] -end +Base.propertynames(lentry::LegendEntry) = [fieldnames(T)..., keys(lentry.attributes)...] legendelements(le::LegendElement, legend) = LegendElement[le] legendelements(les::AbstractArray{<:LegendElement}, legend) = LegendElement[les...] - function LegendEntry(label::Optional{AbstractString}, contentelements::AbstractArray, legend; kwargs...) - attrs = Attributes(label = label) + attrs = Attributes(label=label) kwargattrs = Attributes(kwargs) merge!(attrs, kwargattrs) elems = vcat(legendelements.(contentelements, Ref(legend))...) - LegendEntry(elems, attrs) + return LegendEntry(elems, attrs) end function LegendEntry(label::Optional{AbstractString}, contentelement, legend; kwargs...) - attrs = Attributes(label = label) + attrs = Attributes(label=label) kwargattrs = Attributes(kwargs) merge!(attrs, kwargattrs) elems = legendelements(contentelement, legend) - LegendEntry(elems, attrs) + return LegendEntry(elems, attrs) end +LineElement(; kwargs...) = _legendelement(LineElement, Attributes(kwargs)) -function LineElement(;kwargs...) - _legendelement(LineElement, Attributes(kwargs)) -end +MarkerElement(; kwargs...) = _legendelement(MarkerElement, Attributes(kwargs)) -function MarkerElement(;kwargs...) - _legendelement(MarkerElement, Attributes(kwargs)) -end - -function PolyElement(;kwargs...) - _legendelement(PolyElement, Attributes(kwargs)) -end +PolyElement(; kwargs...) = _legendelement(PolyElement, Attributes(kwargs)) function _legendelement(T::Type{<:LegendElement}, a::Attributes) _rename_attributes!(T, a) - T(a) + return T(a) end -_renaming_mapping(::Type{LineElement}) = Dict( - :points => :linepoints, - :color => :linecolor, -) -_renaming_mapping(::Type{MarkerElement}) = Dict( - :points => :markerpoints, - :color => :markercolor, - :strokewidth => :markerstrokewidth, - :strokecolor => :markerstrokecolor, -) -_renaming_mapping(::Type{PolyElement}) = Dict( - :points => :polypoints, - :color => :polycolor, - :strokewidth => :polystrokewidth, - :strokecolor => :polystrokecolor, -) +_renaming_mapping(::Type{LineElement}) = Dict(:points => :linepoints, :color => :linecolor) +function _renaming_mapping(::Type{MarkerElement}) + return Dict( + :points => :markerpoints, + :color => :markercolor, + :strokewidth => :markerstrokewidth, + :strokecolor => :markerstrokecolor, + ) +end +function _renaming_mapping(::Type{PolyElement}) + return Dict( + :points => :polypoints, + :color => :polycolor, + :strokewidth => :polystrokewidth, + :strokecolor => :polystrokecolor, + ) +end function _rename_attributes!(T, a) m = _renaming_mapping(T) @@ -377,67 +444,71 @@ function _rename_attributes!(T, a) a[newkey] = pop!(a, key) end end - a + return a end - function scalar_lift(attr, default) observable = Observable{Any}() map!(observable, attr, default) do at, def - Makie.is_scalar_attribute(at) ? at : def + return Makie.is_scalar_attribute(at) ? at : def end return observable end -function legendelements(plot::Union{Lines, LineSegments}, legend) - LegendElement[LineElement( - color = scalar_lift(plot.color, legend.linecolor), - linestyle = scalar_lift(plot.linestyle, legend.linestyle), - linewidth = scalar_lift(plot.linewidth, legend.linewidth))] +function legendelements(plot::Union{Lines,LineSegments}, legend) + return LegendElement[LineElement( + color=scalar_lift(plot.color, legend.linecolor), + linestyle=scalar_lift(plot.linestyle, legend.linestyle), + linewidth=scalar_lift(plot.linewidth, legend.linewidth), + )] end - function legendelements(plot::Scatter, legend) - LegendElement[MarkerElement( - color = scalar_lift(plot.color, legend.markercolor), - marker = scalar_lift(plot.marker, legend.marker), - markersize = scalar_lift(plot.markersize, legend.markersize), - strokewidth = scalar_lift(plot.strokewidth, legend.markerstrokewidth), - strokecolor = scalar_lift(plot.strokecolor, legend.markerstrokecolor), + return LegendElement[MarkerElement( + color=scalar_lift(plot.color, legend.markercolor), + marker=scalar_lift(plot.marker, legend.marker), + markersize=scalar_lift(plot.markersize, legend.markersize), + strokewidth=scalar_lift(plot.strokewidth, legend.markerstrokewidth), + strokecolor=scalar_lift(plot.strokecolor, legend.markerstrokecolor), )] end -function legendelements(plot::Union{Poly, Violin, BoxPlot, CrossBar, Density}, legend) - LegendElement[PolyElement( - color = scalar_lift(plot.color, legend.polycolor), - strokecolor = scalar_lift(plot.strokecolor, legend.polystrokecolor), - strokewidth = scalar_lift(plot.strokewidth, legend.polystrokewidth), +function legendelements(plot::Union{Poly,Violin,BoxPlot,CrossBar,Density}, legend) + return LegendElement[PolyElement( + color=scalar_lift(plot.color, legend.polycolor), + strokecolor=scalar_lift(plot.strokecolor, legend.polystrokecolor), + strokewidth=scalar_lift(plot.strokewidth, legend.polystrokewidth), )] end function legendelements(plot::Band, legend) # there seems to be no stroke for Band, so we set it invisible - LegendElement[PolyElement(polycolor = scalar_lift(plot.color, legend.polystrokecolor), polystrokecolor = :transparent, polystrokewidth = 0)] + return LegendElement[PolyElement( + polycolor=scalar_lift(plot.color, legend.polystrokecolor), + polystrokecolor=:transparent, + polystrokewidth=0, + )] end # if there is no specific overload available, we go through the child plots and just stack # those together as a simple fallback function legendelements(plot, legend)::Vector{LegendElement} if isempty(plot.plots) - error("No child plot elements found in plot of type $(typeof(plot)) but also no `legendelements` method defined.") + error( + "No child plot elements found in plot of type $(typeof(plot)) but also no `legendelements` method defined.", + ) end - reduce(vcat, [legendelements(childplot, legend) for childplot in plot.plots]) + return reduce(vcat, [legendelements(childplot, legend) for childplot in plot.plots]) end -function Base.getproperty(legendelement::T, s::Symbol) where T <: LegendElement +Base.getproperty(legendelement::T, s::Symbol) where {T<:LegendElement} = if s in fieldnames(T) getfield(legendelement, s) else legendelement.attributes[s] end -end -function Base.setproperty!(legendelement::T, s::Symbol, value) where T <: LegendElement +function Base.setproperty!(legendelement::T, s::Symbol, value) where {T<:LegendElement} if s in fieldnames(T) setfield!(legendelement, s, value) else @@ -445,12 +516,10 @@ function Base.setproperty!(legendelement::T, s::Symbol, value) where T <: Legend end end -function Base.propertynames(legendelement::T) where T <: LegendElement - [fieldnames(T)..., keys(legendelement.attributes)...] +function Base.propertynames(legendelement::T) where {T<:LegendElement} + return [fieldnames(T)..., keys(legendelement.attributes)...] end - - """ Legend( fig_or_scene, @@ -464,25 +533,26 @@ one content element. A content element can be an `AbstractPlot`, an array of `AbstractPlots`, a `LegendElement`, or any other object for which the `legendelements` method is defined. """ -function Legend(fig_or_scene, - contents::AbstractArray, - labels::AbstractArray{<:Optional{AbstractString}}, - title::Optional{<:AbstractString} = nothing; - kwargs...) - +function Legend( + fig_or_scene, + contents::AbstractArray, + labels::AbstractArray{<:Optional{AbstractString}}, + title::Optional{<:AbstractString}=nothing; + kwargs..., +) if length(contents) != length(labels) - error("Number of elements not equal: $(length(contents)) content elements and $(length(labels)) labels.") + error( + "Number of elements not equal: $(length(contents)) content elements and $(length(labels)) labels.", + ) end entrygroups = Observable{Vector{EntryGroup}}([]) legend = Legend(fig_or_scene, entrygroups; kwargs...) entries = [LegendEntry(label, content, legend) for (content, label) in zip(contents, labels)] entrygroups[] = [(title, entries)] - legend + return legend end - - """ Legend( fig_or_scene, @@ -499,26 +569,29 @@ Within each group, each content element is associated with one label. A content element can be an `AbstractPlot`, an array of `AbstractPlots`, a `LegendElement`, or any other object for which the `legendelements` method is defined. """ -function Legend(fig_or_scene, - contentgroups::AbstractArray{<:AbstractArray}, - labelgroups::AbstractArray{<:AbstractArray}, - titles::AbstractArray{<:Optional{<:AbstractString}}; - kwargs...) - +function Legend( + fig_or_scene, + contentgroups::AbstractArray{<:AbstractArray}, + labelgroups::AbstractArray{<:AbstractArray}, + titles::AbstractArray{<:Optional{<:AbstractString}}; + kwargs..., +) if !(length(titles) == length(contentgroups) == length(labelgroups)) - error("Number of elements not equal: $(length(titles)) titles, $(length(contentgroups)) content groups and $(length(labelgroups)) label groups.") + error( + "Number of elements not equal: $(length(titles)) titles, $(length(contentgroups)) content groups and $(length(labelgroups)) label groups.", + ) end - entrygroups = Observable{Vector{EntryGroup}}([]) legend = Legend(fig_or_scene, entrygroups; kwargs...) - entries = [[LegendEntry(l, pg, legend) for (l, pg) in zip(labelgroup, contentgroup)] - for (labelgroup, contentgroup) in zip(labelgroups, contentgroups)] + entries = [ + [LegendEntry(l, pg, legend) for (l, pg) in zip(labelgroup, contentgroup)] for + (labelgroup, contentgroup) in zip(labelgroups, contentgroups) + ] entrygroups[] = [(t, en) for (t, en) in zip(titles, entries)] - legend + return legend end - """ Legend(fig_or_scene, axis::Union{Axis, Scene, LScene}, title = nothing; merge = false, unique = false, kwargs...) @@ -528,18 +601,27 @@ attribute `label` set. If `merge` is `true`, all plot objects with the same label will be layered on top of each other into one legend entry. If `unique` is `true`, all plot objects with the same plot type and label will be reduced to one occurrence. """ -function Legend(fig_or_scene, axis::Union{Axis, Axis3, Scene, LScene}, title = nothing; merge = false, unique = false, kwargs...) - plots, labels = get_labeled_plots(axis, merge = merge, unique = unique) - isempty(plots) && error("There are no plots with labels in the given axis that can be put in the legend. Supply labels to plotting functions like `plot(args...; label = \"My label\")`") - Legend(fig_or_scene, plots, labels, title; kwargs...) +function Legend( + fig_or_scene, + axis::Union{Axis,Axis3,Scene,LScene}, + title=nothing; + merge=false, + unique=false, + kwargs..., +) + plots, labels = get_labeled_plots(axis, merge=merge, unique=unique) + isempty(plots) && error( + "There are no plots with labels in the given axis that can be put in the legend. Supply labels to plotting functions like `plot(args...; label = \"My label\")`", + ) + return Legend(fig_or_scene, plots, labels, title; kwargs...) end function get_labeled_plots(ax; merge::Bool, unique::Bool) lplots = filter(get_plots(ax)) do plot - haskey(plot.attributes, :label) + return haskey(plot.attributes, :label) end labels = map(lplots) do l - l.label[] + return l.label[] end # filter out plots with same plot type and label @@ -551,17 +633,16 @@ function get_labeled_plots(ax; merge::Bool, unique::Bool) if merge ulabels = Base.unique(labels) - mergedplots = [[lp for (i, lp) in enumerate(lplots) if labels[i] == ul] - for ul in ulabels] + mergedplots = [[lp for (i, lp) in enumerate(lplots) if labels[i] == ul] for ul in ulabels] lplots, labels = mergedplots, ulabels end - lplots, labels + return lplots, labels end get_plots(p::AbstractPlot) = [p] -get_plots(ax::Union{Axis, Axis3}) = get_plots(ax.scene) +get_plots(ax::Union{Axis,Axis3}) = get_plots(ax.scene) get_plots(lscene::LScene) = get_plots(lscene.scene) function get_plots(scene::Scene) plots = AbstractPlot[] @@ -572,7 +653,7 @@ function get_plots(scene::Scene) end # convenience constructor for axis legend -axislegend(ax = current_axis(); kwargs...) = axislegend(ax, ax; kwargs...) +axislegend(ax=current_axis(); kwargs...) = axislegend(ax, ax; kwargs...) axislegend(title::AbstractString; kwargs...) = axislegend(current_axis(), current_axis(), title; kwargs...) @@ -595,35 +676,28 @@ label will be layered on top of each other into one legend entry. If unique is true, all plot objects with the same plot type and label will be reduced to one occurrence. """ -function axislegend(ax, args...; position = :rt, kwargs...) - Legend(ax.parent, args...; - bbox = ax.scene.px_area, - margin = (10, 10, 10, 10), +function axislegend(ax, args...; position=:rt, kwargs...) + return Legend( + ax.parent, + args...; + bbox=ax.scene.px_area, + margin=(10, 10, 10, 10), legend_position_to_aligns(position)..., - kwargs...) + kwargs..., + ) end function legend_position_to_aligns(s::Symbol) p = string(s) length(p) != 2 && throw(ArgumentError("Position symbol must have length == 2")) - haligns = Dict( - 'l' => :left, - 'r' => :right, - 'c' => :center, - ) + haligns = Dict('l' => :left, 'r' => :right, 'c' => :center) haskey(haligns, p[1]) || throw(ArgumentError("First letter can be l, r or c, not $(p[1]).")) - valigns = Dict( - 't' => :top, - 'b' => :bottom, - 'c' => :center, - ) + valigns = Dict('t' => :top, 'b' => :bottom, 'c' => :center) haskey(valigns, p[2]) || throw(ArgumentError("Second letter can be b, t or c, not $(p[2]).")) - (halign = haligns[p[1]], valign = valigns[p[2]]) + return (halign=haligns[p[1]], valign=valigns[p[2]]) end -function legend_position_to_aligns(t::Tuple{Any, Any}) - (halign = t[1], valign = t[2]) -end +legend_position_to_aligns(t::Tuple{Any,Any}) = (halign=t[1], valign=t[2]) diff --git a/src/makielayout/blocks/menu.jl b/src/makielayout/blocks/menu.jl index c1083b5bb96..3abbcb7797c 100644 --- a/src/makielayout/blocks/menu.jl +++ b/src/makielayout/blocks/menu.jl @@ -1,54 +1,53 @@ function block_docs(::Type{Menu}) - """ - A drop-down menu with multiple selectable options. You can pass options - with the keyword argument `options`. + return """ + A drop-down menu with multiple selectable options. You can pass options + with the keyword argument `options`. - Options are given as an iterable of elements. - For each element, the option label in the menu is determined with `optionlabel(element)` - and the option value with `optionvalue(element)`. These functions can be - overloaded for custom types. The default is that tuples of two elements are expected to be label and value, - where `string(label)` is used as the label, while for all other objects, label = `string(object)` and value = object. + Options are given as an iterable of elements. + For each element, the option label in the menu is determined with `optionlabel(element)` + and the option value with `optionvalue(element)`. These functions can be + overloaded for custom types. The default is that tuples of two elements are expected to be label and value, + where `string(label)` is used as the label, while for all other objects, label = `string(object)` and value = object. - When an item is selected in the menu, the menu's `selection` attribute is set to - `optionvalue(selected_element)`. When nothing is selected, that value is `nothing`. + When an item is selected in the menu, the menu's `selection` attribute is set to + `optionvalue(selected_element)`. When nothing is selected, that value is `nothing`. - You can set the initial selection by passing one of the labels with the `default` keyword. + You can set the initial selection by passing one of the labels with the `default` keyword. - ## Constructors + ## Constructors - ```julia - Menu(fig_or_scene; default = nothing, kwargs...) - ``` + ```julia + Menu(fig_or_scene; default = nothing, kwargs...) + ``` - ## Examples + ## Examples - Menu with string entries, second preselected: + Menu with string entries, second preselected: - ```julia - menu1 = Menu(fig[1, 1], options = ["first", "second", "third"], default = "second") - ``` + ```julia + menu1 = Menu(fig[1, 1], options = ["first", "second", "third"], default = "second") + ``` - Menu with two-element entries, label and function: + Menu with two-element entries, label and function: - ```julia - funcs = [sin, cos, tan] - labels = ["Sine", "Cosine", "Tangens"] + ```julia + funcs = [sin, cos, tan] + labels = ["Sine", "Cosine", "Tangens"] - menu2 = Menu(fig[1, 1], options = zip(labels, funcs)) - ``` + menu2 = Menu(fig[1, 1], options = zip(labels, funcs)) + ``` - Executing a function when a selection is made: + Executing a function when a selection is made: - ```julia - on(menu2.selection) do selected_function - # do something with the selected function - end - ``` - """ + ```julia + on(menu2.selection) do selected_function + # do something with the selected function + end + ``` + """ end - -function initialize_block!(m::Menu; default = 1) +function initialize_block!(m::Menu; default=1) blockscene = m.blockscene listheight = Observable(0.0; ignore_equal_values=true) @@ -73,24 +72,32 @@ function initialize_block!(m::Menu; default = 1) end end - scenearea = lift(m.layoutobservables.computedbbox, listheight, _direction, m.is_open; ignore_equal_values=true) do bbox, h, d, open - !open ? - round_to_IRect2D(BBox(left(bbox), right(bbox), 0, 0)) : - round_to_IRect2D(BBox( + scenearea = lift( + m.layoutobservables.computedbbox, + listheight, + _direction, + m.is_open; + ignore_equal_values=true, + ) do bbox, h, d, open + return !open ? round_to_IRect2D(BBox(left(bbox), right(bbox), 0, 0)) : + round_to_IRect2D( + BBox( left(bbox), right(bbox), d == :down ? max(0, bottom(bbox) - h) : top(bbox), - d == :down ? bottom(bbox) : min(top(bbox) + h, top(blockscene.px_area[])))) + d == :down ? bottom(bbox) : min(top(bbox) + h, top(blockscene.px_area[])), + ), + ) end - menuscene = Scene(blockscene, scenearea, camera = campixel!, clear=true) + menuscene = Scene(blockscene, scenearea, camera=campixel!, clear=true) translate!(menuscene, 0, 0, 200) onany(scenearea, listheight) do area, listheight t = translation(menuscene)[] y = t[2] new_y = max(min(0, y), height(area) - listheight) - translate!(menuscene, t[1], new_y, t[3]) + return translate!(menuscene, t[1], new_y, t[3]) end optionstrings = lift(o -> optionlabel.(o), m.options; ignore_equal_values=true) @@ -105,27 +112,31 @@ function initialize_block!(m::Menu; default = 1) selectionarea = Observable(Rect2f(0, 0, 0, 0); ignore_equal_values=true) - selectionpoly = poly!( - blockscene, selectionarea, color = m.selection_cell_color_inactive[]; - inspectable = false - ) + selectionpoly = + poly!(blockscene, selectionarea, color=m.selection_cell_color_inactive[]; inspectable=false) selectiontextpos = Observable(Point2f(0, 0); ignore_equal_values=true) selectiontext = text!( - blockscene, selectiontextpos, text = selected_text, align = (:left, :center), - fontsize = m.fontsize, color = m.textcolor, markerspace = :data, inspectable = false + blockscene, + selectiontextpos, + text=selected_text, + align=(:left, :center), + fontsize=m.fontsize, + color=m.textcolor, + markerspace=:data, + inspectable=false, ) onany(selected_text, m.fontsize, m.textpadding) do _, _, (l, r, b, t) bb = boundingbox(selectiontext) - m.layoutobservables.autosize[] = width(bb) + l + r, height(bb) + b + t + return m.layoutobservables.autosize[] = width(bb) + l + r, height(bb) + b + t end notify(selected_text) on(m.layoutobservables.computedbbox) do cbb selectionarea[] = cbb ch = height(cbb) - selectiontextpos[] = cbb.origin + Point2f(m.textpadding[][1], ch/2) + return selectiontextpos[] = cbb.origin + Point2f(m.textpadding[][1], ch / 2) end textpositions = Observable(zeros(Point2f, length(optionstrings[])); ignore_equal_values=true) @@ -149,15 +160,21 @@ function initialize_block!(m::Menu; default = 1) end end end - notify(optionpolycolors) + return notify(optionpolycolors) end # the y boundaries of the list rectangles list_y_bounds = Ref(Float32[]) - optionpolys = poly!(menuscene, optionrects, color = optionpolycolors, inspectable = false) - optiontexts = text!(menuscene, textpositions, text = optionstrings, align = (:left, :center), - fontsize = m.fontsize, inspectable = false) + optionpolys = poly!(menuscene, optionrects, color=optionpolycolors, inspectable=false) + optiontexts = text!( + menuscene, + textpositions, + text=optionstrings, + align=(:left, :center), + fontsize=m.fontsize, + inspectable=false, + ) onany(optionstrings, m.textpadding, m.layoutobservables.computedbbox) do _, pad, bbox gcs = optiontexts.plots[1][1][]::Vector{GlyphCollection} @@ -166,7 +183,7 @@ function initialize_block!(m::Menu; default = 1) heights_cumsum = [zero(eltype(heights)); cumsum(heights)] h = sum(heights) list_y_bounds[] = h .- heights_cumsum - texts_y = @views h .- 0.5 .* (heights_cumsum[1:end-1] .+ heights_cumsum[2:end]) + texts_y = @views h .- 0.5 .* (heights_cumsum[1:(end - 1)] .+ heights_cumsum[2:end]) textpositions[] = Point2f.(pad[1], texts_y) listheight[] = h w_bbox = width(bbox) @@ -174,11 +191,11 @@ function initialize_block!(m::Menu; default = 1) resize!(optionrects.val, length(bbs)) optionrects.val .= map(eachindex(bbs)) do i - BBox(0, w_bbox, h - heights_cumsum[i+1], h - heights_cumsum[i]) + return BBox(0, w_bbox, h - heights_cumsum[i + 1], h - heights_cumsum[i]) end update_option_colors!(0) - notify(optionrects) + return notify(optionrects) end notify(optionstrings) @@ -188,9 +205,9 @@ function initialize_block!(m::Menu; default = 1) # of the text from the picking value returned # translation due to scrolling has to be removed first ytrans = y - translation(menuscene)[][2] - i = argmin( - i -> abs(ytrans - 0.5 * (list_y_bounds[][i+1] + list_y_bounds[][i])), - 1:length(list_y_bounds[])-1 + return i = argmin( + i -> abs(ytrans - 0.5 * (list_y_bounds[][i + 1] + list_y_bounds[][i])), + 1:(length(list_y_bounds[]) - 1), ) end @@ -320,16 +337,17 @@ function initialize_block!(m::Menu; default = 1) end # trigger eventual selection actions - m.i_selected[] = new_i + return m.i_selected[] = new_i end dropdown_arrow = scatter!( blockscene, @lift(mean(rightline($selectionarea)) - Point2f($(m.textpadding)[2], 0)), - marker = @lift($(m.is_open) ? '▴' : '▾'), - markersize = m.dropdown_arrow_size, - color = m.dropdown_arrow_color, - strokecolor = :transparent, - inspectable = false) + marker=@lift($(m.is_open) ? '▴' : '▾'), + markersize=m.dropdown_arrow_size, + color=m.dropdown_arrow_color, + strokecolor=:transparent, + inspectable=false, + ) translate!(dropdown_arrow, 0, 0, 1) @@ -361,7 +379,7 @@ function initialize_block!(m::Menu; default = 1) if i === nothing error("Initial menu selection was set to $(default) but that was not found in the option names.") end - m.i_selected[] = i + m.i_selected[] = i end notify(m.is_open) @@ -371,18 +389,10 @@ function initialize_block!(m::Menu; default = 1) return end -function optionlabel(option) - string(option) -end +optionlabel(option) = string(option) -function optionlabel(option::Tuple{Any, Any}) - string(option[1]) -end +optionlabel(option::Tuple{Any,Any}) = string(option[1]) -function optionvalue(option) - option -end +optionvalue(option) = option -function optionvalue(option::Tuple{Any, Any}) - option[2] -end +optionvalue(option::Tuple{Any,Any}) = option[2] diff --git a/src/makielayout/blocks/scene.jl b/src/makielayout/blocks/scene.jl index f1c05989190..0f35f92336c 100644 --- a/src/makielayout/blocks/scene.jl +++ b/src/makielayout/blocks/scene.jl @@ -1,25 +1,27 @@ function Makie.plot!( - lscene::LScene, P::Makie.PlotFunc, - attributes::Makie.Attributes, args...; - kw_attributes...) - + lscene::LScene, + P::Makie.PlotFunc, + attributes::Makie.Attributes, + args...; + kw_attributes..., +) plot = Makie.plot!(lscene.scene, P, attributes, args...; kw_attributes...) notify(lscene.scene.theme.limits) center!(lscene.scene) - plot + return plot end function Makie.plot!(P::Makie.PlotFunc, ls::LScene, args...; kw_attributes...) attributes = Makie.Attributes(kw_attributes) _disallow_keyword(:axis, attributes) _disallow_keyword(:figure, attributes) - Makie.plot!(ls, P, attributes, args...) + return Makie.plot!(ls, P, attributes, args...) end -function initialize_block!(ls::LScene; scenekw = NamedTuple()) +function initialize_block!(ls::LScene; scenekw=NamedTuple()) blockscene = ls.blockscene # pick a camera and draw axis. - scenekw = merge((clear = false, camera=cam3d!), scenekw) + scenekw = merge((clear=false, camera=cam3d!), scenekw) ls.scene = Scene(blockscene, lift(round_to_IRect2D, ls.layoutobservables.computedbbox); scenekw...) on(ls.show_axis) do show_axis @@ -32,7 +34,7 @@ function initialize_block!(ls::LScene; scenekw = NamedTuple()) if lims === automatic dl = data_limits(ls.scene, p -> Makie.isaxis(p) || Makie.not_in_data_space(p)) if any(isinf, widths(dl)) || any(isinf, Makie.origin(dl)) - Rect3f((0f0, 0f0, 0f0), (1f0, 1f0, 1f0)) + Rect3f((0.0f0, 0.0f0, 0.0f0), (1.0f0, 1.0f0, 1.0f0)) else dl end @@ -58,7 +60,7 @@ end function Base.delete!(ax::LScene, plot::AbstractPlot) delete!(ax.scene, plot) - ax + return ax end can_be_current_axis(ls::LScene) = true diff --git a/src/makielayout/blocks/slider.jl b/src/makielayout/blocks/slider.jl index 000b5f8ff72..3e667ce3c34 100644 --- a/src/makielayout/blocks/slider.jl +++ b/src/makielayout/blocks/slider.jl @@ -1,9 +1,8 @@ function initialize_block!(sl::Slider) - topscene = sl.blockscene sliderrange = sl.range - + onany(sl.linewidth, sl.horizontal) do lw, horizontal if horizontal sl.layoutobservables.autosize[] = (nothing, Float32(lw)) @@ -15,18 +14,15 @@ function initialize_block!(sl::Slider) sliderbox = lift(identity, sl.layoutobservables.computedbbox) endpoints = lift(sliderbox, sl.horizontal) do bb, horizontal - h = height(bb) w = width(bb) if horizontal y = bottom(bb) + h / 2 - [Point2f(left(bb) + h/2, y), - Point2f(right(bb) - h/2, y)] + [Point2f(left(bb) + h / 2, y), Point2f(right(bb) - h / 2, y)] else x = left(bb) + w / 2 - [Point2f(x, bottom(bb) + w/2), - Point2f(x, top(bb) - w/2)] + [Point2f(x, bottom(bb) + w / 2), Point2f(x, top(bb) - w / 2)] end end @@ -37,7 +33,7 @@ function initialize_block!(sl::Slider) # the fraction on the slider corresponding to the selected_index # this is only used after dragging sliderfraction = lift(selected_index, sliderrange) do i, r - (i - 1) / (length(r) - 1) + return (i - 1) / (length(r) - 1) end dragging = Observable(false) @@ -56,38 +52,52 @@ function initialize_block!(sl::Slider) # when the range is changed, switch to closest value on(sliderrange) do rng - selected_index[] = closest_index(rng, sl.value[]) + return selected_index[] = closest_index(rng, sl.value[]) end on(selected_index) do i - sl.value[] = sliderrange[][i] + return sl.value[] = sliderrange[][i] end # initialize slider value with closest from range selected_index[] = closest_index(sliderrange[], sl.startvalue[]) middlepoint = lift(endpoints, displayed_sliderfraction) do ep, sf - Point2f(ep[1] .+ sf .* (ep[2] .- ep[1])) + return Point2f(ep[1] .+ sf .* (ep[2] .- ep[1])) end linepoints = lift(endpoints, middlepoint) do eps, middle - [eps[1], middle, middle, eps[2]] + return [eps[1], middle, middle, eps[2]] end linecolors = lift(sl.color_active_dimmed, sl.color_inactive) do ca, ci - [ca, ci] + return [ca, ci] end - endbuttons = scatter!(topscene, endpoints, color = linecolors, - markersize = sl.linewidth, strokewidth = 0, inspectable = false, marker=Circle) + endbuttons = scatter!( + topscene, + endpoints, + color=linecolors, + markersize=sl.linewidth, + strokewidth=0, + inspectable=false, + marker=Circle, + ) - linesegs = linesegments!(topscene, linepoints, color = linecolors, - linewidth = sl.linewidth, inspectable = false) + linesegs = + linesegments!(topscene, linepoints, color=linecolors, linewidth=sl.linewidth, inspectable=false) button_magnification = Observable(1.0) buttonsize = @lift($(sl.linewidth) * $button_magnification) - button = scatter!(topscene, middlepoint, color = sl.color_active, strokewidth = 0, - markersize = buttonsize, inspectable = false, marker=Circle) + button = scatter!( + topscene, + middlepoint, + color=sl.color_active, + strokewidth=0, + markersize=buttonsize, + inspectable=false, + marker=Circle, + ) mouseevents = addmouseevents!(topscene, sl.layoutobservables.computedbbox) @@ -148,7 +158,7 @@ function initialize_block!(sl::Slider) # trigger autosize through linewidth for first layout sl.linewidth[] = sl.linewidth[] - sl + return sl end function valueindex(sliderrange, value) @@ -157,14 +167,14 @@ function valueindex(sliderrange, value) return i end end - nothing + return nothing end function closest_fractionindex(sliderrange, fraction) n = length(sliderrange) onestepfrac = 1 / (n - 1) i = round(Int, fraction / onestepfrac) + 1 - min(max(i, 1), n) + return min(max(i, 1), n) end function closest_index(sliderrange, value) @@ -174,7 +184,7 @@ function closest_index(sliderrange, value) end end # if the value wasn't found this way try inexact - closest_index_inexact(sliderrange, value) + return closest_index_inexact(sliderrange, value) end function closest_index_inexact(sliderrange, value) @@ -187,7 +197,7 @@ function closest_index_inexact(sliderrange, value) selected_i = i end end - selected_i + return selected_i end """ @@ -196,5 +206,5 @@ Set the `slider` to the value in the slider's range that is closest to `value` a function set_close_to!(slider::Slider, value) closest = closest_index(slider.range[], value) slider.selected_index = closest - slider.range[][closest] + return slider.range[][closest] end diff --git a/src/makielayout/blocks/slidergrid.jl b/src/makielayout/blocks/slidergrid.jl index ea57b2fcad4..5947ff4af29 100644 --- a/src/makielayout/blocks/slidergrid.jl +++ b/src/makielayout/blocks/slidergrid.jl @@ -1,46 +1,45 @@ function block_docs(::Type{SliderGrid}) - """ - A grid of horizontal `Slider`s, where each slider has one name label on the left, - and a value label on the right. + return """ + A grid of horizontal `Slider`s, where each slider has one name label on the left, + and a value label on the right. - Each `NamedTuple` you pass specifies one `Slider`. You always have to pass `range` - and `label`, and optionally a `format` for the value label. Beyond that, you can set - any keyword that `Slider` takes, such as `startvalue`. + Each `NamedTuple` you pass specifies one `Slider`. You always have to pass `range` + and `label`, and optionally a `format` for the value label. Beyond that, you can set + any keyword that `Slider` takes, such as `startvalue`. - The `format` keyword can be a `String` with Formatting.jl style, such as "{:.2f}Hz", or - a function. + The `format` keyword can be a `String` with Formatting.jl style, such as "{:.2f}Hz", or + a function. - ## Constructors + ## Constructors - ```julia - SliderGrid(fig_or_scene, nts::NamedTuple...; kwargs...) - ``` + ```julia + SliderGrid(fig_or_scene, nts::NamedTuple...; kwargs...) + ``` - ## Examples + ## Examples - ```julia - sg = SliderGrid(fig[1, 1], - (label = "Amplitude", range = 0:0.1:10, startvalue = 5), - (label = "Frequency", range = 0:0.5:50, format = "{:.1f}Hz", startvalue = 10), - (label = "Phase", range = 0:0.01:2pi, - format = x -> string(round(x/pi, digits = 2), "π")) - ) - ``` + ```julia + sg = SliderGrid(fig[1, 1], + (label = "Amplitude", range = 0:0.1:10, startvalue = 5), + (label = "Frequency", range = 0:0.5:50, format = "{:.1f}Hz", startvalue = 10), + (label = "Phase", range = 0:0.01:2pi, + format = x -> string(round(x/pi, digits = 2), "π")) + ) + ``` - Working with slider values: + Working with slider values: - ```julia - on(sg.sliders[1].value) do val - # do something with `val` - end - ``` - """ + ```julia + on(sg.sliders[1].value) do val + # do something with `val` + end + ``` + """ end function initialize_block!(sg::SliderGrid, nts::NamedTuple...) - default_format(x) = string(x) - default_format(x::AbstractFloat) = string(round(x, sigdigits = 3)) + default_format(x::AbstractFloat) = string(round(x, sigdigits=3)) sg.sliders = Slider[] sg.valuelabels = Label[] @@ -55,10 +54,9 @@ function initialize_block!(sg::SliderGrid, nts::NamedTuple...) range = nt.range format = haskey(nt, :format) ? nt.format : default_format remaining_pairs = filter(pair -> pair[1] ∉ (:label, :range, :format), pairs(nt)) - l = Label(sg.layout[i, 1], label, halign = :left) - slider = Slider(sg.layout[i, 2]; range = range, remaining_pairs...) - vl = Label(sg.layout[i, 3], - lift(x -> apply_format(x, format), slider.value), halign = :right) + l = Label(sg.layout[i, 1], label, halign=:left) + slider = Slider(sg.layout[i, 2]; range=range, remaining_pairs...) + vl = Label(sg.layout[i, 3], lift(x -> apply_format(x, format), slider.value), halign=:right) push!(sg.valuelabels, vl) push!(sg.sliders, slider) push!(sg.labels, l) diff --git a/src/makielayout/blocks/textbox.jl b/src/makielayout/blocks/textbox.jl index 9c4b21fa1d0..bef0e074ca9 100644 --- a/src/makielayout/blocks/textbox.jl +++ b/src/makielayout/blocks/textbox.jl @@ -1,15 +1,13 @@ using InteractiveUtils: clipboard - function initialize_block!(tbox::Textbox) - topscene = tbox.blockscene scenearea = lift(tbox.layoutobservables.computedbbox) do bb - Rect(round.(Int, bb.origin), round.(Int, bb.widths)) + return Rect(round.(Int, bb.origin), round.(Int, bb.widths)) end - scene = Scene(topscene, scenearea, camera = campixel!) + scene = Scene(topscene, scenearea, camera=campixel!) cursorindex = Observable(0) setfield!(tbox, :cursorindex, cursorindex) @@ -21,14 +19,22 @@ function initialize_block!(tbox::Textbox) tbox.displayed_string[] = isnothing(tbox.stored_string[]) ? tbox.placeholder[] : tbox.stored_string[] displayed_is_valid = lift(tbox.displayed_string, tbox.validator) do str, validator - valid::Bool = validate_textbox(str, validator) + return valid::Bool = validate_textbox(str, validator) end hovering = Observable(false) realbordercolor = Observable{RGBAf}() - map!(realbordercolor, tbox.bordercolor, tbox.bordercolor_focused, - tbox.bordercolor_focused_invalid, tbox.bordercolor_hover, tbox.focused, displayed_is_valid, hovering) do bc, bcf, bcfi, bch, focused, valid, hovering + map!( + realbordercolor, + tbox.bordercolor, + tbox.bordercolor_focused, + tbox.bordercolor_focused_invalid, + tbox.bordercolor_hover, + tbox.focused, + displayed_is_valid, + hovering, + ) do bc, bcf, bcfi, bch, focused, valid, hovering c = if focused valid ? bcf : bcfi else @@ -38,9 +44,16 @@ function initialize_block!(tbox::Textbox) end realboxcolor = Observable{RGBAf}() - map!(realboxcolor, tbox.boxcolor, tbox.boxcolor_focused, - tbox.boxcolor_focused_invalid, tbox.boxcolor_hover, tbox.focused, displayed_is_valid, hovering) do bc, bcf, bcfi, bch, focused, valid, hovering - + map!( + realboxcolor, + tbox.boxcolor, + tbox.boxcolor_focused, + tbox.boxcolor_focused_invalid, + tbox.boxcolor_hover, + tbox.focused, + displayed_is_valid, + hovering, + ) do bc, bcf, bcfi, bch, focused, valid, hovering c = if focused valid ? bcf : bcfi else @@ -49,38 +62,58 @@ function initialize_block!(tbox::Textbox) return to_color(c) end - box = poly!(topscene, roundedrectpoints, strokewidth = tbox.borderwidth, - strokecolor = realbordercolor, - color = realboxcolor, inspectable = false) + box = poly!( + topscene, + roundedrectpoints, + strokewidth=tbox.borderwidth, + strokecolor=realbordercolor, + color=realboxcolor, + inspectable=false, + ) displayed_chars = @lift([c for c in $(tbox.displayed_string)]) realtextcolor = Observable{RGBAf}() - map!(realtextcolor, tbox.textcolor, tbox.textcolor_placeholder, tbox.focused, tbox.stored_string, tbox.displayed_string) do tc, tcph, foc, cont, disp + map!( + realtextcolor, + tbox.textcolor, + tbox.textcolor_placeholder, + tbox.focused, + tbox.stored_string, + tbox.displayed_string, + ) do tc, tcph, foc, cont, disp # the textbox has normal text color if it's focused # if it's defocused, the displayed text has to match the stored text in order # to be normal colored return to_color(foc || cont == disp ? tc : tcph) end - t = Label(scene, text = tbox.displayed_string, bbox = bbox, halign = :left, valign = :top, - width = Auto(true), height = Auto(true), color = realtextcolor, - fontsize = tbox.fontsize, padding = tbox.textpadding) + t = Label( + scene, + text=tbox.displayed_string, + bbox=bbox, + halign=:left, + valign=:top, + width=Auto(true), + height=Auto(true), + color=realtextcolor, + fontsize=tbox.fontsize, + padding=tbox.textpadding, + ) textplot = t.blockscene.plots[1] displayed_charbbs = lift(textplot.text, textplot[1]) do _, _ - charbbs(textplot) + return charbbs(textplot) end cursorpoints = lift(cursorindex, displayed_charbbs) do ci, bbs - textplot = t.blockscene.plots[1] glyphcollection = textplot.plots[1][1][][]::Makie.GlyphCollection hadvances = Float32[] broadcast_foreach(glyphcollection.extents, glyphcollection.scales) do ex, sc hadvance = ex.hadvance * sc[1] - push!(hadvances, hadvance) + return push!(hadvances, hadvance) end if ci > length(bbs) @@ -90,7 +123,7 @@ function initialize_block!(tbox::Textbox) end if 0 < ci < length(bbs) - [leftline(bbs[ci+1])...] + [leftline(bbs[ci + 1])...] elseif ci == 0 [leftline(bbs[1])...] else @@ -98,12 +131,12 @@ function initialize_block!(tbox::Textbox) end end - cursor = linesegments!(scene, cursorpoints, color = tbox.cursorcolor, linewidth = 2, inspectable = false) + cursor = linesegments!(scene, cursorpoints, color=tbox.cursorcolor, linewidth=2, inspectable=false) tbox.cursoranimtask = nothing on(t.layoutobservables.reporteddimensions) do dims - tbox.layoutobservables.autosize[] = dims.inner + return tbox.layoutobservables.autosize[] = dims.inner end # trigger text for autosize @@ -124,9 +157,7 @@ function initialize_block!(tbox::Textbox) end pos = state.data - closest_charindex = argmin( - [sum((pos .- center(bb)).^2) for bb in displayed_charbbs[]] - ) + closest_charindex = argmin([sum((pos .- center(bb)) .^ 2) for bb in displayed_charbbs[]]) # set cursor to index of closest char if right of center, or previous char if left of center cursorindex[] = if (pos .- center(displayed_charbbs[][closest_charindex]))[1] > 0 closest_charindex @@ -160,17 +191,15 @@ function initialize_block!(tbox::Textbox) empty!(displayed_chars[]) index = 1 end - newchars = [displayed_chars[][1:index-1]; c; displayed_chars[][index:end]] + newchars = [displayed_chars[][1:(index - 1)]; c; displayed_chars[][index:end]] tbox.displayed_string[] = join(newchars) - cursorindex[] = index + return cursorindex[] = index end - function appendchar!(c) - insertchar!(c, length(tbox.displayed_string[])) - end + appendchar!(c) = insertchar!(c, length(tbox.displayed_string[])) function removechar!(index) - newchars = [displayed_chars[][1:index-1]; displayed_chars[][index+1:end]] + newchars = [displayed_chars[][1:(index - 1)]; displayed_chars[][(index + 1):end]] if isempty(newchars) newchars = [' '] @@ -180,10 +209,10 @@ function initialize_block!(tbox::Textbox) cursorindex[] = max(0, cursorindex[] - 1) end - tbox.displayed_string[] = join(newchars) + return tbox.displayed_string[] = join(newchars) end - on(events(scene).unicode_input, priority = 60) do char + on(events(scene).unicode_input, priority=60) do char if tbox.focused[] && is_allowed(char, tbox.restriction[]) insertchar!(char, cursorindex[] + 1) return Consume(true) @@ -200,18 +229,14 @@ function initialize_block!(tbox::Textbox) end end - function cursor_forward() + cursor_forward() = if tbox.displayed_string[] != " " cursorindex[] = min(length(tbox.displayed_string[]), cursorindex[] + 1) end - end - function cursor_backward() - cursorindex[] = max(0, cursorindex[] - 1) - end + cursor_backward() = cursorindex[] = max(0, cursorindex[] - 1) - - on(events(scene).keyboardbutton, priority = 60) do event + on(events(scene).keyboardbutton, priority=60) do event if tbox.focused[] ctrl_v = (Keyboard.left_control | Keyboard.right_control) & Keyboard.v if ispressed(scene, ctrl_v) @@ -263,10 +288,9 @@ function initialize_block!(tbox::Textbox) return Consume(false) end - tbox + return tbox end - function charbbs(text) gc = text.plots[1][1][][] if !(gc isa Makie.GlyphCollection) @@ -278,32 +302,24 @@ function charbbs(text) bb = Makie.height_insensitive_boundingbox_with_advance(ext) bb = bb * sc fr = Rect2f(Point2f(ori) + bb.origin + pos, bb.widths) - push!(bbs, fr) + return push!(bbs, fr) end - bbs + return bbs end -function validate_textbox(str, validator::Function) - validator(str) -end +validate_textbox(str, validator::Function) = validator(str) -function validate_textbox(str, T::Type) - !isnothing(tryparse(T, str)) -end +validate_textbox(str, T::Type) = !isnothing(tryparse(T, str)) function validate_textbox(str, validator::Regex) m = match(validator, str) # check that the validator matches the whole string - !isnothing(m) && m.match == str + return !isnothing(m) && m.match == str end -function is_allowed(char, restriction::Nothing) - true -end +is_allowed(char, restriction::Nothing) = true -function is_allowed(char, restriction::Function) - allowed::Bool = restriction(char) -end +is_allowed(char, restriction::Function) = allowed::Bool = restriction(char) """ reset!(tb::Textbox) @@ -313,7 +329,7 @@ function reset!(tb::Textbox) tb.stored_string.val = nothing tb.displayed_string = tb.placeholder[] defocus!(tb) - nothing + return nothing end """ @@ -327,7 +343,7 @@ function set!(tb::Textbox, string::String) tb.displayed_string = string tb.stored_string = string - nothing + return nothing end """ @@ -342,19 +358,23 @@ function focus!(tb::Textbox) Animations.Animation( [0, 1.0], [Colors.alphacolor(COLOR_ACCENT[], 0), Colors.alphacolor(COLOR_ACCENT[], 1)], - Animations.sineio(n = 2, yoyo = true, postwait = 0.2)), - 0.0, 0.0, 1000) + Animations.sineio(n=2, yoyo=true, postwait=0.2), + ), + 0.0, + 0.0, + 1000, + ) if !isnothing(tb.cursoranimtask) Animations.stop(tb.cursoranimtask) tb.cursoranimtask = nothing end - tb.cursoranimtask = Animations.animate_async(cursoranim; fps = 30) do t, color - tb.cursorcolor = color + tb.cursoranimtask = Animations.animate_async(cursoranim; fps=30) do t, color + return tb.cursorcolor = color end end - nothing + return nothing end """ @@ -362,7 +382,6 @@ end Defocuses a `Textbox` so it doesn't receive keyboard input. """ function defocus!(tb::Textbox) - if tb.displayed_string[] in (" ", "") tb.displayed_string[] = tb.placeholder[] end @@ -373,5 +392,5 @@ function defocus!(tb::Textbox) end tb.cursorcolor = :transparent tb.focused = false - nothing + return nothing end diff --git a/src/makielayout/blocks/toggle.jl b/src/makielayout/blocks/toggle.jl index 6cdc5bb4d4c..2758c62ab7a 100644 --- a/src/makielayout/blocks/toggle.jl +++ b/src/makielayout/blocks/toggle.jl @@ -1,30 +1,29 @@ function initialize_block!(t::Toggle) - topscene = t.blockscene markersize = lift(t.layoutobservables.computedbbox) do bbox - min(width(bbox), height(bbox)) + return min(width(bbox), height(bbox)) end button_endpoint_inactive = lift(markersize) do ms bbox = t.layoutobservables.computedbbox[] - Point2f(left(bbox) + ms / 2, bottom(bbox) + ms / 2) + return Point2f(left(bbox) + ms / 2, bottom(bbox) + ms / 2) end button_endpoint_active = lift(markersize) do ms bbox = t.layoutobservables.computedbbox[] - Point2f(right(bbox) - ms / 2, bottom(bbox) + ms / 2) + return Point2f(right(bbox) - ms / 2, bottom(bbox) + ms / 2) end buttonvertices = lift(markersize, t.cornersegments) do ms, cs - roundedrectvertices(t.layoutobservables.computedbbox[], ms * 0.499, cs) + return roundedrectvertices(t.layoutobservables.computedbbox[], ms * 0.499, cs) end # trigger bbox notify(t.layoutobservables.suggestedbbox) framecolor = Observable{Any}(t.active[] ? t.framecolor_active[] : t.framecolor_inactive[]) - frame = poly!(topscene, buttonvertices, color = framecolor, inspectable = false) + frame = poly!(topscene, buttonvertices, color=framecolor, inspectable=false) animating = Observable(false) buttonpos = Observable(t.active[] ? [button_endpoint_active[]] : [button_endpoint_inactive[]]) @@ -38,11 +37,18 @@ function initialize_block!(t::Toggle) buttonfactor = Observable(1.0) buttonsize = lift(markersize, t.rimfraction, buttonfactor) do ms, rf, bf - ms * (1 - rf) * bf + return ms * (1 - rf) * bf end - button = scatter!(topscene, buttonpos, markersize = buttonsize, - color = t.buttoncolor, strokewidth = 0, inspectable = false, marker = Circle) + button = scatter!( + topscene, + buttonpos, + markersize=buttonsize, + color=t.buttoncolor, + strokewidth=0, + inspectable=false, + marker=Circle, + ) mouseevents = addmouseevents!(topscene, t.layoutobservables.computedbbox) @@ -57,25 +63,33 @@ function initialize_block!(t::Toggle) anim_posfrac = Animations.Animation( [0, t.toggleduration[]], t.active[] ? [1.0, 0.0] : [0.0, 1.0], - Animations.sineio()) + Animations.sineio(), + ) coloranim = Animations.Animation( [0, t.toggleduration[]], - t.active[] ? [t.framecolor_active[], t.framecolor_inactive[]] : [t.framecolor_inactive[], t.framecolor_active[]], - Animations.sineio()) + t.active[] ? [t.framecolor_active[], t.framecolor_inactive[]] : + [t.framecolor_inactive[], t.framecolor_active[]], + Animations.sineio(), + ) t.active[] = !t.active[] @async while true tim = time() - tstart # request endpoint values in every frame if the layout changes during # the animation - buttonpos[] = [Animations.linear_interpolate(anim_posfrac(tim), - button_endpoint_inactive[], button_endpoint_active[])] + buttonpos[] = [ + Animations.linear_interpolate( + anim_posfrac(tim), + button_endpoint_inactive[], + button_endpoint_active[], + ), + ] framecolor[] = coloranim(tim) if tim >= t.toggleduration[] animating[] = false break end - sleep(1/FPS[]) + sleep(1 / FPS[]) end return Consume(true) end diff --git a/src/makielayout/defaultattributes.jl b/src/makielayout/defaultattributes.jl index 01626c8203d..05db85194d2 100644 --- a/src/makielayout/defaultattributes.jl +++ b/src/makielayout/defaultattributes.jl @@ -1,60 +1,76 @@ -function inherit(scene, attr::Symbol, default_value) +inherit(scene, attr::Symbol, default_value) = if haskey(scene.theme, attr) lift(identity, scene.theme[attr]) else inherit(scene.parent, attr, default_value) end -end -function inherit(::Nothing, attr::Symbol, default_value) - default_value -end +inherit(::Nothing, attr::Symbol, default_value) = default_value function default_attributes(::Type{LineAxis}) - Attributes( - endpoints = (Point2f(0, 0), Point2f(100, 0)), - trimspine = false, - limits = (0f0, 100f0), - flipped = false, - flip_vertical_label = false, - ticksize = 6f0, - tickwidth = 1f0, - tickcolor = RGBf(0, 0, 0), - tickalign = 0f0, - ticks = Makie.automatic, - tickformat = Makie.automatic, - ticklabelalign = (:center, :top), - ticksvisible = true, - ticklabelrotation = 0f0, - ticklabelsize = 20f0, - ticklabelcolor = RGBf(0, 0, 0), - ticklabelsvisible = true, - spinewidth = 1f0, - label = "label", - labelsize = 20f0, - labelcolor = RGBf(0, 0, 0), - labelvisible = true, - ticklabelspace = Makie.automatic, - ticklabelpad = 3f0, - labelpadding = 5f0, - reversed = false, - minorticksvisible = true, - minortickalign = 0f0, - minorticksize = 4f0, - minortickwidth = 1f0, - minortickcolor = :black, - minorticks = Makie.automatic, - scale = identity, + return Attributes( + endpoints=(Point2f(0, 0), Point2f(100, 0)), + trimspine=false, + limits=(0.0f0, 100.0f0), + flipped=false, + flip_vertical_label=false, + ticksize=6.0f0, + tickwidth=1.0f0, + tickcolor=RGBf(0, 0, 0), + tickalign=0.0f0, + ticks=Makie.automatic, + tickformat=Makie.automatic, + ticklabelalign=(:center, :top), + ticksvisible=true, + ticklabelrotation=0.0f0, + ticklabelsize=20.0f0, + ticklabelcolor=RGBf(0, 0, 0), + ticklabelsvisible=true, + spinewidth=1.0f0, + label="label", + labelsize=20.0f0, + labelcolor=RGBf(0, 0, 0), + labelvisible=true, + ticklabelspace=Makie.automatic, + ticklabelpad=3.0f0, + labelpadding=5.0f0, + reversed=false, + minorticksvisible=true, + minortickalign=0.0f0, + minorticksize=4.0f0, + minortickwidth=1.0f0, + minortickcolor=:black, + minorticks=Makie.automatic, + scale=identity, ) end - function attributenames(::Type{LegendEntry}) - (:label, :labelsize, :labelfont, :labelcolor, :labelhalign, :labelvalign, - :patchsize, :patchstrokecolor, :patchstrokewidth, :patchcolor, - :linepoints, :linewidth, :linecolor, :linestyle, - :markerpoints, :markersize, :markerstrokewidth, :markercolor, :markerstrokecolor, - :polypoints, :polystrokewidth, :polycolor, :polystrokecolor) + return ( + :label, + :labelsize, + :labelfont, + :labelcolor, + :labelhalign, + :labelvalign, + :patchsize, + :patchstrokecolor, + :patchstrokewidth, + :patchcolor, + :linepoints, + :linewidth, + :linecolor, + :linestyle, + :markerpoints, + :markersize, + :markerstrokewidth, + :markercolor, + :markerstrokecolor, + :polypoints, + :polystrokewidth, + :polycolor, + :polystrokecolor, + ) end function extractattributes(attributes::Attributes, typ::Type) @@ -64,7 +80,7 @@ function extractattributes(attributes::Attributes, typ::Type) extracted[name] = attributes[name] end end - extracted + return extracted end function extractattributes(leg::Legend, typ::Type) @@ -74,5 +90,5 @@ function extractattributes(leg::Legend, typ::Type) extracted[name] = getproperty(leg, name) end end - extracted + return extracted end diff --git a/src/makielayout/geometrybasics_extension.jl b/src/makielayout/geometrybasics_extension.jl index 3edcc050fbe..aa7744292f3 100644 --- a/src/makielayout/geometrybasics_extension.jl +++ b/src/makielayout/geometrybasics_extension.jl @@ -14,37 +14,29 @@ bottomline(bbox::Rect2) = (bottomleft(bbox), bottomright(bbox)) leftline(bbox::Rect2) = (bottomleft(bbox), topleft(bbox)) rightline(bbox::Rect2) = (bottomright(bbox), topright(bbox)) -function shrinkbymargin(rect, margin) - return Recti(minimum(rect) .+ margin, (widths(rect) .- 2 .* margin)) -end +shrinkbymargin(rect, margin) = Recti(minimum(rect) .+ margin, (widths(rect) .- 2 .* margin)) -function limits(r::Rect{N, T}) where {N, T} +function limits(r::Rect{N,T}) where {N,T} mini, maxi = extrema(r) return ntuple(i -> (mini[i], maxi[i]), N) end -function limits(r::Rect, dim::Integer) - return (minimum(r)[dim], maximum(r)[dim]) -end +limits(r::Rect, dim::Integer) = (minimum(r)[dim], maximum(r)[dim]) xlimits(r::Rect) = limits(r, 1) ylimits(r::Rect) = limits(r, 2) -function enlarge(bbox::Rect2, l, r, b, t) - BBox(left(bbox) - l, right(bbox) + r, bottom(bbox) - b, top(bbox) + t) -end +enlarge(bbox::Rect2, l, r, b, t) = BBox(left(bbox) - l, right(bbox) + r, bottom(bbox) - b, top(bbox) + t) -function center(bbox::Rect2) - Point2((right(bbox) + left(bbox)) / 2, (top(bbox) + bottom(bbox)) / 2) -end +center(bbox::Rect2) = Point2((right(bbox) + left(bbox)) / 2, (top(bbox) + bottom(bbox)) / 2) """ Converts a point in fractions of rect dimensions into real coordinates. """ -function fractionpoint(bbox::Rect2f, point::T) where T <: Point2 - T(left(bbox) + point[1] * width(bbox), bottom(bbox) + point[2] * height(bbox)) +function fractionpoint(bbox::Rect2f, point::T) where {T<:Point2} + return T(left(bbox) + point[1] * width(bbox), bottom(bbox) + point[2] * height(bbox)) end function anglepoint(center::Point2, angle::Real, radius::Real) - Ref(center) .+ Ref(Point2(cos(angle), sin(angle))) .* radius + return Ref(center) .+ Ref(Point2(cos(angle), sin(angle))) .* radius end diff --git a/src/makielayout/helpers.jl b/src/makielayout/helpers.jl index 5d0b24ef525..d8d2bc8015f 100644 --- a/src/makielayout/helpers.jl +++ b/src/makielayout/helpers.jl @@ -7,12 +7,11 @@ function round_to_IRect2D(r::Rect{2}) newori = round.(Int, minimum(r)) othercorner = round.(Int, maximum(r)) newwidth = othercorner .- newori - Rect{2, Int}(newori, newwidth) + return Rect{2,Int}(newori, newwidth) end function sceneareanode!(finalbbox, limits, aspect) return map(finalbbox, limits, aspect; ignore_equal_values=true) do bbox, limits, aspect - w = width(bbox) h = height(bbox) # as = mw / mh @@ -67,26 +66,26 @@ function roundedrectvertices(rect, cornerradius, cornersegments) htouching = height(rect) / 2 == cr cstr = if wtouching - anglepoint.(Ref(ictr), LinRange(0, pi/2, csegs), cr) + anglepoint.(Ref(ictr), LinRange(0, pi / 2, csegs), cr) else - anglepoint.(Ref(ictr), LinRange(0, pi/2, csegs)[1:end-1], cr) + anglepoint.(Ref(ictr), LinRange(0, pi / 2, csegs)[1:(end - 1)], cr) end cstl = if htouching - anglepoint.(Ref(ictl), LinRange(pi/2, pi, csegs), cr) + anglepoint.(Ref(ictl), LinRange(pi / 2, pi, csegs), cr) else - anglepoint.(Ref(ictl), LinRange(pi/2, pi, csegs)[1:end-1], cr) + anglepoint.(Ref(ictl), LinRange(pi / 2, pi, csegs)[1:(end - 1)], cr) end csbl = if wtouching - anglepoint.(Ref(icbl), LinRange(pi, 3pi/2, csegs), cr) + anglepoint.(Ref(icbl), LinRange(pi, 3pi / 2, csegs), cr) else - anglepoint.(Ref(icbl), LinRange(pi, 3pi/2, csegs)[1:end-1], cr) + anglepoint.(Ref(icbl), LinRange(pi, 3pi / 2, csegs)[1:(end - 1)], cr) end csbr = if htouching - anglepoint.(Ref(icbr), LinRange(3pi/2, 2pi, csegs), cr) + anglepoint.(Ref(icbr), LinRange(3pi / 2, 2pi, csegs), cr) else - anglepoint.(Ref(icbr), LinRange(3pi/2, 2pi, csegs)[1:end-1], cr) + anglepoint.(Ref(icbr), LinRange(3pi / 2, 2pi, csegs)[1:(end - 1)], cr) end - arr = [cstr; cstl; csbl; csbr] + return arr = [cstr; cstl; csbl; csbr] end """ @@ -97,7 +96,7 @@ Sets the autolimit margins to zero on all sides. function tightlimits!(la::Axis) la.xautolimitmargin = (0, 0) la.yautolimitmargin = (0, 0) - reset_limits!(la) + return reset_limits!(la) end """ @@ -111,78 +110,85 @@ Example: tightlimits!(laxis, Bottom()) ``` """ -function tightlimits!(la::Axis, sides::Union{Left, Right, Bottom, Top}...) +tightlimits!(la::Axis, sides::Union{Left,Right,Bottom,Top}...) = for s in sides tightlimits!(la, s) end -end function tightlimits!(la::Axis, ::Left) la.xautolimitmargin = Base.setindex(la.xautolimitmargin[], 0.0, 1) - autolimits!(la) + return autolimits!(la) end function tightlimits!(la::Axis, ::Right) la.xautolimitmargin = Base.setindex(la.xautolimitmargin[], 0.0, 2) - autolimits!(la) + return autolimits!(la) end function tightlimits!(la::Axis, ::Bottom) la.yautolimitmargin = Base.setindex(la.yautolimitmargin[], 0.0, 1) - autolimits!(la) + return autolimits!(la) end function tightlimits!(la::Axis, ::Top) la.yautolimitmargin = Base.setindex(la.yautolimitmargin[], 0.0, 2) - autolimits!(la) + return autolimits!(la) end -GridLayoutBase.GridLayout(scene::Scene, args...; kwargs...) = GridLayout(args...; bbox = lift(x -> Rect2f(x), pixelarea(scene)), kwargs...) - -function axislines!(scene, rect, spinewidth, topspinevisible, rightspinevisible, - leftspinevisible, bottomspinevisible, topspinecolor, leftspinecolor, - rightspinecolor, bottomspinecolor) +function GridLayoutBase.GridLayout(scene::Scene, args...; kwargs...) + return GridLayout(args...; bbox=lift(x -> Rect2f(x), pixelarea(scene)), kwargs...) +end +function axislines!( + scene, + rect, + spinewidth, + topspinevisible, + rightspinevisible, + leftspinevisible, + bottomspinevisible, + topspinecolor, + leftspinecolor, + rightspinecolor, + bottomspinecolor, +) bottomline = lift(rect, spinewidth) do r, sw y = bottom(r) p1 = Point2(left(r) - 0.5sw, y) p2 = Point2(right(r) + 0.5sw, y) - [p1, p2] + return [p1, p2] end leftline = lift(rect, spinewidth) do r, sw x = left(r) p1 = Point2(x, bottom(r) - 0.5sw) p2 = Point2(x, top(r) + 0.5sw) - [p1, p2] + return [p1, p2] end topline = lift(rect, spinewidth) do r, sw y = top(r) p1 = Point2(left(r) - 0.5sw, y) p2 = Point2(right(r) + 0.5sw, y) - [p1, p2] + return [p1, p2] end rightline = lift(rect, spinewidth) do r, sw x = right(r) p1 = Point2(x, bottom(r) - 0.5sw) p2 = Point2(x, top(r) + 0.5sw) - [p1, p2] + return [p1, p2] end - (lines!(scene, bottomline, linewidth = spinewidth, - visible = bottomspinevisible, color = bottomspinecolor), - lines!(scene, leftline, linewidth = spinewidth, - visible = leftspinevisible, color = leftspinecolor), - lines!(scene, rightline, linewidth = spinewidth, - visible = rightspinevisible, color = rightspinecolor), - lines!(scene, topline, linewidth = spinewidth, - visible = topspinevisible, color = topspinecolor)) + return ( + lines!(scene, bottomline, linewidth=spinewidth, visible=bottomspinevisible, color=bottomspinecolor), + lines!(scene, leftline, linewidth=spinewidth, visible=leftspinevisible, color=leftspinecolor), + lines!(scene, rightline, linewidth=spinewidth, visible=rightspinevisible, color=rightspinecolor), + lines!(scene, topline, linewidth=spinewidth, visible=topspinevisible, color=topspinecolor), + ) end - -function interleave_vectors(vec1::Vector{T}, vec2::Vector{T}) where T +function interleave_vectors(vec1::Vector{T}, vec2::Vector{T}) where {T} n = length(vec1) @assert n == length(vec2) @@ -192,7 +198,7 @@ function interleave_vectors(vec1::Vector{T}, vec2::Vector{T}) where T vec[k + 1] = vec1[i] vec[k + 2] = vec2[i] end - vec + return vec end """ @@ -243,25 +249,30 @@ macro documented_attributes(exp) else error("Neither docstringed variable nor normal variable: $e") end - varname, var_exp, str_exp + return varname, var_exp, str_exp end # make a dictionary of :variable_name => docstring_expression - exp_docdict = Expr(:call, :Dict, - (Expr(:call, Symbol("=>"), QuoteNode(name), strexp) - for (name, _, strexp) in vars_and_exps)...) + exp_docdict = Expr( + :call, + :Dict, + (Expr(:call, Symbol("=>"), QuoteNode(name), strexp) for (name, _, strexp) in vars_and_exps)..., + ) # make a dictionary of :variable_name => docstring_expression - defaults_dict = Expr(:call, :Dict, - (Expr(:call, Symbol("=>"), QuoteNode(name), exp isa String ? "\"$exp\"" : string(exp)) - for (name, exp, _) in vars_and_exps)...) + defaults_dict = Expr( + :call, + :Dict, + ( + Expr(:call, Symbol("=>"), QuoteNode(name), exp isa String ? "\"$exp\"" : string(exp)) for + (name, exp, _) in vars_and_exps + )..., + ) # make an Attributes instance with of variable_name = variable_expression - exp_attrs = Expr(:call, :Attributes, - (Expr(:kw, name, exp) - for (name, exp, _) in vars_and_exps)...) + exp_attrs = Expr(:call, :Attributes, (Expr(:kw, name, exp) for (name, exp, _) in vars_and_exps)...) - esc(quote + return esc(quote ($exp_attrs, $exp_docdict, $defaults_dict) end) end @@ -276,19 +287,17 @@ function docvarstring(docdict, defaultdict) for (var, doc) in sort(collect(pairs(docdict))) print(buffer, "`$var`\\\nDefault: `$(defaultdict[var])`\\\n$doc\n\n") end - String(take!(buffer)) + return String(take!(buffer)) end - function subtheme(scene, key::Symbol) sub = haskey(theme(scene), key) ? theme(scene, key) : Attributes() if !(sub isa Attributes) error("Subtheme is not of type Attributes but is $sub") end - sub + return sub end - """ labelslider!(scene, label, range; format = string, sliderkw = Dict(), labelkw = Dict(), valuekw = Dict(), value_column_width = automatic, layoutkw...) @@ -316,14 +325,27 @@ ls = labelslider!(scene, "Voltage:", 0:10; format = x -> "\$(x)V") layout[1, 1] = ls.layout ``` """ -function labelslider!(scene, label, range; format = string, - sliderkw = Dict(), labelkw = Dict(), valuekw = Dict(), value_column_width = automatic, layoutkw...) - slider = Slider(scene; range = range, sliderkw...) +function labelslider!( + scene, + label, + range; + format=string, + sliderkw=Dict(), + labelkw=Dict(), + valuekw=Dict(), + value_column_width=automatic, + layoutkw..., +) + slider = Slider(scene; range=range, sliderkw...) label = Label(scene, label; labelkw...) valuelabel = Label(scene, lift(x -> apply_format(x, format), slider.value); valuekw...) layout = hbox!(label, slider, valuelabel; layoutkw...) - Base.depwarn("labelslider! is deprecated and will be removed in the future. Use SliderGrid instead." , :labelslider!, force = true) + Base.depwarn( + "labelslider! is deprecated and will be removed in the future. Use SliderGrid instead.", + :labelslider!, + force=true, + ) if value_column_width === automatic maxwidth = 0.0 @@ -342,10 +364,9 @@ function labelslider!(scene, label, range; format = string, colsize!(layout, 3, value_column_width) end - (slider = slider, label = label, valuelabel = valuelabel, layout = layout) + return (slider=slider, label=label, valuelabel=valuelabel, layout=layout) end - """ labelslidergrid!(scene, labels, ranges; formats = [string], sliderkw = Dict(), labelkw = Dict(), valuekw = Dict(), @@ -375,16 +396,29 @@ ls = labelslidergrid!(scene, ["Voltage", "Ampere"], Ref(0:0.1:100); format = x - layout[1, 1] = ls.layout ``` """ -function labelslidergrid!(scene, labels, ranges; formats = [string], value_column_width = automatic, - sliderkw = Dict(), labelkw = Dict(), valuekw = Dict(), layoutkw...) - - Base.depwarn("labelslidergrid! is deprecated and will be removed in the future. Use SliderGrid instead." , :labelslidergrid!, force = true) +function labelslidergrid!( + scene, + labels, + ranges; + formats=[string], + value_column_width=automatic, + sliderkw=Dict(), + labelkw=Dict(), + valuekw=Dict(), + layoutkw..., +) + Base.depwarn( + "labelslidergrid! is deprecated and will be removed in the future. Use SliderGrid instead.", + :labelslidergrid!, + force=true, + ) elements = broadcast(labels, ranges, formats) do label, range, format - slider = Slider(scene; range = range, sliderkw...) - label = Label(scene, label; halign = :left, labelkw...) - valuelabel = Label(scene, lift(x -> apply_format(x, format), slider.value); halign = :right, valuekw...) - (; slider = slider, label = label, valuelabel = valuelabel) + slider = Slider(scene; range=range, sliderkw...) + label = Label(scene, label; halign=:left, labelkw...) + valuelabel = + Label(scene, lift(x -> apply_format(x, format), slider.value); halign=:right, valuekw...) + return (; slider=slider, label=label, valuelabel=valuelabel) end sliders = map(x -> x.slider, elements) @@ -417,16 +451,12 @@ function labelslidergrid!(scene, labels, ranges; formats = [string], value_colum colsize!(layout, 3, value_column_width) end - (sliders = sliders, labels = labels, valuelabels = valuelabels, layout = layout) + return (sliders=sliders, labels=labels, valuelabels=valuelabels, layout=layout) end -function apply_format(value, format) - format(value) -end +apply_format(value, format) = format(value) -function apply_format(value, formatstring::String) - Formatting.format(formatstring, value) -end +apply_format(value, formatstring::String) = Formatting.format(formatstring, value) Makie.get_scene(ax::Axis) = ax.scene Makie.get_scene(ax::Axis3) = ax.scene diff --git a/src/makielayout/interactions.jl b/src/makielayout/interactions.jl index 537f114a552..d97a44db7d3 100644 --- a/src/makielayout/interactions.jl +++ b/src/makielayout/interactions.jl @@ -84,7 +84,6 @@ function deactivate_interaction!(parent, name::Symbol) return nothing end - function process_interaction(@nospecialize args...) # do nothing in the default case return Consume(false) @@ -101,14 +100,11 @@ function process_interaction(f::Function, event, parent) return Consume(false) end - - ############################################################################ # Axis interactions # ############################################################################ function _chosen_limits(rz, ax) - r = positivize(Rect2f(rz.from, rz.to .- rz.from)) lims = ax.finallimits[] # restrict to y change @@ -151,7 +147,7 @@ function process_interaction(r::RectangleZoom, event::MouseEvent, ax::Axis) inv_transf = Makie.inverse_transform(transf) if isnothing(inv_transf) - @warn "Can't rectangle zoom without inverse transform" maxlog=1 + @warn "Can't rectangle zoom without inverse transform" maxlog = 1 # TODO, what can we do without inverse? return Consume(false) end @@ -179,7 +175,7 @@ function process_interaction(r::RectangleZoom, event::MouseEvent, ax::Axis) try r.callback(r.rectnode[]) catch e - @warn "error in rectangle zoom" exception=e + @warn "error in rectangle zoom" exception = e end r.active[] = false return Consume(true) @@ -188,10 +184,10 @@ function process_interaction(r::RectangleZoom, event::MouseEvent, ax::Axis) return Consume(false) end -function rectclamp(p::Point{N, T}, r::Rect) where {N, T} +function rectclamp(p::Point{N,T}, r::Rect) where {N,T} mi, ma = extrema(r) p = clamp.(p, mi, ma) - return Point{N, T}(p) + return Point{N,T}(p) end function process_interaction(r::RectangleZoom, event::KeysEvent, ax::Axis) @@ -211,7 +207,6 @@ function positivize(r::Rect2f) end function process_interaction(l::LimitReset, event::MouseEvent, ax::Axis) - if event.type === MouseEventTypes.leftclick if ispressed(ax.scene, Keyboard.left_control) if ispressed(ax.scene, Keyboard.left_shift) @@ -243,12 +238,13 @@ function process_interaction(s::ScrollZoom, event::ScrollEvent, ax::Axis) if zoom != 0 pa = pixelarea(scene)[] - z = (1f0 - s.speed)^zoom + z = (1.0f0 - s.speed)^zoom mp_axscene = Vec4f((e.mouseposition[] .- pa.origin)..., 0, 1) # first to normal -1..1 space - mp_axfraction = (cam.pixel_space[] * mp_axscene)[Vec(1, 2)] .* + mp_axfraction = + (cam.pixel_space[] * mp_axscene)[Vec(1, 2)] .* # now to 1..-1 if an axis is reversed to correct zoom point (-2 .* ((ax.xreversed[], ax.yreversed[])) .+ 1) .* # now to 0..1 @@ -272,7 +268,13 @@ function process_interaction(s::ScrollZoom, event::ScrollEvent, ax::Axis) newxorigin = xzoomlock[] ? xorigin : xorigin + mp_axfraction[1] * (xwidth - newxwidth) newyorigin = yzoomlock[] ? yorigin : yorigin + mp_axfraction[2] * (ywidth - newywidth) - timed_ticklabelspace_reset(ax, s.reset_timer, s.prev_xticklabelspace, s.prev_yticklabelspace, s.reset_delay) + timed_ticklabelspace_reset( + ax, + s.reset_timer, + s.prev_xticklabelspace, + s.prev_yticklabelspace, + s.reset_delay, + ) newrect_trans = if ispressed(scene, xzoomkey[]) Rectf(newxorigin, yorigin, newxwidth, ywidth) @@ -291,7 +293,6 @@ function process_interaction(s::ScrollZoom, event::ScrollEvent, ax::Axis) end function process_interaction(dp::DragPan, event::MouseEvent, ax) - if event.type !== MouseEventTypes.rightdrag return Consume(false) end @@ -312,11 +313,11 @@ function process_interaction(dp::DragPan, event::MouseEvent, ax) mp_axfraction, mp_axfraction_prev = map((mp_axscene, mp_axscene_prev)) do mp # first to normal -1..1 space - (cam.pixel_space[] * mp)[Vec(1, 2)] .* - # now to 1..-1 if an axis is reversed to correct zoom point - (-2 .* ((ax.xreversed[], ax.yreversed[])) .+ 1) .* - # now to 0..1 - 0.5 .+ 0.5 + return (cam.pixel_space[] * mp)[Vec(1, 2)] .* + # now to 1..-1 if an axis is reversed to correct zoom point + (-2 .* ((ax.xreversed[], ax.yreversed[])) .+ 1) .* + # now to 0..1 + 0.5 .+ 0.5 end xscale = ax.xscale[] @@ -343,7 +344,13 @@ function process_interaction(dp::DragPan, event::MouseEvent, ax) yori = tlimits_trans.origin[2] end - timed_ticklabelspace_reset(ax, dp.reset_timer, dp.prev_xticklabelspace, dp.prev_yticklabelspace, dp.reset_delay) + timed_ticklabelspace_reset( + ax, + dp.reset_timer, + dp.prev_xticklabelspace, + dp.prev_yticklabelspace, + dp.reset_delay, + ) inv_transf = Makie.inverse_transform(transf) newrect_trans = Rectf(Vec2f(xori, yori), widths(tlimits_trans)) @@ -352,7 +359,6 @@ function process_interaction(dp::DragPan, event::MouseEvent, ax) return Consume(true) end - function process_interaction(dr::DragRotate, event::MouseEvent, ax3d) if event.type !== MouseEventTypes.leftdrag return Consume(false) @@ -361,7 +367,7 @@ function process_interaction(dr::DragRotate, event::MouseEvent, ax3d) dpx = event.px - event.prev_px ax3d.azimuth[] += -dpx[1] * 0.01 - ax3d.elevation[] = clamp(ax3d.elevation[] - dpx[2] * 0.01, -pi/2 + 0.001, pi/2 - 0.001) + ax3d.elevation[] = clamp(ax3d.elevation[] - dpx[2] * 0.01, -pi / 2 + 0.001, pi / 2 - 0.001) return Consume(true) end diff --git a/src/makielayout/lineaxis.jl b/src/makielayout/lineaxis.jl index aed8d714e90..fef916ed982 100644 --- a/src/makielayout/lineaxis.jl +++ b/src/makielayout/lineaxis.jl @@ -3,7 +3,7 @@ function LineAxis(parent::Scene; @nospecialize(kwargs...)) return LineAxis(parent, attrs) end -function calculate_horizontal_extends(endpoints)::Tuple{Float32, NTuple{2, Float32}, Bool} +function calculate_horizontal_extends(endpoints)::Tuple{Float32,NTuple{2,Float32},Bool} if endpoints[1][2] == endpoints[2][2] horizontal = true extents = (endpoints[1][1], endpoints[2][1]) @@ -15,41 +15,53 @@ function calculate_horizontal_extends(endpoints)::Tuple{Float32, NTuple{2, Float position = endpoints[1][1] return (position, extents, horizontal) else - error("OldAxis endpoints $(endpoints[1]) and $(endpoints[2]) are neither on a horizontal nor vertical line") + error( + "OldAxis endpoints $(endpoints[1]) and $(endpoints[2]) are neither on a horizontal nor vertical line", + ) end end - function calculate_protrusion( - closure_args, - ticksvisible::Bool, label, labelvisible::Bool, labelpadding::Number, tickspace::Number, ticklabelsvisible::Bool, - actual_ticklabelspace::Number, ticklabelpad::Number, _...) - + closure_args, + ticksvisible::Bool, + label, + labelvisible::Bool, + labelpadding::Number, + tickspace::Number, + ticklabelsvisible::Bool, + actual_ticklabelspace::Number, + ticklabelpad::Number, + _..., +) horizontal, labeltext, ticklabel_annotation_obs = closure_args label_is_empty::Bool = iswhitespace(label) || isempty(label) real_labelsize::Float32 = if label_is_empty - 0f0 + 0.0f0 else boundingbox(labeltext).widths[horizontal[] ? 2 : 1] end - labelspace::Float32 = (labelvisible && !label_is_empty) ? real_labelsize + labelpadding : 0f0 + labelspace::Float32 = (labelvisible && !label_is_empty) ? real_labelsize + labelpadding : 0.0f0 - _tickspace::Float32 = (ticksvisible && !isempty(ticklabel_annotation_obs[])) ? tickspace : 0f0 + _tickspace::Float32 = (ticksvisible && !isempty(ticklabel_annotation_obs[])) ? tickspace : 0.0f0 - ticklabelgap::Float32 = (ticklabelsvisible && actual_ticklabelspace > 0) ? actual_ticklabelspace + ticklabelpad : 0f0 + ticklabelgap::Float32 = + (ticklabelsvisible && actual_ticklabelspace > 0) ? actual_ticklabelspace + ticklabelpad : 0.0f0 return _tickspace + ticklabelgap + labelspace end - function create_linepoints( - pos_ext_hor, - flipped::Bool, spine_width::Number, trimspine::Union{Bool, Tuple{Bool, Bool}}, tickpositions::Vector{Point2f}, tickwidth::Number) - - (position::Float32, extents::NTuple{2, Float32}, horizontal::Bool) = pos_ext_hor + pos_ext_hor, + flipped::Bool, + spine_width::Number, + trimspine::Union{Bool,Tuple{Bool,Bool}}, + tickpositions::Vector{Point2f}, + tickwidth::Number, +) + (position::Float32, extents::NTuple{2,Float32}, horizontal::Bool) = pos_ext_hor if trimspine isa Bool trimspine = (trimspine, trimspine) @@ -73,19 +85,20 @@ function create_linepoints( y = position pstart = Point2f(-0.5f0 * tickwidth, 0) pend = Point2f(0.5f0 * tickwidth, 0) - from = trimspine[1] ? tickpositions[1] .+ pstart : Point2f(extents_oriented[1] - 0.5spine_width, y) + from = + trimspine[1] ? tickpositions[1] .+ pstart : Point2f(extents_oriented[1] - 0.5spine_width, y) to = trimspine[2] ? tickpositions[end] .+ pend : Point2f(extents_oriented[2] + 0.5spine_width, y) return [from, to] else x = position pstart = Point2f(-0.5f0 * tickwidth, 0) pend = Point2f(0.5f0 * tickwidth, 0) - from = trimspine[1] ? tickpositions[1] .+ pstart : Point2f(x, extents_oriented[1] - 0.5spine_width) + from = + trimspine[1] ? tickpositions[1] .+ pstart : Point2f(x, extents_oriented[1] - 0.5spine_width) to = trimspine[2] ? tickpositions[end] .+ pend : Point2f(x, extents_oriented[2] + 0.5spine_width) return [from, to] end end - end function calculate_real_ticklabel_align(al, horizontal, fl::Bool, rot::Number) @@ -97,13 +110,13 @@ function calculate_real_ticklabel_align(al, horizontal, fl::Bool, rot::Number) else (fl ? :left : :right, :center) end - elseif rot ≈ pi/2 + elseif rot ≈ pi / 2 if hor (fl ? :left : :right, :center) else (:center, fl ? :top : :bottom) end - elseif rot ≈ -pi/2 + elseif rot ≈ -pi / 2 if hor (fl ? :right : :left, :center) else @@ -122,7 +135,7 @@ function calculate_real_ticklabel_align(al, horizontal, fl::Bool, rot::Number) (fl ? :left : :right, :center) end end - elseif al isa NTuple{2, Symbol} + elseif al isa NTuple{2,Symbol} return al else error("Align needs to be a NTuple{2, Symbol}.") @@ -130,9 +143,13 @@ function calculate_real_ticklabel_align(al, horizontal, fl::Bool, rot::Number) end function update_ticklabel_node( - closure_args, - ticklabel_annotation_obs::Observable, - labelgap::Number, flipped::Bool, tickpositions::Vector{Point2f}, tickstrings) + closure_args, + ticklabel_annotation_obs::Observable, + labelgap::Number, + flipped::Bool, + tickpositions::Vector{Point2f}, + tickstrings, +) # tickspace is always updated before labelgap # tickpositions are always updated before tickstrings # so we don't need to lift those @@ -144,9 +161,9 @@ function update_ticklabel_node( ticklabelgap::Float32 = spinewidth[] + tickspace[] + ticklabelpad[] shift = if horizontal[] - Point2f(0f0, flipped ? ticklabelgap : -ticklabelgap) + Point2f(0.0f0, flipped ? ticklabelgap : -ticklabelgap) else - Point2f(flipped ? ticklabelgap : -ticklabelgap, 0f0) + Point2f(flipped ? ticklabelgap : -ticklabelgap, 0.0f0) end # re-use already allocated array result = ticklabel_annotation_obs[] @@ -161,20 +178,28 @@ function update_ticklabel_node( return end -function update_tick_obs(tick_obs, horizontal::Observable{Bool}, flipped::Observable{Bool}, tickpositions, tickalign, ticksize, spinewidth) +function update_tick_obs( + tick_obs, + horizontal::Observable{Bool}, + flipped::Observable{Bool}, + tickpositions, + tickalign, + ticksize, + spinewidth, +) result = tick_obs[] empty!(result) # re-use allocated array sign::Int = flipped[] ? -1 : 1 if horizontal[] for tp in tickpositions - tstart = tp + sign * Point2f(0f0, tickalign * ticksize - 0.5f0 * spinewidth) - tend = tstart + sign * Point2f(0f0, -ticksize) + tstart = tp + sign * Point2f(0.0f0, tickalign * ticksize - 0.5f0 * spinewidth) + tend = tstart + sign * Point2f(0.0f0, -ticksize) push!(result, tstart, tend) end else for tp in tickpositions - tstart = tp + sign * Point2f(tickalign * ticksize - 0.5f0 * spinewidth, 0f0) - tend = tstart + sign * Point2f(-ticksize, 0f0) + tstart = tp + sign * Point2f(tickalign * ticksize - 0.5f0 * spinewidth, 0.0f0) + tend = tstart + sign * Point2f(-ticksize, 0.0f0) push!(result, tstart, tend) end end @@ -183,13 +208,12 @@ function update_tick_obs(tick_obs, horizontal::Observable{Bool}, flipped::Observ end function update_tickpos_string(closure_args, tickvalues_labels_unfiltered, reversed::Bool, scale) - tickstrings, tickpositions, tickvalues, pos_extents_horizontal, limits_obs = closure_args - limits = limits_obs[]::NTuple{2, Float32} + limits = limits_obs[]::NTuple{2,Float32} tickvalues_unfiltered, tickstrings_unfiltered = tickvalues_labels_unfiltered - position::Float32, extents_uncorrected::NTuple{2, Float32}, horizontal::Bool = pos_extents_horizontal[] + position::Float32, extents_uncorrected::NTuple{2,Float32}, horizontal::Bool = pos_extents_horizontal[] extents = reversed ? reverse(extents_uncorrected) : extents_uncorrected @@ -202,8 +226,7 @@ function update_tickpos_string(closure_args, tickvalues_labels_unfiltered, rever # if labels are given manually, it's possible that some of them are outside the displayed limits # we only check approximately because otherwise because of floating point errors, ticks can be dismissed sometimes i_values_within_limits = findall(tickvalues_unfiltered) do tv - return (limits[1] <= tv || limits[1] ≈ tv) && - (tv <= limits[2] || tv ≈ limits[2]) + return (limits[1] <= tv || limits[1] ≈ tv) && (tv <= limits[2] || tv ≈ limits[2]) end tickvalues[] = tickvalues_unfiltered[i_values_within_limits] @@ -226,8 +249,15 @@ function update_tickpos_string(closure_args, tickvalues_labels_unfiltered, rever return end -function update_minor_ticks(minortickpositions, limits::NTuple{2, Float32}, pos_extents_horizontal, minortickvalues, scale, reversed::Bool) - position::Float32, extents_uncorrected::NTuple{2, Float32}, horizontal::Bool = pos_extents_horizontal +function update_minor_ticks( + minortickpositions, + limits::NTuple{2,Float32}, + pos_extents_horizontal, + minortickvalues, + scale, + reversed::Bool, +) + position::Float32, extents_uncorrected::NTuple{2,Float32}, horizontal::Bool = pos_extents_horizontal extents = reversed ? reverse(extents_uncorrected) : extents_uncorrected @@ -253,53 +283,109 @@ function update_minor_ticks(minortickpositions, limits::NTuple{2, Float32}, pos_ end function LineAxis(parent::Scene, attrs::Attributes) - decorations = Dict{Symbol, Any}() - - @extract attrs (endpoints, ticksize, tickwidth, - tickcolor, tickalign, ticks, tickformat, ticklabelalign, ticklabelrotation, ticksvisible, - ticklabelspace, ticklabelpad, labelpadding, - ticklabelsize, ticklabelsvisible, spinewidth, spinecolor, label, labelsize, labelcolor, - labelfont, ticklabelfont, ticklabelcolor, - labelrotation, labelvisible, spinevisible, trimspine, flip_vertical_label, reversed, - minorticksvisible, minortickalign, minorticksize, minortickwidth, minortickcolor, minorticks) + decorations = Dict{Symbol,Any}() + + @extract attrs ( + endpoints, + ticksize, + tickwidth, + tickcolor, + tickalign, + ticks, + tickformat, + ticklabelalign, + ticklabelrotation, + ticksvisible, + ticklabelspace, + ticklabelpad, + labelpadding, + ticklabelsize, + ticklabelsvisible, + spinewidth, + spinecolor, + label, + labelsize, + labelcolor, + labelfont, + ticklabelfont, + ticklabelcolor, + labelrotation, + labelvisible, + spinevisible, + trimspine, + flip_vertical_label, + reversed, + minorticksvisible, + minortickalign, + minorticksize, + minortickwidth, + minortickcolor, + minorticks, + ) pos_extents_horizontal = lift(calculate_horizontal_extends, endpoints; ignore_equal_values=true) - horizontal = lift(x-> x[3], pos_extents_horizontal) + horizontal = lift(x -> x[3], pos_extents_horizontal) # Tuple constructor converts more than `convert(NTuple{2, Float32}, x)` but we still need the conversion to Float32 tuple: - limits = lift(x-> convert(NTuple{2, Float32}, Tuple(x)), attrs.limits; ignore_equal_values=true) - flipped = lift(x-> convert(Bool, x), attrs.flipped; ignore_equal_values=true) + limits = lift(x -> convert(NTuple{2,Float32}, Tuple(x)), attrs.limits; ignore_equal_values=true) + flipped = lift(x -> convert(Bool, x), attrs.flipped; ignore_equal_values=true) ticksnode = Observable(Point2f[]; ignore_equal_values=true) ticklines = linesegments!( - parent, ticksnode, linewidth = tickwidth, color = tickcolor, linestyle = nothing, - visible = ticksvisible, inspectable = false + parent, + ticksnode, + linewidth=tickwidth, + color=tickcolor, + linestyle=nothing, + visible=ticksvisible, + inspectable=false, ) decorations[:ticklines] = ticklines translate!(ticklines, 0, 0, 10) minorticksnode = Observable(Point2f[]; ignore_equal_values=true) minorticklines = linesegments!( - parent, minorticksnode, linewidth = minortickwidth, color = minortickcolor, - linestyle = nothing, visible = minorticksvisible, inspectable = false + parent, + minorticksnode, + linewidth=minortickwidth, + color=minortickcolor, + linestyle=nothing, + visible=minorticksvisible, + inspectable=false, ) decorations[:minorticklines] = minorticklines translate!(minorticklines, 0, 0, 10) - realticklabelalign = Observable{Tuple{Symbol, Symbol}}((:none, :none); ignore_equal_values=true) + realticklabelalign = Observable{Tuple{Symbol,Symbol}}((:none, :none); ignore_equal_values=true) - map!(calculate_real_ticklabel_align, realticklabelalign, ticklabelalign, horizontal, flipped, ticklabelrotation) + map!( + calculate_real_ticklabel_align, + realticklabelalign, + ticklabelalign, + horizontal, + flipped, + ticklabelrotation, + ) - ticklabel_annotation_obs = Observable(Tuple{AbstractString, Point2f}[]; ignore_equal_values=true) + ticklabel_annotation_obs = Observable(Tuple{AbstractString,Point2f}[]; ignore_equal_values=true) ticklabels = nothing # this gets overwritten later to be used in the below - ticklabel_ideal_space = Observable(0f0; ignore_equal_values=true) + ticklabel_ideal_space = Observable(0.0f0; ignore_equal_values=true) - map!(ticklabel_ideal_space, ticklabel_annotation_obs, ticklabelalign, ticklabelrotation, ticklabelfont, ticklabelsvisible) do args... + map!( + ticklabel_ideal_space, + ticklabel_annotation_obs, + ticklabelalign, + ticklabelrotation, + ticklabelfont, + ticklabelsvisible, + ) do args... maxwidth = if pos_extents_horizontal[][3] - # height - ticklabelsvisible[] ? (ticklabels === nothing ? 0f0 : height(Rect2f(boundingbox(ticklabels)))) : 0f0 - else - # width - ticklabelsvisible[] ? (ticklabels === nothing ? 0f0 : width(Rect2f(boundingbox(ticklabels)))) : 0f0 + # height + ticklabelsvisible[] ? + (ticklabels === nothing ? 0.0f0 : height(Rect2f(boundingbox(ticklabels)))) : 0.0f0 + else + # width + ticklabelsvisible[] ? + (ticklabels === nothing ? 0.0f0 : width(Rect2f(boundingbox(ticklabels)))) : 0.0f0 end # in case there is no string in the annotations and the boundingbox comes back all NaN if !isfinite(maxwidth) @@ -308,7 +394,7 @@ function LineAxis(parent::Scene, attrs::Attributes) return maxwidth end - attrs[:actual_ticklabelspace] = 0f0 + attrs[:actual_ticklabelspace] = 0.0f0 actual_ticklabelspace = attrs[:actual_ticklabelspace] onany(ticklabel_ideal_space, ticklabelspace) do idealspace, space @@ -322,24 +408,35 @@ function LineAxis(parent::Scene, attrs::Attributes) end end - tickspace = Observable(0f0; ignore_equal_values=true) + tickspace = Observable(0.0f0; ignore_equal_values=true) map!(tickspace, ticksvisible, ticksize, tickalign) do ticksvisible, ticksize, tickalign - ticksvisible ? max(0f0, ticksize * (1f0 - tickalign)) : 0f0 + return ticksvisible ? max(0.0f0, ticksize * (1.0f0 - tickalign)) : 0.0f0 end - labelgap = Observable(0f0; ignore_equal_values=true) - map!(labelgap, spinewidth, tickspace, ticklabelsvisible, actual_ticklabelspace, - ticklabelpad, labelpadding) do spinewidth, tickspace, ticklabelsvisible, - actual_ticklabelspace, ticklabelpad, labelpadding - - return spinewidth + tickspace + - (ticklabelsvisible ? actual_ticklabelspace + ticklabelpad : 0f0) + - labelpadding + labelgap = Observable(0.0f0; ignore_equal_values=true) + map!( + labelgap, + spinewidth, + tickspace, + ticklabelsvisible, + actual_ticklabelspace, + ticklabelpad, + labelpadding, + ) do spinewidth, tickspace, ticklabelsvisible, actual_ticklabelspace, ticklabelpad, labelpadding + return spinewidth + + tickspace + + (ticklabelsvisible ? actual_ticklabelspace + ticklabelpad : 0.0f0) + + labelpadding end labelpos = Observable(Point2f(NaN); ignore_equal_values=true) - map!(labelpos, pos_extents_horizontal, flipped, labelgap) do (position, extents, horizontal), flipped, labelgap + map!( + labelpos, + pos_extents_horizontal, + flipped, + labelgap, + ) do (position, extents, horizontal), flipped, labelgap # fullgap = tickspace[] + labelgap middle = extents[1] + 0.5f0 * (extents[2] - extents[1]) @@ -350,8 +447,13 @@ function LineAxis(parent::Scene, attrs::Attributes) # Initial values should be overwritten by map!. `ignore_equal_values` doesn't work right now without initial values labelalign = Observable((:none, :none); ignore_equal_values=true) - map!(labelalign, labelrotation, horizontal, flipped, flip_vertical_label) do labelrotation, - horizontal::Bool, flipped::Bool, flip_vertical_label::Bool + map!( + labelalign, + labelrotation, + horizontal, + flipped, + flip_vertical_label, + ) do labelrotation, horizontal::Bool, flipped::Bool, flip_vertical_label::Bool return if labelrotation isa Automatic if horizontal (:center, flipped ? :bottom : :top) @@ -364,15 +466,19 @@ function LineAxis(parent::Scene, attrs::Attributes) end else (:center, :center) - end::NTuple{2, Symbol} + end::NTuple{2,Symbol} end - labelrot = Observable(0f0; ignore_equal_values=true) - map!(labelrot, labelrotation, horizontal, flip_vertical_label) do labelrotation, - horizontal::Bool, flip_vertical_label::Bool + labelrot = Observable(0.0f0; ignore_equal_values=true) + map!( + labelrot, + labelrotation, + horizontal, + flip_vertical_label, + ) do labelrotation, horizontal::Bool, flip_vertical_label::Bool return if labelrotation isa Automatic if horizontal - 0f0 + 0.0f0 else (flip_vertical_label ? -0.5f0 : 0.5f0) * π end @@ -382,27 +488,34 @@ function LineAxis(parent::Scene, attrs::Attributes) end labeltext = text!( - parent, labelpos, text = label, fontsize = labelsize, color = labelcolor, - visible = labelvisible, - align = labelalign, rotation = labelrot, font = labelfont, - markerspace = :data, inspectable = false + parent, + labelpos, + text=label, + fontsize=labelsize, + color=labelcolor, + visible=labelvisible, + align=labelalign, + rotation=labelrot, + font=labelfont, + markerspace=:data, + inspectable=false, ) # translate axis labels on explicit rotations # in order to prevent plot and axis overlap onany(labelrotation, flipped, horizontal) do labelrotation, flipped, horizontal xs::Float32, ys::Float32 = if labelrotation isa Automatic - 0f0, 0f0 + 0.0f0, 0.0f0 else wx, wy = widths(boundingbox(labeltext)) sign::Int = flipped ? 1 : -1 if horizontal - 0f0, Float32(sign * 0.5f0 * wy) + 0.0f0, Float32(sign * 0.5f0 * wy) else - Float32(sign * 0.5f0 * wx), 0f0 + Float32(sign * 0.5f0 * wx), 0.0f0 end end - translate!(labeltext, xs, ys, 0f0) + return translate!(labeltext, xs, ys, 0.0f0) end decorations[:labeltext] = labeltext @@ -410,17 +523,27 @@ function LineAxis(parent::Scene, attrs::Attributes) tickvalues = Observable(Float32[]; ignore_equal_values=true) tickvalues_labels_unfiltered = Observable{Tuple{Vector{Float32},Vector{AbstractString}}}() - map!(tickvalues_labels_unfiltered, pos_extents_horizontal, limits, ticks, tickformat, attrs.scale) do (position, extents, horizontal), - limits, ticks, tickformat, scale - get_ticks(ticks, scale, tickformat, limits...) + map!( + tickvalues_labels_unfiltered, + pos_extents_horizontal, + limits, + ticks, + tickformat, + attrs.scale, + ) do (position, extents, horizontal), limits, ticks, tickformat, scale + return get_ticks(ticks, scale, tickformat, limits...) end tickpositions = Observable(Point2f[]; ignore_equal_values=true) tickstrings = Observable(AbstractString[]; ignore_equal_values=true) - onany(update_tickpos_string, + onany( + update_tickpos_string, Observable((tickstrings, tickpositions, tickvalues, pos_extents_horizontal, limits)), - tickvalues_labels_unfiltered, reversed, attrs.scale) + tickvalues_labels_unfiltered, + reversed, + attrs.scale, + ) minortickvalues = Observable(Float32[]; ignore_equal_values=true) minortickpositions = Observable(Point2f[]; ignore_equal_values=true) @@ -431,38 +554,87 @@ function LineAxis(parent::Scene, attrs::Attributes) end onany(minortickvalues, limits, pos_extents_horizontal) do mtv, limits, peh - update_minor_ticks(minortickpositions, limits, peh, mtv, attrs.scale[], reversed[]) - end - - onany(update_tick_obs, - Observable(minorticksnode), Observable(horizontal), Observable(flipped), - minortickpositions, minortickalign, minorticksize, spinewidth) + return update_minor_ticks(minortickpositions, limits, peh, mtv, attrs.scale[], reversed[]) + end + + onany( + update_tick_obs, + Observable(minorticksnode), + Observable(horizontal), + Observable(flipped), + minortickpositions, + minortickalign, + minorticksize, + spinewidth, + ) - onany(update_ticklabel_node, + onany( + update_ticklabel_node, # we don't want to update on these, so we wrap them in an observable: Observable((horizontal, spinewidth, tickspace, ticklabelpad, tickvalues)), Observable(ticklabel_annotation_obs), - labelgap, flipped, tickpositions, tickstrings) + labelgap, + flipped, + tickpositions, + tickstrings, + ) - onany(update_tick_obs, - Observable(ticksnode), Observable(horizontal), Observable(flipped), - tickpositions, tickalign, ticksize, spinewidth) + onany( + update_tick_obs, + Observable(ticksnode), + Observable(horizontal), + Observable(flipped), + tickpositions, + tickalign, + ticksize, + spinewidth, + ) - linepoints = lift(create_linepoints, pos_extents_horizontal, flipped, spinewidth, trimspine, tickpositions, tickwidth) + linepoints = lift( + create_linepoints, + pos_extents_horizontal, + flipped, + spinewidth, + trimspine, + tickpositions, + tickwidth, + ) - decorations[:axisline] = linesegments!(parent, linepoints, linewidth = spinewidth, visible = spinevisible, - color = spinecolor, inspectable = false, linestyle = nothing) + decorations[:axisline] = linesegments!( + parent, + linepoints, + linewidth=spinewidth, + visible=spinevisible, + color=spinecolor, + inspectable=false, + linestyle=nothing, + ) translate!(decorations[:axisline], 0, 0, 20) - protrusion = Observable(0f0; ignore_equal_values=true) + protrusion = Observable(0.0f0; ignore_equal_values=true) - map!(calculate_protrusion, protrusion, + map!( + calculate_protrusion, + protrusion, # we pass these as observables, to not trigger on them Observable((horizontal, labeltext, ticklabel_annotation_obs)), - ticksvisible, label, labelvisible, labelpadding, tickspace, ticklabelsvisible, actual_ticklabelspace, ticklabelpad, + ticksvisible, + label, + labelvisible, + labelpadding, + tickspace, + ticklabelsvisible, + actual_ticklabelspace, + ticklabelpad, # we don't need these as arguments to calculate it, but we need to pass it because it indirectly influences the protrusion - labelfont, labelalign, labelrot, labelsize, ticklabelfont, tickalign) + labelfont, + labelalign, + labelrot, + labelsize, + ticklabelfont, + tickalign, + ) # trigger whole pipeline once to fill tickpositions and tickstrings # etc to avoid empty ticks bug #69 @@ -473,14 +645,15 @@ function LineAxis(parent::Scene, attrs::Attributes) ticklabels = text!( parent, ticklabel_annotation_obs, - align = realticklabelalign, - rotation = ticklabelrotation, - fontsize = ticklabelsize, - font = ticklabelfont, - color = ticklabelcolor, - visible = ticklabelsvisible, - markerspace = :data, - inspectable = false) + align=realticklabelalign, + rotation=ticklabelrotation, + fontsize=ticklabelsize, + font=ticklabelfont, + color=ticklabelcolor, + visible=ticklabelsvisible, + markerspace=:data, + inspectable=false, + ) decorations[:ticklabels] = ticklabels @@ -493,11 +666,20 @@ function LineAxis(parent::Scene, attrs::Attributes) # trigger calculation of ticklabel width once, now that it's not nothing anymore notify(ticklabelsvisible) - return LineAxis(parent, protrusion, attrs, decorations, tickpositions, tickvalues, tickstrings, minortickpositions, minortickvalues) + return LineAxis( + parent, + protrusion, + attrs, + decorations, + tickpositions, + tickvalues, + tickstrings, + minortickpositions, + minortickvalues, + ) end function tight_ticklabel_spacing!(la::LineAxis) - horizontal = if la.attributes.endpoints[][1][2] == la.attributes.endpoints[][2][2] true elseif la.attributes.endpoints[][1][1] == la.attributes.endpoints[][2][1] @@ -508,20 +690,19 @@ function tight_ticklabel_spacing!(la::LineAxis) tls = la.elements[:ticklabels] maxwidth = if horizontal - # height - tls.visible[] ? height(Rect2f(boundingbox(tls))) : 0f0 - else - # width - tls.visible[] ? width(Rect2f(boundingbox(tls))) : 0f0 + # height + tls.visible[] ? height(Rect2f(boundingbox(tls))) : 0.0f0 + else + # width + tls.visible[] ? width(Rect2f(boundingbox(tls))) : 0.0f0 end la.attributes.ticklabelspace = maxwidth return Float64(maxwidth) end - iswhitespace(str) = match(r"^\s*$", str) !== nothing -function Base.delete!(la::LineAxis) +Base.delete!(la::LineAxis) = for (_, d) in la.elements if d isa AbstractPlot delete!(d.parent, d) @@ -529,7 +710,6 @@ function Base.delete!(la::LineAxis) delete!(d) end end -end """ get_ticks(ticks, scale, formatter, vmin, vmax) @@ -547,7 +727,9 @@ function get_ticks(ticks, scale, formatter, vmin, vmax) end # automatic with identity scaling uses WilkinsonTicks by default -get_tickvalues(::Automatic, ::typeof(identity), vmin, vmax) = get_tickvalues(WilkinsonTicks(5, k_min = 3), vmin, vmax) +function get_tickvalues(::Automatic, ::typeof(identity), vmin, vmax) + return get_tickvalues(WilkinsonTicks(5, k_min=3), vmin, vmax) +end # fall back to identity if not overloaded scale function is used with automatic get_tickvalues(::Automatic, F, vmin, vmax) = get_tickvalues(automatic, identity, vmin, vmax) @@ -555,18 +737,20 @@ get_tickvalues(::Automatic, F, vmin, vmax) = get_tickvalues(automatic, identity, # fall back to non-scale aware behavior if no special version is overloaded get_tickvalues(ticks, scale, vmin, vmax) = get_tickvalues(ticks, vmin, vmax) -function get_ticks(ticks_and_labels::Tuple{Any, Any}, any_scale, ::Automatic, vmin, vmax) +function get_ticks(ticks_and_labels::Tuple{Any,Any}, any_scale, ::Automatic, vmin, vmax) n1 = length(ticks_and_labels[1]) n2 = length(ticks_and_labels[2]) if n1 != n2 - error("There are $n1 tick values in $(ticks_and_labels[1]) but $n2 tick labels in $(ticks_and_labels[2]).") + error( + "There are $n1 tick values in $(ticks_and_labels[1]) but $n2 tick labels in $(ticks_and_labels[2]).", + ) end - ticks_and_labels + return ticks_and_labels end function get_ticks(tickfunction::Function, any_scale, formatter, vmin, vmax) result = tickfunction(vmin, vmax) - if result isa Tuple{Any, Any} + if result isa Tuple{Any,Any} tickvalues, ticklabels = result else tickvalues = result @@ -579,14 +763,18 @@ _logbase(::typeof(log10)) = "10" _logbase(::typeof(log2)) = "2" _logbase(::typeof(log)) = "e" - -function get_ticks(::Automatic, scale::Union{typeof(log10), typeof(log2), typeof(log)}, - any_formatter, vmin, vmax) - get_ticks(LogTicks(WilkinsonTicks(5, k_min = 3)), scale, any_formatter, vmin, vmax) +function get_ticks( + ::Automatic, + scale::Union{typeof(log10),typeof(log2),typeof(log)}, + any_formatter, + vmin, + vmax, +) + return get_ticks(LogTicks(WilkinsonTicks(5, k_min=3)), scale, any_formatter, vmin, vmax) end # log ticks just use the normal pipeline but with log'd limits, then transform the labels -function get_ticks(l::LogTicks, scale::Union{typeof(log10), typeof(log2), typeof(log)}, ::Automatic, vmin, vmax) +function get_ticks(l::LogTicks, scale::Union{typeof(log10),typeof(log2),typeof(log)}, ::Automatic, vmin, vmax) ticks_scaled = get_tickvalues(l.linear_ticks, identity, scale(vmin), scale(vmax)) ticks = Makie.inverse_transform(scale).(ticks_scaled) @@ -595,11 +783,11 @@ function get_ticks(l::LogTicks, scale::Union{typeof(log10), typeof(log2), typeof # avoid unicode superscripts in ticks, as the ticks are converted # to superscripts in the next step xs -> Showoff.showoff(xs, :plain), - ticks_scaled + ticks_scaled, ) - labels = rich.(_logbase(scale), superscript.(labels_scaled, offset = Vec2f(0.1f0, 0f0))) + labels = rich.(_logbase(scale), superscript.(labels_scaled, offset=Vec2f(0.1f0, 0.0f0))) - (ticks, labels) + return (ticks, labels) end # function get_ticks(::Automatic, scale::typeof(Makie.logit), any_formatter, vmin, vmax) @@ -638,7 +826,6 @@ Runs a common tick finding algorithm to as many ticks as requested by the """ get_tickvalues(lt::LinearTicks, vmin, vmax) = locateticks(vmin, vmax, lt.n_ideal) - """ get_tickvalues(tickvalues, vmin, vmax) @@ -646,7 +833,6 @@ Convert tickvalues to a float array by default. """ get_tickvalues(tickvalues, vmin, vmax) = convert(Vector{Float64}, tickvalues) - # function get_tickvalues(l::LogitTicks, vmin, vmax) # ticks_scaled = get_tickvalues(l.linear_ticks, identity, logit_10(vmin), logit_10(vmax)) # expit_10.(ticks_scaled) @@ -654,7 +840,7 @@ get_tickvalues(tickvalues, vmin, vmax) = convert(Vector{Float64}, tickvalues) function get_tickvalues(l::LogTicks, scale, vmin, vmax) ticks_scaled = get_tickvalues(l.linear_ticks, scale(vmin), scale(vmax)) - Makie.inverse_transform(scale).(ticks_scaled) + return Makie.inverse_transform(scale).(ticks_scaled) end """ @@ -678,13 +864,12 @@ Gets tick labels by formatting each value in `values` according to a `Formatting """ get_ticklabels(formatstring::AbstractString, values) = [Formatting.format(formatstring, v) for v in values] - function get_ticks(m::MultiplesTicks, any_scale, ::Automatic, vmin, vmax) dvmin = vmin / m.multiple dvmax = vmax / m.multiple multiples = Makie.get_tickvalues(LinearTicks(m.n_ideal), dvmin, dvmax) - multiples .* m.multiple, Showoff.showoff(multiples) .* m.suffix + return multiples .* m.multiple, Showoff.showoff(multiples) .* m.suffix end function get_minor_tickvalues(i::IntervalsBetween, scale, tickvalues, vmin, vmax) @@ -696,32 +881,37 @@ function get_minor_tickvalues(i::IntervalsBetween, scale, tickvalues, vmin, vmax firstinterval = tickvalues[2] - tickvalues[1] stepsize = firstinterval / n v = tickvalues[1] - stepsize - prepend!(vals, v:-stepsize:vmin) + prepend!(vals, v:(-stepsize):vmin) end - for (lo, hi) in zip(@view(tickvalues[1:end-1]), @view(tickvalues[2:end])) + for (lo, hi) in zip(@view(tickvalues[1:(end - 1)]), @view(tickvalues[2:end])) interval = hi - lo stepsize = interval / n v = lo - for i in 1:n-1 + for i in 1:(n - 1) v += stepsize push!(vals, v) end end if i.mirror - lastinterval = tickvalues[end] - tickvalues[end-1] + lastinterval = tickvalues[end] - tickvalues[end - 1] stepsize = lastinterval / n v = tickvalues[end] + stepsize append!(vals, v:stepsize:vmax) end - vals + return vals end # for log scales, we need to step in log steps at the edges -function get_minor_tickvalues(i::IntervalsBetween, scale::Union{typeof(log), typeof(log2), typeof(log10)}, tickvalues, vmin, vmax) - +function get_minor_tickvalues( + i::IntervalsBetween, + scale::Union{typeof(log),typeof(log2),typeof(log10)}, + tickvalues, + vmin, + vmax, +) vals = Float64[] length(tickvalues) < 2 && return vals n = i.n @@ -734,30 +924,28 @@ function get_minor_tickvalues(i::IntervalsBetween, scale::Union{typeof(log), typ prevtick = invscale(scale(tickvalues[1]) - firstinterval_scaled) stepsize = (tickvalues[1] - prevtick) / n v = tickvalues[1] - stepsize - prepend!(vals, v:-stepsize:vmin) + prepend!(vals, v:(-stepsize):vmin) end - for (lo, hi) in zip(@view(tickvalues[1:end-1]), @view(tickvalues[2:end])) + for (lo, hi) in zip(@view(tickvalues[1:(end - 1)]), @view(tickvalues[2:end])) interval = hi - lo stepsize = interval / n v = lo - for i in 1:n-1 + for i in 1:(n - 1) v += stepsize push!(vals, v) end end if i.mirror - lastinterval_scaled = scale(tickvalues[end]) - scale(tickvalues[end-1]) + lastinterval_scaled = scale(tickvalues[end]) - scale(tickvalues[end - 1]) nexttick = invscale(scale(tickvalues[end]) + lastinterval_scaled) stepsize = (nexttick - tickvalues[end]) / n v = tickvalues[end] + stepsize append!(vals, v:stepsize:vmax) end - vals + return vals end -function get_minor_tickvalues(v::AbstractVector{<:Real}, _, _, _, _) - Float32.(v) -end +get_minor_tickvalues(v::AbstractVector{<:Real}, _, _, _, _) = Float32.(v) diff --git a/src/makielayout/mousestatemachine.jl b/src/makielayout/mousestatemachine.jl index 40653697f4a..d548a9e9389 100644 --- a/src/makielayout/mousestatemachine.jl +++ b/src/makielayout/mousestatemachine.jl @@ -1,32 +1,32 @@ module MouseEventTypes - @enum MouseEventType begin - out - enter - over - leftdown - rightdown - middledown - leftup - rightup - middleup - leftdragstart - rightdragstart - middledragstart - leftdrag - rightdrag - middledrag - leftdragstop - rightdragstop - middledragstop - leftclick - rightclick - middleclick - leftdoubleclick - rightdoubleclick - middledoubleclick - downoutside - end - export MouseEventType +@enum MouseEventType begin + out + enter + over + leftdown + rightdown + middledown + leftup + rightup + middleup + leftdragstart + rightdragstart + middledragstart + leftdrag + rightdrag + middledrag + leftdragstop + rightdragstop + middledragstop + leftclick + rightclick + middleclick + leftdoubleclick + rightdoubleclick + middledoubleclick + downoutside +end +export MouseEventType end using .MouseEventTypes @@ -68,31 +68,27 @@ function clear!(handle::MouseEventHandle) foreach(Observables.off, handle.observerfuncs) empty!(handle.observerfuncs) empty!(handle.obs.listeners) - nothing + return nothing end - for eventtype in instances(MouseEventType) onfunctionname = Symbol("onmouse" * String(Symbol(eventtype))) @eval begin - """ Executes the function f whenever the `MouseEventHandle`'s observable is set to a MouseEvent with `event.type === $($eventtype)`. """ - function $onfunctionname(f, mev::MouseEventHandle; priority = 0) - on(mev.obs, priority = priority) do event + $onfunctionname(f, mev::MouseEventHandle; priority=0) = + on(mev.obs, priority=priority) do event if event.type === $eventtype return f(event) end return Consume(false) end - end export $onfunctionname end end - """ addmouseevents!(scene, elements...) @@ -112,22 +108,23 @@ onmouseleftclick(mouseevents) do event end ``` """ -function addmouseevents!(scene, elements...; priority = 1) - is_mouse_over_relevant_area() = isempty(elements) ? Makie.is_mouseinside(scene) : mouseover(scene, elements...) - _addmouseevents!(scene, is_mouse_over_relevant_area, priority) +function addmouseevents!(scene, elements...; priority=1) + function is_mouse_over_relevant_area() + return isempty(elements) ? Makie.is_mouseinside(scene) : mouseover(scene, elements...) + end + return _addmouseevents!(scene, is_mouse_over_relevant_area, priority) end -function addmouseevents!(scene, bbox::Observables.AbstractObservable{<: Rect2}; priority = 1) +function addmouseevents!(scene, bbox::Observables.AbstractObservable{<:Rect2}; priority=1) is_mouse_over_relevant_area() = Makie.mouseposition_px(scene) in bbox[] - _addmouseevents!(scene, is_mouse_over_relevant_area, priority) + return _addmouseevents!(scene, is_mouse_over_relevant_area, priority) end - function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse = Makie.Mouse dblclick_max_interval = 0.2 mouseevent = Observable{MouseEvent}( - MouseEvent(MouseEventTypes.out, 0.0, Point2f(0, 0), Point2f(0, 0), 0.0, Point2f(0, 0), Point2f(0, 0)) + MouseEvent(MouseEventTypes.out, 0.0, Point2f(0, 0), Point2f(0, 0), 0.0, Point2f(0, 0), Point2f(0, 0)), ) # initialize state variables last_mouseevent = Ref{Mouse.Action}(Mouse.release) @@ -157,7 +154,6 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) # it can also mean that a drag that started outside and isn't related to this # object is going across it and should be ignored here if last_mouseevent[] == Mouse.press - if drag_ongoing[] # continue the drag event = @match mouse_downed_button[] begin @@ -166,9 +162,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse.middle => MouseEventTypes.middledrag x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) - ) + x = setindex!(mouseevent, MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[])) consumed = consumed || x else # mouse was downed inside but no drag is ongoing @@ -181,8 +175,9 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse.middle => MouseEventTypes.middledragstart x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x @@ -192,8 +187,9 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse.middle => MouseEventTypes.middledrag x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x end @@ -201,19 +197,22 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) else if mouse_inside x = if mouse_was_inside[] - setindex!(mouseevent, - MouseEvent(MouseEventTypes.over, t, data, px, prev_t[], prev_data[], prev_px[]) + setindex!( + mouseevent, + MouseEvent(MouseEventTypes.over, t, data, px, prev_t[], prev_data[], prev_px[]), ) else - setindex!(mouseevent, - MouseEvent(MouseEventTypes.enter, t, data, px, prev_t[], prev_data[], prev_px[]) + setindex!( + mouseevent, + MouseEvent(MouseEventTypes.enter, t, data, px, prev_t[], prev_data[], prev_px[]), ) end consumed = consumed || x else if mouse_was_inside[] - x = setindex!(mouseevent, - MouseEvent(MouseEventTypes.out, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(MouseEventTypes.out, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x end @@ -227,7 +226,6 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) return Consume(consumed) end - # react to mouse button changes mousedrag_observerfunc = on(events(scene).mousebutton, priority=priority) do event consumed = false @@ -253,15 +251,25 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse.middle => MouseEventTypes.middledown x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x mouse_downed_inside[] = true else mouse_downed_inside[] = false - x = setindex!(mouseevent, - MouseEvent(MouseEventTypes.downoutside, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent( + MouseEventTypes.downoutside, + t, + data, + px, + prev_t[], + prev_data[], + prev_px[], + ), ) consumed = consumed || x end @@ -276,7 +284,6 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) some_mouse_button_had_been_downed = !isnothing(mouse_downed_button[]) if downed_button_missing_from_pressed && some_mouse_button_had_been_downed - if drag_ongoing[] event = @match mouse_downed_button[] begin Mouse.left => MouseEventTypes.leftdragstop @@ -284,8 +291,9 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse.middle => MouseEventTypes.middledragstop x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x drag_ongoing[] = false @@ -299,14 +307,16 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x else # mouse could be not over elements after drag is over - x = setindex!(mouseevent, - MouseEvent(MouseEventTypes.out, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(MouseEventTypes.out, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x end @@ -317,17 +327,18 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) # guard against mouse coming in from outside, then mouse upping if mouse_downed_inside[] - if dt_last_click < dblclick_max_interval && !last_click_was_double[] && - mouse_downed_button[] == b_last_click[] - + if dt_last_click < dblclick_max_interval && + !last_click_was_double[] && + mouse_downed_button[] == b_last_click[] event = @match mouse_downed_button[] begin Mouse.left => MouseEventTypes.leftdoubleclick Mouse.right => MouseEventTypes.rightdoubleclick Mouse.middle => MouseEventTypes.middledoubleclick x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x last_click_was_double[] = true @@ -338,8 +349,9 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse.middle => MouseEventTypes.middleclick x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x last_click_was_double[] = false @@ -357,8 +369,9 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) x => error("No recognized mouse button $x") end - x = setindex!(mouseevent, - MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]) + x = setindex!( + mouseevent, + MouseEvent(event, t, data, px, prev_t[], prev_data[], prev_px[]), ) consumed = consumed || x end @@ -368,10 +381,9 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) last_mouseevent[] = Mouse.release end - prev_t[] = t return Consume(consumed) end - MouseEventHandle(mouseevent, [mousepos_observerfunc, mousedrag_observerfunc]) + return MouseEventHandle(mouseevent, [mousepos_observerfunc, mousedrag_observerfunc]) end diff --git a/src/makielayout/roundedrect.jl b/src/makielayout/roundedrect.jl index f8109fe645a..f4f5cd86963 100644 --- a/src/makielayout/roundedrect.jl +++ b/src/makielayout/roundedrect.jl @@ -1,24 +1,20 @@ @recipe(RoundedRect) do scene - Theme( - rect = BBox(0, 100, 0, 100), - cornerradius = 5, - cornersegments = 10, - color = RGBf(0.9, 0.9, 0.9), - strokecolor = RGBf(0, 0, 0) + return Theme( + rect=BBox(0, 100, 0, 100), + cornerradius=5, + cornersegments=10, + color=RGBf(0.9, 0.9, 0.9), + strokecolor=RGBf(0, 0, 0), ) end function plot!(roundrect::RoundedRect) - @extract(roundrect, ( - rect, cornerradius, cornersegments, color, strokecolor - )) + @extract(roundrect, (rect, cornerradius, cornersegments, color, strokecolor)) heightattr = roundrect.height widthattr = roundrect.width - roundedrectpoints = lift(rect, cornerradius, cornersegments) do rect, - cr, csegs - + roundedrectpoints = lift(rect, cornerradius, cornersegments) do rect, cr, csegs cr = min(width(rect) / 2, height(rect) / 2, cr) # inner corners @@ -27,13 +23,13 @@ function plot!(roundrect::RoundedRect) icbl = bottomleft(rect) .+ Point2(cr, cr) icbr = bottomright(rect) .+ Point2(-cr, cr) - cstr = anglepoint.(Ref(ictr), LinRange(0, pi/2, csegs), cr) - cstl = anglepoint.(Ref(ictl), LinRange(pi/2, pi, csegs), cr) - csbl = anglepoint.(Ref(icbl), LinRange(pi, 3pi/2, csegs), cr) - csbr = anglepoint.(Ref(icbr), LinRange(3pi/2, 2pi, csegs), cr) + cstr = anglepoint.(Ref(ictr), LinRange(0, pi / 2, csegs), cr) + cstl = anglepoint.(Ref(ictl), LinRange(pi / 2, pi, csegs), cr) + csbl = anglepoint.(Ref(icbl), LinRange(pi, 3pi / 2, csegs), cr) + csbr = anglepoint.(Ref(icbr), LinRange(3pi / 2, 2pi, csegs), cr) return [cstr; cstl; csbl; csbr] end - poly!(roundrect, roundedrectpoints, color = color, strokecolor = strokecolor) + return poly!(roundrect, roundedrectpoints, color=color, strokecolor=strokecolor) end diff --git a/src/makielayout/ticklocators/linear.jl b/src/makielayout/ticklocators/linear.jl index 75e6d02c133..ae8b7d7f6b6 100644 --- a/src/makielayout/ticklocators/linear.jl +++ b/src/makielayout/ticklocators/linear.jl @@ -4,27 +4,26 @@ function scale_range(vmin, vmax, n=1, threshold=100) offset = if abs(meanv) / dv < threshold 0.0 else - copysign(10 ^ (log10(abs(meanv)) ÷ 1), meanv) + copysign(10^(log10(abs(meanv)) ÷ 1), meanv) end - scale = 10 ^ (log10(dv / n) ÷ 1) - scale, offset + scale = 10^(log10(dv / n) ÷ 1) + return scale, offset end function _staircase(steps) n = length(steps) result = Vector{Float64}(undef, 2n) - for i in 1:(n-1) + for i in 1:(n - 1) @inbounds result[i] = 0.1 * steps[i] end for i in 1:n - @inbounds result[i+(n-1)] = steps[i] + @inbounds result[i + (n - 1)] = steps[i] end result[end] = 10 * steps[2] return result # [0.1 .* steps[1:end-1]; steps; 10 .* steps[2]] end - struct EdgeInteger step::Float64 offset::Float64 @@ -33,19 +32,19 @@ struct EdgeInteger if step <= 0 error("Step must be positive") end - new(step, abs(offset)) + return new(step, abs(offset)) end end function closeto(e::EdgeInteger, ms, edge) tol = if e.offset > 0 digits = log10(e.offset / e.step) - tol = max(1e-10, 10 ^ (digits - 12)) + tol = max(1e-10, 10^(digits - 12)) min(0.4999, tol) else 1e-10 end - abs(ms - edge) < tol + return abs(ms - edge) < tol end function le(e::EdgeInteger, x) @@ -68,12 +67,10 @@ function ge(e::EdgeInteger, x) end end - """ A cheaper function that tries to come up with usable tick locations for a given value range """ -function locateticks(vmin, vmax, n_ideal::Int, _integer::Bool = false, _min_n_ticks::Int = 2) - +function locateticks(vmin, vmax, n_ideal::Int, _integer::Bool=false, _min_n_ticks::Int=2) @assert isfinite(vmin) @assert isfinite(vmax) @assert vmin != vmax @@ -93,7 +90,7 @@ function locateticks(vmin, vmax, n_ideal::Int, _integer::Bool = false, _min_n_ti if _integer # For steps > 1, keep only integer values. filter!(steps) do i - (i < 1) || (abs(i - round(i)) < 0.001) + return (i < 1) || (abs(i - round(i)) < 0.001) end end @@ -142,12 +139,18 @@ function locateticks(vmin, vmax, n_ideal::Int, _integer::Bool = false, _min_n_ti # 0.08000000001 instead of 0.08 # so here we round off the numbers to the required number of digits after the decimal point exponent = floor(Int, minimum(log10.(abs.(diff(vals))))) - round.(vals, digits = max(0, -exponent+1)) + return round.(vals, digits=max(0, -exponent + 1)) end - -function locateticks(vmin, vmax, width_px, ideal_tick_distance::Float32, _integer::Bool = false, _min_n_ticks::Int = 2) +function locateticks( + vmin, + vmax, + width_px, + ideal_tick_distance::Float32, + _integer::Bool=false, + _min_n_ticks::Int=2, +) # how many ticks would ideally fit? n_ideal = round(Int, width_px / ideal_tick_distance) + 1 - locateticks(vmin, vmax, n_ideal, _integer, _min_n_ticks) + return locateticks(vmin, vmax, n_ideal, _integer, _min_n_ticks) end diff --git a/src/makielayout/ticklocators/wilkinson.jl b/src/makielayout/ticklocators/wilkinson.jl index 2e5922db448..892faa57a60 100644 --- a/src/makielayout/ticklocators/wilkinson.jl +++ b/src/makielayout/ticklocators/wilkinson.jl @@ -1,33 +1,49 @@ -function WilkinsonTicks(k_ideal::Int; k_min = 2, k_max = 10, - Q = [(1.0,1.0), (5.0, 0.9), (2.0, 0.7), (2.5, 0.5), (3.0, 0.2)], - granularity_weight = 1/4, - simplicity_weight = 1/6, - coverage_weight = 1/3, - niceness_weight = 1/4, - min_px_dist = 50.0) - +function WilkinsonTicks( + k_ideal::Int; + k_min=2, + k_max=10, + Q=[(1.0, 1.0), (5.0, 0.9), (2.0, 0.7), (2.5, 0.5), (3.0, 0.2)], + granularity_weight=1 / 4, + simplicity_weight=1 / 6, + coverage_weight=1 / 3, + niceness_weight=1 / 4, + min_px_dist=50.0, +) if !(0 < k_min <= k_ideal <= k_max) error("Invalid tick number specifications k_ideal $k_ideal, k_min $k_min, k_max $k_max") end - WilkinsonTicks(k_ideal, k_min, k_max, Q, granularity_weight, simplicity_weight, - coverage_weight, niceness_weight, min_px_dist) + return WilkinsonTicks( + k_ideal, + k_min, + k_max, + Q, + granularity_weight, + simplicity_weight, + coverage_weight, + niceness_weight, + min_px_dist, + ) end get_tickvalues(ticks::WilkinsonTicks, vmin, vmax) = get_tickvalues(ticks, Float64(vmin), Float64(vmax)) function get_tickvalues(ticks::WilkinsonTicks, vmin::Float64, vmax::Float64) + tickvalues, _ = PlotUtils.optimize_ticks( + Float64(vmin), + Float64(vmax); + extend_ticks=false, + strict_span=true, + span_buffer=nothing, + k_min=ticks.k_min, + k_max=ticks.k_max, + k_ideal=ticks.k_ideal, + Q=ticks.Q, + granularity_weight=ticks.granularity_weight, + simplicity_weight=ticks.simplicity_weight, + coverage_weight=ticks.coverage_weight, + niceness_weight=ticks.niceness_weight, + ) - tickvalues, _ = PlotUtils.optimize_ticks(Float64(vmin), Float64(vmax); - extend_ticks = false, strict_span=true, span_buffer = nothing, - k_min = ticks.k_min, - k_max = ticks.k_max, - k_ideal = ticks.k_ideal, - Q = ticks.Q, - granularity_weight = ticks.granularity_weight, - simplicity_weight = ticks.simplicity_weight, - coverage_weight = ticks.coverage_weight, - niceness_weight = ticks.niceness_weight) - - tickvalues + return tickvalues end diff --git a/src/makielayout/types.jl b/src/makielayout/types.jl index bf52b111bb7..96a954bc5d7 100644 --- a/src/makielayout/types.jl +++ b/src/makielayout/types.jl @@ -1,6 +1,4 @@ -const Optional{T} = Union{Nothing, T} - - +const Optional{T} = Union{Nothing,T} struct AxisAspect aspect::Float32 @@ -8,27 +6,25 @@ end struct DataAspect end - struct Cycler - counters::Dict{Type, Int} + counters::Dict{Type,Int} end -Cycler() = Cycler(Dict{Type, Int}()) - +Cycler() = Cycler(Dict{Type,Int}()) struct Cycle - cycle::Vector{Pair{Vector{Symbol}, Symbol}} + cycle::Vector{Pair{Vector{Symbol},Symbol}} covary::Bool end -Cycle(cycle; covary = false) = Cycle(to_cycle(cycle), covary) +Cycle(cycle; covary=false) = Cycle(to_cycle(cycle), covary) to_cycle(single) = [to_cycle_single(single)] to_cycle(::Nothing) = [] to_cycle(symbolvec::Vector) = map(to_cycle_single, symbolvec) to_cycle_single(sym::Symbol) = [sym] => sym -to_cycle_single(pair::Pair{Symbol, Symbol}) = [pair[1]] => pair[2] -to_cycle_single(pair::Pair{Vector{Symbol}, Symbol}) = pair +to_cycle_single(pair::Pair{Symbol,Symbol}) = [pair[1]] => pair[2] +to_cycle_single(pair::Pair{Vector{Symbol},Symbol}) = pair """ Cycled(i::Int) @@ -51,7 +47,7 @@ struct LinearTicks if n_ideal <= 0 error("Ideal number of ticks can't be smaller than 0, but is $n_ideal") end - new(n_ideal) + return new(n_ideal) end end @@ -59,7 +55,7 @@ struct WilkinsonTicks k_ideal::Int k_min::Int k_max::Int - Q::Vector{Tuple{Float64, Float64}} + Q::Vector{Tuple{Float64,Float64}} granularity_weight::Float64 simplicity_weight::Float64 coverage_weight::Float64 @@ -82,7 +78,6 @@ struct MultiplesTicks suffix::String end - # """ # LogitTicks{T}(linear_ticks::T) @@ -113,17 +108,16 @@ struct IntervalsBetween mirror::Bool function IntervalsBetween(n::Int, mirror::Bool) n < 2 && error("You can't have $n intervals (must be at least 2 which means 1 minor tick)") - new(n, mirror) + return new(n, mirror) end end IntervalsBetween(n) = IntervalsBetween(n, true) - mutable struct LineAxis parent::Scene protrusion::Observable{Float32} attributes::Attributes - elements::Dict{Symbol, Any} + elements::Dict{Symbol,Any} tickpositions::Observable{Vector{Point2f}} tickvalues::Observable{Vector{Float32}} ticklabels::Observable{Vector{AbstractString}} @@ -138,42 +132,58 @@ mutable struct RectangleZoom active::Observable{Bool} restrict_x::Bool restrict_y::Bool - from::Union{Nothing, Point2f} - to::Union{Nothing, Point2f} + from::Union{Nothing,Point2f} + to::Union{Nothing,Point2f} rectnode::Observable{Rect2f} end function RectangleZoom(callback::Function; restrict_x=false, restrict_y=false) - return RectangleZoom(callback, Observable(false), restrict_x, restrict_y, - nothing, nothing, Observable(Rect2f(0, 0, 1, 1))) + return RectangleZoom( + callback, + Observable(false), + restrict_x, + restrict_y, + nothing, + nothing, + Observable(Rect2f(0, 0, 1, 1)), + ) end struct ScrollZoom speed::Float32 - reset_timer::RefValue{Union{Nothing, Timer}} - prev_xticklabelspace::RefValue{Union{Automatic, Float64}} - prev_yticklabelspace::RefValue{Union{Automatic, Float64}} + reset_timer::RefValue{Union{Nothing,Timer}} + prev_xticklabelspace::RefValue{Union{Automatic,Float64}} + prev_yticklabelspace::RefValue{Union{Automatic,Float64}} reset_delay::Float32 end function ScrollZoom(speed, reset_delay) - return ScrollZoom(speed, RefValue{Union{Nothing, Timer}}(nothing), RefValue{Union{Automatic, Float64}}(0.0), RefValue{Union{Automatic, Float64}}(0.0), reset_delay) + return ScrollZoom( + speed, + RefValue{Union{Nothing,Timer}}(nothing), + RefValue{Union{Automatic,Float64}}(0.0), + RefValue{Union{Automatic,Float64}}(0.0), + reset_delay, + ) end struct DragPan - reset_timer::RefValue{Union{Nothing, Timer}} - prev_xticklabelspace::RefValue{Union{Automatic, Float64}} - prev_yticklabelspace::RefValue{Union{Automatic, Float64}} + reset_timer::RefValue{Union{Nothing,Timer}} + prev_xticklabelspace::RefValue{Union{Automatic,Float64}} + prev_yticklabelspace::RefValue{Union{Automatic,Float64}} reset_delay::Float32 end function DragPan(reset_delay) - return DragPan(RefValue{Union{Nothing, Timer}}(nothing), RefValue{Union{Automatic, Float64}}(0.0), RefValue{Union{Automatic, Float64}}(0.0), reset_delay) + return DragPan( + RefValue{Union{Nothing,Timer}}(nothing), + RefValue{Union{Automatic,Float64}}(0.0), + RefValue{Union{Automatic,Float64}}(0.0), + reset_delay, + ) end - -struct DragRotate -end +struct DragRotate end struct ScrollEvent x::Float32 @@ -196,7 +206,7 @@ end mouseeventhandle::MouseEventHandle scrollevents::Observable{ScrollEvent} keysevents::Observable{KeysEvent} - interactions::Dict{Symbol, Tuple{Bool, Any}} + interactions::Dict{Symbol,Tuple{Bool,Any}} xaxis::LineAxis yaxis::LineAxis @attributes begin @@ -209,9 +219,9 @@ end "The font family of the title." titlefont = :bold "The title's font size." - titlesize::Float64 = @inherit(:fontsize, 16f0) + titlesize::Float64 = @inherit(:fontsize, 16.0f0) "The gap between axis and title." - titlegap::Float64 = 4f0 + titlegap::Float64 = 4.0f0 "Controls if the title is visible." titlevisible::Bool = true "The horizontal alignment of the title." @@ -225,7 +235,7 @@ end "The font family of the subtitle." subtitlefont = :regular "The subtitle's font size." - subtitlesize::Float64 = @inherit(:fontsize, 16f0) + subtitlesize::Float64 = @inherit(:fontsize, 16.0f0) "The gap between subtitle and title." subtitlegap::Float64 = 0 "Controls if the subtitle is visible." @@ -243,17 +253,17 @@ end "The color of the ylabel." ylabelcolor::RGBAf = @inherit(:textcolor, :black) "The font size of the xlabel." - xlabelsize::Float64 = @inherit(:fontsize, 16f0) + xlabelsize::Float64 = @inherit(:fontsize, 16.0f0) "The font size of the ylabel." - ylabelsize::Float64 = @inherit(:fontsize, 16f0) + ylabelsize::Float64 = @inherit(:fontsize, 16.0f0) "Controls if the xlabel is visible." xlabelvisible::Bool = true "Controls if the ylabel is visible." ylabelvisible::Bool = true "The padding between the xlabel and the ticks or axis." - xlabelpadding::Float64 = 3f0 + xlabelpadding::Float64 = 3.0f0 "The padding between the ylabel and the ticks or axis." - ylabelpadding::Float64 = 5f0 # xlabels usually have some more visual padding because of ascenders, which are larger than the hadvance gaps of ylabels + ylabelpadding::Float64 = 5.0f0 # xlabels usually have some more visual padding because of ascenders, which are larger than the hadvance gaps of ylabels "The xlabel rotation in radians." xlabelrotation = Makie.automatic "The ylabel rotation in radians." @@ -267,45 +277,45 @@ end "The color of yticklabels." yticklabelcolor::RGBAf = @inherit(:textcolor, :black) "The font size of the xticklabels." - xticklabelsize::Float64 = @inherit(:fontsize, 16f0) + xticklabelsize::Float64 = @inherit(:fontsize, 16.0f0) "The font size of the yticklabels." - yticklabelsize::Float64 = @inherit(:fontsize, 16f0) + yticklabelsize::Float64 = @inherit(:fontsize, 16.0f0) "Controls if the xticklabels are visible." xticklabelsvisible::Bool = true "Controls if the yticklabels are visible." yticklabelsvisible::Bool = true "The space reserved for the xticklabels." - xticklabelspace::Union{Makie.Automatic, Float64} = Makie.automatic + xticklabelspace::Union{Makie.Automatic,Float64} = Makie.automatic "The space reserved for the yticklabels." - yticklabelspace::Union{Makie.Automatic, Float64} = Makie.automatic + yticklabelspace::Union{Makie.Automatic,Float64} = Makie.automatic "The space between xticks and xticklabels." - xticklabelpad::Float64 = 2f0 + xticklabelpad::Float64 = 2.0f0 "The space between yticks and yticklabels." - yticklabelpad::Float64 = 4f0 + yticklabelpad::Float64 = 4.0f0 "The counterclockwise rotation of the xticklabels in radians." - xticklabelrotation::Float64 = 0f0 + xticklabelrotation::Float64 = 0.0f0 "The counterclockwise rotation of the yticklabels in radians." - yticklabelrotation::Float64 = 0f0 + yticklabelrotation::Float64 = 0.0f0 "The horizontal and vertical alignment of the xticklabels." - xticklabelalign::Union{Makie.Automatic, Tuple{Symbol, Symbol}} = Makie.automatic + xticklabelalign::Union{Makie.Automatic,Tuple{Symbol,Symbol}} = Makie.automatic "The horizontal and vertical alignment of the yticklabels." - yticklabelalign::Union{Makie.Automatic, Tuple{Symbol, Symbol}} = Makie.automatic + yticklabelalign::Union{Makie.Automatic,Tuple{Symbol,Symbol}} = Makie.automatic "The size of the xtick marks." - xticksize::Float64 = 6f0 + xticksize::Float64 = 6.0f0 "The size of the ytick marks." - yticksize::Float64 = 6f0 + yticksize::Float64 = 6.0f0 "Controls if the xtick marks are visible." xticksvisible::Bool = true "Controls if the ytick marks are visible." yticksvisible::Bool = true "The alignment of the xtick marks relative to the axis spine (0 = out, 1 = in)." - xtickalign::Float64 = 0f0 + xtickalign::Float64 = 0.0f0 "The alignment of the ytick marks relative to the axis spine (0 = out, 1 = in)." - ytickalign::Float64 = 0f0 + ytickalign::Float64 = 0.0f0 "The width of the xtick marks." - xtickwidth::Float64 = 1f0 + xtickwidth::Float64 = 1.0f0 "The width of the ytick marks." - ytickwidth::Float64 = 1f0 + ytickwidth::Float64 = 1.0f0 "The color of the xtick marks." xtickcolor::RGBAf = RGBf(0, 0, 0) "The color of the ytick marks." @@ -327,15 +337,15 @@ end "Controls if rectangle zooming affects the y dimension." yrectzoom::Bool = true "The width of the axis spines." - spinewidth::Float64 = 1f0 + spinewidth::Float64 = 1.0f0 "Controls if the x grid lines are visible." xgridvisible::Bool = true "Controls if the y grid lines are visible." ygridvisible::Bool = true "The width of the x grid lines." - xgridwidth::Float64 = 1f0 + xgridwidth::Float64 = 1.0f0 "The width of the y grid lines." - ygridwidth::Float64 = 1f0 + ygridwidth::Float64 = 1.0f0 "The color of the x grid lines." xgridcolor::RGBAf = RGBAf(0, 0, 0, 0.12) "The color of the y grid lines." @@ -349,9 +359,9 @@ end "Controls if the y minor grid lines are visible." yminorgridvisible::Bool = false "The width of the x minor grid lines." - xminorgridwidth::Float64 = 1f0 + xminorgridwidth::Float64 = 1.0f0 "The width of the y minor grid lines." - yminorgridwidth::Float64 = 1f0 + yminorgridwidth::Float64 = 1.0f0 "The color of the x minor grid lines." xminorgridcolor::RGBAf = RGBAf(0, 0, 0, 0.05) "The color of the y minor grid lines." @@ -391,9 +401,9 @@ end "Controls if the parent layout can adjust to this element's height" tellheight::Bool = true "The relative margins added to the autolimits in x direction." - xautolimitmargin::Tuple{Float64, Float64} = (0.05f0, 0.05f0) + xautolimitmargin::Tuple{Float64,Float64} = (0.05f0, 0.05f0) "The relative margins added to the autolimits in y direction." - yautolimitmargin::Tuple{Float64, Float64} = (0.05f0, 0.05f0) + yautolimitmargin::Tuple{Float64,Float64} = (0.05f0, 0.05f0) "The xticks." xticks = Makie.automatic "Format for xticks." @@ -417,9 +427,9 @@ end "The position of the y axis (`:left` or `:right`)." yaxisposition::Symbol = :left "Controls if the x spine is limited to the furthest tick marks or not." - xtrimspine::Union{Bool, Tuple{Bool,Bool}} = false + xtrimspine::Union{Bool,Tuple{Bool,Bool}} = false "Controls if the y spine is limited to the furthest tick marks or not." - ytrimspine::Union{Bool, Tuple{Bool,Bool}} = false + ytrimspine::Union{Bool,Tuple{Bool,Bool}} = false "The background color of the axis." backgroundcolor::RGBAf = :white "Controls if the ylabel's rotation is flipped." @@ -437,11 +447,11 @@ end "Controls if minor ticks on the x axis are visible" xminorticksvisible::Bool = false "The alignment of x minor ticks on the axis spine" - xminortickalign::Float64 = 0f0 + xminortickalign::Float64 = 0.0f0 "The tick size of x minor ticks" - xminorticksize::Float64 = 4f0 + xminorticksize::Float64 = 4.0f0 "The tick width of x minor ticks" - xminortickwidth::Float64 = 1f0 + xminortickwidth::Float64 = 1.0f0 "The tick color of x minor ticks" xminortickcolor::RGBAf = :black "The tick locator for the x minor ticks" @@ -449,11 +459,11 @@ end "Controls if minor ticks on the y axis are visible" yminorticksvisible::Bool = false "The alignment of y minor ticks on the axis spine" - yminortickalign::Float64 = 0f0 + yminortickalign::Float64 = 0.0f0 "The tick size of y minor ticks" - yminorticksize::Float64 = 4f0 + yminorticksize::Float64 = 4.0f0 "The tick width of y minor ticks" - yminortickwidth::Float64 = 1f0 + yminortickwidth::Float64 = 1.0f0 "The tick color of y minor ticks" yminortickcolor::RGBAf = :black "The tick locator for the y minor ticks" @@ -472,21 +482,28 @@ function RectangleZoom(f::Function, ax::Axis; kw...) faces = [1 2 5; 5 2 6; 2 3 6; 6 3 7; 3 4 7; 7 4 8; 4 1 8; 8 1 5] # plot to blockscene, so ax.scene stays exclusive for user plots # That's also why we need to pass `ax.scene` to _selection_vertices, so it can project to that space - mesh = mesh!(ax.blockscene, selection_vertices, faces, color = (:black, 0.2), shading = false, - inspectable = false, visible=r.active, transparency=true) + mesh = mesh!( + ax.blockscene, + selection_vertices, + faces, + color=(:black, 0.2), + shading=false, + inspectable=false, + visible=r.active, + transparency=true, + ) # translate forward so selection mesh and frame are never behind data translate!(mesh, 0, 0, 100) return r end -function RectangleZoom(ax::Axis; kw...) - return RectangleZoom(ax; kw...) do newlims +RectangleZoom(ax::Axis; kw...) = + RectangleZoom(ax; kw...) do newlims if !(0 in widths(newlims)) ax.targetlimits[] = newlims end return end -end @Block Colorbar begin axis::LineAxis @@ -498,23 +515,23 @@ end "The label font family." labelfont = :regular "The label font size." - labelsize = @inherit(:fontsize, 16f0) + labelsize = @inherit(:fontsize, 16.0f0) "Controls if the label is visible." labelvisible = true "The gap between the label and the ticks." - labelpadding = 5f0 + labelpadding = 5.0f0 "The label rotation in radians." labelrotation = Makie.automatic "The font family of the tick labels." ticklabelfont = :regular "The font size of the tick labels." - ticklabelsize = @inherit(:fontsize, 16f0) + ticklabelsize = @inherit(:fontsize, 16.0f0) "Controls if the tick labels are visible." ticklabelsvisible = true "The color of the tick labels." ticklabelcolor = @inherit(:textcolor, :black) "The size of the tick marks." - ticksize = 6f0 + ticksize = 6.0f0 "Controls if the tick marks are visible." ticksvisible = true "The ticks." @@ -524,19 +541,19 @@ end "The space reserved for the tick labels." ticklabelspace = Makie.automatic "The gap between tick labels and tick marks." - ticklabelpad = 3f0 + ticklabelpad = 3.0f0 "The alignment of the tick marks relative to the axis spine (0 = out, 1 = in)." - tickalign = 0f0 + tickalign = 0.0f0 "The line width of the tick marks." - tickwidth = 1f0 + tickwidth = 1.0f0 "The color of the tick marks." tickcolor = RGBf(0, 0, 0) "The horizontal and vertical alignment of the tick labels." ticklabelalign = Makie.automatic "The rotation of the ticklabels." - ticklabelrotation = 0f0 + ticklabelrotation = 0.0f0 "The line width of the spines." - spinewidth = 1f0 + spinewidth = 1.0f0 "Controls if the top spine is visible." topspinevisible = true "Controls if the right spine is visible." @@ -588,11 +605,11 @@ end "Controls if minor ticks are visible" minorticksvisible = false "The alignment of minor ticks on the axis spine" - minortickalign = 0f0 + minortickalign = 0.0f0 "The tick size of minor ticks" - minorticksize = 4f0 + minorticksize = 4.0f0 "The tick width of minor ticks" - minortickwidth = 1f0 + minortickwidth = 1.0f0 "The tick color of minor ticks" minortickcolor = :black "The tick locator for the minor ticks" @@ -613,7 +630,7 @@ end "The color of the text." color::RGBAf = @inherit(:textcolor, :black) "The font size of the text." - fontsize::Float32 = @inherit(:fontsize, 16f0) + fontsize::Float32 = @inherit(:fontsize, 16.0f0) "The font family of the text." font = :regular "The justification of the text (:left, :right, :center)." @@ -625,9 +642,9 @@ end "The horizontal alignment of the text in its suggested boundingbox" halign = :center "The counterclockwise rotation of the text in radians." - rotation::Float32 = 0f0 + rotation::Float32 = 0.0f0 "The extra space added to the sides of the text boundingbox." - padding = (0f0, 0f0, 0f0, 0f0) + padding = (0.0f0, 0.0f0, 0.0f0, 0.0f0) "The height setting of the text." height = Auto() "The width setting of the text." @@ -654,9 +671,9 @@ end "The horizontal alignment of the rectangle in its suggested boundingbox" halign = :center "The extra space added to the sides of the rectangle boundingbox." - padding = (0f0, 0f0, 0f0, 0f0) + padding = (0.0f0, 0.0f0, 0.0f0, 0.0f0) "The line width of the rectangle's border." - strokewidth = 1f0 + strokewidth = 1.0f0 "Controls if the border of the rectangle is visible." strokevisible = true "The color of the border." @@ -738,8 +755,8 @@ end end @Block IntervalSlider begin - selected_indices::Observable{Tuple{Int, Int}} - displayed_sliderfractions::Observable{Tuple{Float64, Float64}} + selected_indices::Observable{Tuple{Int,Int}} + displayed_sliderfractions::Observable{Tuple{Float64,Float64}} @attributes begin "The horizontal alignment of the slider in its suggested bounding box." halign = :center @@ -783,9 +800,9 @@ end "The vertical alignment of the button in its suggested boundingbox" valign = :center "The extra space added to the sides of the button label's boundingbox." - padding = (10f0, 10f0, 10f0, 10f0) + padding = (10.0f0, 10.0f0, 10.0f0, 10.0f0) "The font size of the button label." - fontsize = @inherit(:fontsize, 16f0) + fontsize = @inherit(:fontsize, 16.0f0) "The text of the button label." label = "Button" "The font family of the button label." @@ -803,7 +820,7 @@ end "The number of poly segments used for each rounded corner." cornersegments = 10 "The line width of the button border." - strokewidth = 2f0 + strokewidth = 2.0f0 "The color of the button border." strokecolor = :transparent "The color of the button." @@ -900,7 +917,7 @@ end "The list of options selectable in the menu. This can be any iterable of a mixture of strings and containers with one string and one other value. If an entry is just a string, that string is both label and selection. If an entry is a container with one string and one other value, the string is the label and the other value is the selection." options = ["no options"] "Font size of the cell texts" - fontsize = @inherit(:fontsize, 16f0) + fontsize = @inherit(:fontsize, 16.0f0) "Padding of entry texts" textpadding = (10, 10, 10, 10) "Color of entry texts" @@ -912,7 +929,6 @@ end end end - abstract type LegendElement end struct LineElement <: LegendElement @@ -932,7 +948,7 @@ struct LegendEntry attributes::Attributes end -const EntryGroup = Tuple{Optional{<:AbstractString}, Vector{LegendEntry}} +const EntryGroup = Tuple{Optional{<:AbstractString},Vector{LegendEntry}} @Block Legend begin entrygroups::Observable{Vector{EntryGroup}} @@ -955,7 +971,7 @@ const EntryGroup = Tuple{Optional{<:AbstractString}, Vector{LegendEntry}} "The font family of the legend group titles." titlefont = :bold "The font size of the legend group titles." - titlesize = @inherit(:fontsize, 16f0) + titlesize = @inherit(:fontsize, 16.0f0) "The horizontal alignment of the legend group titles." titlehalign = :center "The vertical alignment of the legend group titles." @@ -967,7 +983,7 @@ const EntryGroup = Tuple{Optional{<:AbstractString}, Vector{LegendEntry}} "The group title positions relative to their groups. Can be `:top` or `:left`." titleposition = :top "The font size of the entry labels." - labelsize = @inherit(:fontsize, 16f0) + labelsize = @inherit(:fontsize, 16.0f0) "The font family of the entry labels." labelfont = :regular "The color of the entry labels." @@ -979,23 +995,23 @@ const EntryGroup = Tuple{Optional{<:AbstractString}, Vector{LegendEntry}} "The vertical alignment of the entry labels." labelvalign = :center "The additional space between the legend content and the border." - padding = (10f0, 10f0, 8f0, 8f0) + padding = (10.0f0, 10.0f0, 8.0f0, 8.0f0) "The additional space between the legend and its suggested boundingbox." - margin = (0f0, 0f0, 0f0, 0f0) + margin = (0.0f0, 0.0f0, 0.0f0, 0.0f0) "The background color of the legend." bgcolor = :white "The color of the legend border." framecolor = :black "The line width of the legend border." - framewidth = 1f0 + framewidth = 1.0f0 "Controls if the legend border is visible." framevisible = true "The size of the rectangles containing the legend markers." - patchsize = (20f0, 20f0) + patchsize = (20.0f0, 20.0f0) "The color of the border of the patches containing the legend markers." patchstrokecolor = :transparent "The line width of the border of the patches containing the legend markers." - patchstrokewidth = 1f0 + patchstrokewidth = 1.0f0 "The color of the patches containing the legend markers." patchcolor = :transparent "The default entry label." @@ -1102,7 +1118,7 @@ end "Controls if the textbox is defocused when a string is submitted." defocus_on_submit = true "Text size." - fontsize = @inherit(:fontsize, 16f0) + fontsize = @inherit(:fontsize, 16.0f0) "Text color." textcolor = @inherit(:textcolor, :black) "Text color for the placeholder." @@ -1126,7 +1142,7 @@ end "Color of the box border when focused and invalid." bordercolor_focused_invalid = RGBf(1, 0, 0) "Width of the box border." - borderwidth = 2f0 + borderwidth = 2.0f0 "Padding of the text against the box." textpadding = (10, 10, 10, 10) "If the textbox is focused and receives text input." @@ -1150,7 +1166,7 @@ end mouseeventhandle::MouseEventHandle scrollevents::Observable{ScrollEvent} keysevents::Observable{KeysEvent} - interactions::Dict{Symbol, Tuple{Bool, Any}} + interactions::Dict{Symbol,Tuple{Bool,Any}} cycler::Cycler palette::Attributes @attributes begin @@ -1169,13 +1185,13 @@ end "The alignment of the scene in its suggested bounding box." alignmode = Inside() "The elevation angle of the camera" - elevation = pi/8 + elevation = pi / 8 "The azimuth angle of the camera" azimuth = 1.275 * pi "A number between 0 and 1, where 0 is orthographic, and 1 full perspective" - perspectiveness = 0f0 + perspectiveness = 0.0f0 "Aspects of the 3 axes with each other" - aspect = (1.0, 1.0, 2/3) # :data :equal + aspect = (1.0, 1.0, 2 / 3) # :data :equal "The view mode which affects the final projection. `:fit` results in the projection that always fits the limits into the viewport, invariant to rotation. `:fitzoom` keeps the x/y ratio intact but stretches the view so the corners touch the scene viewport. `:stretch` scales separately in both x and y direction to fill the viewport, which can distort the `aspect` that is set." viewmode = :fitzoom # :fit :fitzoom :stretch "The background color" @@ -1211,11 +1227,11 @@ end "Controls if the z ticks are visible" zticksvisible = true "The x label size" - xlabelsize = @inherit(:fontsize, 16f0) + xlabelsize = @inherit(:fontsize, 16.0f0) "The y label size" - ylabelsize = @inherit(:fontsize, 16f0) + ylabelsize = @inherit(:fontsize, 16.0f0) "The z label size" - zlabelsize = @inherit(:fontsize, 16f0) + zlabelsize = @inherit(:fontsize, 16.0f0) "The x label font" xlabelfont = :regular "The y label font" @@ -1247,11 +1263,11 @@ end "The z ticklabel color" zticklabelcolor = @inherit(:textcolor, :black) "The x ticklabel size" - xticklabelsize = @inherit(:fontsize, 16f0) + xticklabelsize = @inherit(:fontsize, 16.0f0) "The y ticklabel size" - yticklabelsize = @inherit(:fontsize, 16f0) + yticklabelsize = @inherit(:fontsize, 16.0f0) "The z ticklabel size" - zticklabelsize = @inherit(:fontsize, 16f0) + zticklabelsize = @inherit(:fontsize, 16.0f0) "The x ticklabel pad" xticklabelpad = 5 "The y ticklabel pad" @@ -1327,11 +1343,11 @@ end "The protrusions on the sides of the axis, how much gap space is reserved for labels etc." protrusions = 30 "The x ticks" - xticks = WilkinsonTicks(5; k_min = 3) + xticks = WilkinsonTicks(5; k_min=3) "The y ticks" - yticks = WilkinsonTicks(5; k_min = 3) + yticks = WilkinsonTicks(5; k_min=3) "The z ticks" - zticks = WilkinsonTicks(5; k_min = 3) + zticks = WilkinsonTicks(5; k_min=3) "The x tick format" xtickformat = Makie.automatic "The y tick format" @@ -1343,9 +1359,9 @@ end "The font family of the title." titlefont = :bold "The title's font size." - titlesize = @inherit(:fontsize, 16f0) + titlesize = @inherit(:fontsize, 16.0f0) "The gap between axis and title." - titlegap = 4f0 + titlegap = 4.0f0 "Controls if the title is visible." titlevisible = true "The horizontal alignment of the title." diff --git a/src/patterns.jl b/src/patterns.jl index 88f834a01d7..1c13221969e 100644 --- a/src/patterns.jl +++ b/src/patterns.jl @@ -6,16 +6,12 @@ plottable objects. There are currently two subtypes: `LinePattern` and `ImagePattern`. Any abstract pattern must implement the `to_image(pat)` function, which must return a `Matrix{<: AbstractRGB}`. """ -abstract type AbstractPattern{T} <: AbstractArray{T, 2} end +abstract type AbstractPattern{T} <: AbstractArray{T,2} end # for print_array because we defined it as <: Base.AbstractArray -function Base.show(io::IO, p::AbstractPattern) - print(io, typeof(p)) -end +Base.show(io::IO, p::AbstractPattern) = print(io, typeof(p)) -function Base.show(io::IO, ::MIME"text/plain", p::AbstractPattern) - print(io, typeof(p)) -end +Base.show(io::IO, ::MIME"text/plain", p::AbstractPattern) = print(io, typeof(p)) struct ImagePattern <: AbstractPattern{RGBAf} img::Matrix{RGBAf} @@ -32,10 +28,10 @@ Creates an `ImagePattern` from an `image` (a matrix of colors) or a `mask` texture it. If a `mask` is passed, one can specify to colors between which colors are interpolated. """ -Pattern(img::Array{<: Colorant, 2}) = ImagePattern(img) +Pattern(img::Array{<:Colorant,2}) = ImagePattern(img) -function Pattern(mask::Matrix{<: Real}; color1=RGBAf(0,0,0,1), color2=RGBAf(1,1,1,0)) - img = map(x -> to_color(color1) * x + to_color(color2) * (1-x), mask) +function Pattern(mask::Matrix{<:Real}; color1=RGBAf(0, 0, 0, 1), color2=RGBAf(1, 1, 1, 0)) + img = map(x -> to_color(color1) * x + to_color(color2) * (1 - x), mask) return ImagePattern(img) end @@ -46,13 +42,12 @@ struct LinePattern <: AbstractPattern{RGBAf} widths::Vector{Float32} shifts::Vector{Vec2f} - tilesize::NTuple{2, Int} - colors::NTuple{2, RGBAf} + tilesize::NTuple{2,Int} + colors::NTuple{2,RGBAf} end Base.size(pattern::LinePattern) = pattern.tilesize - """ LinePattern([; kwargs...]) @@ -69,10 +64,13 @@ Multiple `direction`s, `width`s and `shift`s can also be given to create more complex patterns, e.g. a cross-hatching pattern. """ function LinePattern(; - direction = Vec2f(1), width = 2f0, tilesize = (10,10), - shift = map(w -> Vec2f(0.5 - 0.5(w%2)), width), - linecolor = RGBAf(0,0,0,1), background_color = RGBAf(1,1,1,0) - ) + direction=Vec2f(1), + width=2.0f0, + tilesize=(10, 10), + shift=map(w -> Vec2f(0.5 - 0.5(w % 2)), width), + linecolor=RGBAf(0, 0, 0, 1), + background_color=RGBAf(1, 1, 1, 0), +) N = 1 direction isa Vector{<:Vec2} && (N = length(direction)) width isa Vector && (length(width) > N) && (N = length(width)) @@ -95,7 +93,7 @@ Creates a line pattern based on the given argument. Available patterns are to the keyword arguments for [`LinePattern`](@ref). """ Pattern(style::String; kwargs...) = Pattern(style[1]; kwargs...) -function Pattern(style::Char = '/'; kwargs...) +Pattern(style::Char='/'; kwargs...) = if style == '/' LinePattern(direction=Vec2f(1); kwargs...) elseif style == '\\' @@ -111,7 +109,6 @@ function Pattern(style::Char = '/'; kwargs...) else LinePattern(; kwargs...) end -end function to_image(p::LinePattern) tilesize = p.tilesize @@ -123,31 +120,31 @@ function to_image(p::LinePattern) # m = dx / dy; x = m * (y-1) + 1 m = dir[1] / dir[2] for y in 1:tilesize[2] - cx = m * (y-shift[2]) + shift[1] - r = floor(Int64, cx-0.5width):ceil(Int64, cx+0.5width) - for x in r[2:end-1] + cx = m * (y - shift[2]) + shift[1] + r = floor(Int64, cx - 0.5width):ceil(Int64, cx + 0.5width) + for x in r[2:(end - 1)] mask[mod1(x, tilesize[1]), y] = 1.0 end - mask[mod1(r[1], tilesize[1]), y] = 1 - abs(cx-0.5width - r[1]) - mask[mod1(r[end], tilesize[1]), y] = 1 - abs(cx+0.5width - r[end]) + mask[mod1(r[1], tilesize[1]), y] = 1 - abs(cx - 0.5width - r[1]) + mask[mod1(r[end], tilesize[1]), y] = 1 - abs(cx + 0.5width - r[end]) end else # m = dy / dx; y = m * (x-1) + 1 m = dir[2] / dir[1] for x in 1:tilesize[1] - cy = m * (x-shift[1]) + shift[2] - r = floor(Int64, cy-0.5width):ceil(Int64, cy+0.5width) - for y in r[2:end-1] + cy = m * (x - shift[1]) + shift[2] + r = floor(Int64, cy - 0.5width):ceil(Int64, cy + 0.5width) + for y in r[2:(end - 1)] mask[x, mod1(y, tilesize[2])] = 1.0 end - mask[x, mod1(r[1], tilesize[2])] = 1 - abs(cy-0.5width - r[1]) - mask[x, mod1(r[end], tilesize[2])] = 1 - abs(cy+0.5width - r[end]) + mask[x, mod1(r[1], tilesize[2])] = 1 - abs(cy - 0.5width - r[1]) + mask[x, mod1(r[end], tilesize[2])] = 1 - abs(cy + 0.5width - r[end]) end end full_mask .+= mask end return map(full_mask) do x - return convert(RGBAf, p.colors[1] * clamp(x, 0, 1) + p.colors[2] * (1-clamp(x, 0, 1))) + return convert(RGBAf, p.colors[1] * clamp(x, 0, 1) + p.colors[2] * (1 - clamp(x, 0, 1))) end end diff --git a/src/recording.jl b/src/recording.jl index 449f04b9d98..480191ca6a3 100644 --- a/src/recording.jl +++ b/src/recording.jl @@ -26,14 +26,44 @@ mutable struct RamStepper format::Symbol end -function Stepper(figlike::FigureLike; backend=current_backend(), format=:png, visible=false, connect=false, srceen_kw...) - screen = getscreen(backend, get_scene(figlike), JuliaNative; visible=visible, start_renderloop=false, srceen_kw...) +function Stepper( + figlike::FigureLike; + backend=current_backend(), + format=:png, + visible=false, + connect=false, + srceen_kw..., +) + screen = getscreen( + backend, + get_scene(figlike), + JuliaNative; + visible=visible, + start_renderloop=false, + srceen_kw..., + ) display(screen, figlike; connect=connect) return RamStepper(figlike, screen, Matrix{RGBf}[], format) end -function Stepper(figlike::FigureLike, path::String, step::Int; format=:png, backend=current_backend(), visible=false, connect=false, screen_config...) - screen = getscreen(backend, get_scene(figlike), JuliaNative; visible=visible, start_renderloop=false, srceen_kw...) +function Stepper( + figlike::FigureLike, + path::String, + step::Int; + format=:png, + backend=current_backend(), + visible=false, + connect=false, + screen_config..., +) + screen = getscreen( + backend, + get_scene(figlike), + JuliaNative; + visible=visible, + start_renderloop=false, + srceen_kw..., + ) display(screen, figlike; connect=connect) return FolderStepper(figlike, screen, path, format, step) end @@ -140,16 +170,15 @@ end function record(func, figlike::FigureLike, path::AbstractString; kw_args...) format = lstrip(splitext(path)[2], '.') io = Record(func, figlike; format=format, kw_args...) - save(path, io) + return save(path, io) end function record(func, figlike::FigureLike, path::AbstractString, iter; kw_args...) format = lstrip(splitext(path)[2], '.') io = Record(func, figlike, iter; format=format, kw_args...) - save(path, io) + return save(path, io) end - """ Record(func, figlike, [iter]; kw_args...) @@ -166,7 +195,7 @@ function Record(func, figlike, iter; kw_args...) for i in iter func(i) recordframe!(io) - @debug "Recording" progress=i/length(iter) + @debug "Recording" progress = i / length(iter) yield() end return io @@ -175,11 +204,11 @@ end function Base.show(io::IO, ::MIME"text/html", vs::VideoStream) mktempdir() do dir path = save(joinpath(dir, "video.mp4"), vs) - print( + return print( io, """""" + """" type="video/mp4">""", ) end end diff --git a/src/scenes.jl b/src/scenes.jl index 29633cf39d5..df59e645600 100644 --- a/src/scenes.jl +++ b/src/scenes.jl @@ -26,7 +26,7 @@ function Base.show(io::IO, ssao::SSAO) println(io, "SSAO:") println(io, " radius: ", ssao.radius[]) println(io, " bias: ", ssao.bias[]) - println(io, " blur: ", ssao.blur[]) + return println(io, " blur: ", ssao.blur[]) end function SSAO(; radius=nothing, bias=nothing, blur=nothing) @@ -75,7 +75,7 @@ $(FIELDS) """ mutable struct Scene <: AbstractScene "The parent of the Scene; if it is a top-level Scene, `parent == nothing`." - parent::Union{Nothing, Scene} + parent::Union{Nothing,Scene} "[`Events`](@ref) associated with the Scene." events::Events @@ -113,7 +113,6 @@ mutable struct Scene <: AbstractScene visible::Observable{Bool} ssao::SSAO lights::Vector{AbstractLight} - end get_scene(scene::Scene) = scene @@ -138,29 +137,32 @@ function Base.show(io::IO, scene::Scene) print(io, ":") for (i, subscene) in enumerate(scene.children) print(io, "\n") - print(io," $(i == length(scene.children) ? '└' : '├') Scene ($(size(subscene, 1))px, $(size(subscene, 2))px)") + print( + io, + " $(i == length(scene.children) ? '└' : '├') Scene ($(size(subscene, 1))px, $(size(subscene, 2))px)", + ) end end end function Scene(; - px_area::Union{Observable{Rect2i}, Nothing} = nothing, - events::Events = Events(), - clear::Bool = true, - transform_func=identity, - camera::Union{Function, Camera, Nothing} = nothing, - camera_controls::AbstractCamera = EmptyCamera(), - transformation::Transformation = Transformation(transform_func), - plots::Vector{AbstractPlot} = AbstractPlot[], - theme::Attributes = Attributes(), - children::Vector{Scene} = Scene[], - current_screens::Vector{MakieScreen} = MakieScreen[], - parent = nothing, - visible = Observable(true), - ssao = SSAO(), - lights = automatic, - theme_kw... - ) + px_area::Union{Observable{Rect2i},Nothing}=nothing, + events::Events=Events(), + clear::Bool=true, + transform_func=identity, + camera::Union{Function,Camera,Nothing}=nothing, + camera_controls::AbstractCamera=EmptyCamera(), + transformation::Transformation=Transformation(transform_func), + plots::Vector{AbstractPlot}=AbstractPlot[], + theme::Attributes=Attributes(), + children::Vector{Scene}=Scene[], + current_screens::Vector{MakieScreen}=MakieScreen[], + parent=nothing, + visible=Observable(true), + ssao=SSAO(), + lights=automatic, + theme_kw..., +) m_theme = current_default_theme(; theme..., theme_kw...) bg = map(to_color, m_theme.backgroundcolor) @@ -168,13 +170,13 @@ function Scene(; wasnothing = isnothing(px_area) if wasnothing px_area = lift(m_theme.resolution) do res - Recti(0, 0, res) + return Recti(0, 0, res) end end cam = camera isa Camera ? camera : Camera(px_area) if wasnothing - on(events.window_area, priority = typemax(Int)) do w_area + on(events.window_area, priority=typemax(Int)) do w_area if !any(x -> x ≈ 0.0, widths(w_area)) && px_area[] != w_area px_area[] = w_area end @@ -185,9 +187,21 @@ function Scene(; _lights = lights isa Automatic ? AbstractLight[] : lights scene = Scene( - parent, events, px_area, clear, cam, camera_controls, - transformation, plots, m_theme, - children, current_screens, bg, visible, ssao, _lights + parent, + events, + px_area, + clear, + cam, + camera_controls, + transformation, + plots, + m_theme, + children, + current_screens, + bg, + visible, + ssao, + _lights, ) if camera isa Function cam = camera(scene) @@ -213,7 +227,7 @@ function Scene(; end function get_one_light(scene::Scene, Typ) - indices = findall(x-> x isa Typ, scene.lights) + indices = findall(x -> x isa Typ, scene.lights) isempty(indices) && return nothing if length(indices) > 1 @warn("Only one light supported by backend right now. Using only first light") @@ -224,19 +238,18 @@ end get_point_light(scene::Scene) = get_one_light(scene, PointLight) get_ambient_light(scene::Scene) = get_one_light(scene, AmbientLight) - function Scene( - parent::Scene; - events=parent.events, - px_area=nothing, - clear=false, - camera=nothing, - camera_controls=parent.camera_controls, - transformation=Transformation(parent), - theme=theme(parent), - current_screens=parent.current_screens, - kw... - ) + parent::Scene; + events=parent.events, + px_area=nothing, + clear=false, + camera=nothing, + camera_controls=parent.camera_controls, + transformation=Transformation(parent), + theme=theme(parent), + current_screens=parent.current_screens, + kw..., +) if isnothing(px_area) px_area = lift(zero_origin, parent.px_area; ignore_equal_values=true) else @@ -259,7 +272,7 @@ function Scene( transformation=transformation, theme=theme, current_screens=current_screens, - kw... + kw..., ) push!(parent.children, child) child.parent = parent @@ -267,9 +280,7 @@ function Scene( end # legacy constructor -function Scene(parent::Scene, area; kw...) - return Scene(parent; px_area=area, kw...) -end +Scene(parent::Scene, area; kw...) = Scene(parent; px_area=area, kw...) # Base overloads for Scene Base.parent(scene::Scene) = scene.parent @@ -281,7 +292,7 @@ function root(scene::Scene) while !isroot(scene) scene = parent(scene) end - scene + return scene end parent_or_self(scene::Scene) = isroot(scene) ? scene : parent(scene) @@ -289,13 +300,9 @@ GeometryBasics.widths(scene::Scene) = widths(to_value(pixelarea(scene))) Base.size(scene::Scene) = Tuple(widths(scene)) Base.size(x::Scene, i) = size(x)[i] -function Base.resize!(scene::Scene, xy::Tuple{Number,Number}) - resize!(scene, Recti(0, 0, xy)) -end +Base.resize!(scene::Scene, xy::Tuple{Number,Number}) = resize!(scene, Recti(0, 0, xy)) Base.resize!(scene::Scene, x::Number, y::Number) = resize!(scene, (x, y)) -function Base.resize!(scene::Scene, rect::Rect2) - pixelarea(scene)[] = rect -end +Base.resize!(scene::Scene, rect::Rect2) = pixelarea(scene)[] = rect """ getscreen(scene::Scene) @@ -330,17 +337,11 @@ end """ Creates a subscene with a pixel camera """ -function cam2d(scene::Scene) - return child(scene, clear=false, camera=cam2d!) -end +cam2d(scene::Scene) = child(scene, clear=false, camera=cam2d!) -function campixel(scene::Scene) - return child(scene, clear=false, camera=campixel!) -end +campixel(scene::Scene) = child(scene, clear=false, camera=campixel!) -function camrelative(scene::Scene) - return child(scene, clear=false, camera=cam_relative!) -end +camrelative(scene::Scene) = child(scene, clear=false, camera=cam_relative!) function getindex(scene::Scene, ::Type{OldAxis}) for plot in scene @@ -479,7 +480,7 @@ function plots_from_camera(scene::Scene, camera::Camera, list=AbstractPlot[]) for child in scene.children child.camera == camera && plots_from_camera(child, camera, list) end - list + return list end """ @@ -493,31 +494,29 @@ function flatten_combined(plots::Vector, flat=AbstractPlot[]) push!(flat, elem) end end - flat + return flat end function insertplots!(screen::AbstractDisplay, scene::Scene) for elem in scene.plots insert!(screen, scene, elem) end - foreach(child -> insertplots!(screen, child), scene.children) + return foreach(child -> insertplots!(screen, child), scene.children) end update_cam!(x, bb::AbstractCamera, rect) = update_cam!(get_scene(x), bb, rect) update_cam!(scene::Scene, bb::AbstractCamera, rect) = nothing -function not_in_data_space(p) - !is_data_space(to_value(get(p, :space, :data))) -end +not_in_data_space(p) = !is_data_space(to_value(get(p, :space, :data))) -function center!(scene::Scene, padding=0.01, exclude = not_in_data_space) +function center!(scene::Scene, padding=0.01, exclude=not_in_data_space) bb = boundingbox(scene, exclude) bb = transformationmatrix(scene)[] * bb w = widths(bb) padd = w .* padding bb = Rect3f(minimum(bb) .- padd, w .+ 2padd) update_cam!(scene, bb) - scene + return scene end parent_scene(x) = parent_scene(get_scene(x)) @@ -548,14 +547,14 @@ struct Figure function Figure(args...) f = new(args...) current_figure!(f) - f + return f end end struct FigureAxisPlot figure::Figure - axis + axis::Any plot::AbstractPlot end -const FigureLike = Union{Scene, Figure, FigureAxisPlot} +const FigureLike = Union{Scene,Figure,FigureAxisPlot} diff --git a/src/shorthands.jl b/src/shorthands.jl index 31fded1dfe9..73012e245b0 100644 --- a/src/shorthands.jl +++ b/src/shorthands.jl @@ -1,5 +1,4 @@ - function xlims! end function ylims! end function zlims! end @@ -14,7 +13,7 @@ function xlabel!(scene, xlabel::AbstractString) axis = scene[OldAxis] @assert !isnothing(axis) "The Scene does not have an axis!" scene[OldAxis][:names][:axisnames][] = (xlabel, scene[OldAxis][:names][:axisnames][][2:end]...) - nothing + return nothing end """ @@ -27,11 +26,12 @@ function ylabel!(scene, ylabel::AbstractString) axis = scene[OldAxis] @assert !isnothing(axis) "The Scene does not have an axis!" if axis isa Axis3D - scene[OldAxis][:names][:axisnames][] = (scene[OldAxis][:names][:axisnames][][1], ylabel, scene[OldAxis][:names][:axisnames][][3]) + scene[OldAxis][:names][:axisnames][] = + (scene[OldAxis][:names][:axisnames][][1], ylabel, scene[OldAxis][:names][:axisnames][][3]) else @error("Unknown axis type $(typeof(axis)).") end - nothing + return nothing end """ @@ -46,7 +46,8 @@ function zlabel!(scene, zlabel::AbstractString) axis = scene[OldAxis] @assert !isnothing(axis) "The Scene does not have an axis!" @assert axis isa Axis3D "The scene does not have a z-axis" - scene[OldAxis][:names][:axisnames][] = (scene[OldAxis][:names][:axisnames][][1], scene[OldAxis][:names][:axisnames][][2], zlabel) + scene[OldAxis][:names][:axisnames][] = + (scene[OldAxis][:names][:axisnames][][1], scene[OldAxis][:names][:axisnames][][2], zlabel) return end @@ -82,8 +83,8 @@ yticklabels(scene) = ticklabels(scene)[2] Returns the all the z-axis tick labels. See also `ticklabels`. """ function zticklabels(scene) - @assert !is2d(scene) "The Scene does not have a z-axis!" - ticklabels(scene)[3] + @assert !is2d(scene) "The Scene does not have a z-axis!" + return ticklabels(scene)[3] end """ @@ -94,7 +95,7 @@ Returns the tick ranges along all axes. function tickranges(scene) axis = scene[OldAxis] @assert !isnothing(axis) "The Scene does not have an axis!" - scene[OldAxis].ticks.ranges_labels[][1] + return scene[OldAxis].ticks.ranges_labels[][1] end """ @@ -117,7 +118,7 @@ ytickrange(scene) = tickranges(scene)[2] Returns the tick range along the z-axis. See also `tickranges`. """ function ztickrange(scene) - @assert !is2d(scene) "The Scene does not have a z-axis!" + @assert !is2d(scene) "The Scene does not have a z-axis!" return tickranges(scene)[3] end @@ -144,7 +145,11 @@ end Set the tick labels and range along the x-axes. See also `ticks!`. """ function xticks!(scene::Scene; xtickrange=xtickrange(scene), xticklabels=xticklabels(scene)) - ticks!(scene, tickranges=(xtickrange, tickranges(scene)[2:end]...), ticklabels=(xticklabels, ticklabels(scene)[2:end]...)) + ticks!( + scene, + tickranges=(xtickrange, tickranges(scene)[2:end]...), + ticklabels=(xticklabels, ticklabels(scene)[2:end]...), + ) return nothing end @@ -159,7 +164,7 @@ function yticks!(scene::Scene; ytickrange=ytickrange(scene), yticklabels=ytickla if length(r) == 2 ticks!(scene, tickranges=(first(r), ytickrange), ticklabels=(first(l), yticklabels)) else # length(r) == 3 - ticks!(scene, tickranges=(first(r), ytickrange, last(r)), ticklabels =(first(l), yticklabels, last(l))) + ticks!(scene, tickranges=(first(r), ytickrange, last(r)), ticklabels=(first(l), yticklabels, last(l))) end return nothing end @@ -170,8 +175,12 @@ end Set the tick labels and range along all z-axis. See also `ticks!`. """ function zticks!(scene::Scene; ztickrange=ztickrange(scene), zticklabels=zticklabels(scene)) - @assert !is2d(scene) "The Scene does not have a z-axis!" - ticks!(scene, tickranges=(tickranges(scene)[1:2]..., ztickrange), ticklabels=(ticklabels(scene)[1:2]..., zticklabels)) + @assert !is2d(scene) "The Scene does not have a z-axis!" + ticks!( + scene, + tickranges=(tickranges(scene)[1:2]..., ztickrange), + ticklabels=(ticklabels(scene)[1:2]..., zticklabels), + ) return nothing end @@ -209,7 +218,7 @@ ytickrotation(scene) = tickrotations(scene)[2] Returns the rotation of tick labels along the z-axis. See also `tickrotations` """ function ztickrotation(scene) - @assert !is2d(scene) "The Scene does not have a z-axis!" + @assert !is2d(scene) "The Scene does not have a z-axis!" return tickrotations(scene)[3] end @@ -254,7 +263,7 @@ end Set the rotation of tick labels along the z-axis. See also `tickrotations!`. """ function ztickrotation!(scene::Scene, zangle) - @assert !is2d(scene) "The Scene does not have a z-axis!" + @assert !is2d(scene) "The Scene does not have a z-axis!" tickrotations!(scene, (tickrotations(scene)[1:2]..., zangle)) return nothing end diff --git a/src/stats/boxplot.jl b/src/stats/boxplot.jl index 7ec7fb4f5ae..a0a86eaa0ec 100644 --- a/src/stats/boxplot.jl +++ b/src/stats/boxplot.jl @@ -32,41 +32,41 @@ The boxplot has 3 components: - `dodge_gap = 0.03`: spacing between dodged boxes """ @recipe(BoxPlot, x, y) do scene - Theme( - weights = automatic, - color = theme(scene, :patchcolor), - colormap = theme(scene, :colormap), - colorrange = automatic, - orientation = :vertical, + return Theme( + weights=automatic, + color=theme(scene, :patchcolor), + colormap=theme(scene, :colormap), + colorrange=automatic, + orientation=:vertical, # box and dodging - width = automatic, - dodge = automatic, - n_dodge = automatic, - gap = 0.2, - dodge_gap = 0.03, - strokecolor = theme(scene, :patchstrokecolor), - strokewidth = theme(scene, :patchstrokewidth), + width=automatic, + dodge=automatic, + n_dodge=automatic, + gap=0.2, + dodge_gap=0.03, + strokecolor=theme(scene, :patchstrokecolor), + strokewidth=theme(scene, :patchstrokewidth), # notch - show_notch = false, - notchwidth = 0.5, + show_notch=false, + notchwidth=0.5, # median line - show_median = true, - mediancolor = theme(scene, :linecolor), - medianlinewidth = theme(scene, :linewidth), + show_median=true, + mediancolor=theme(scene, :linecolor), + medianlinewidth=theme(scene, :linewidth), # whiskers - range = 1.5, - whiskerwidth = 0.0, - whiskercolor = theme(scene, :linecolor), - whiskerlinewidth = theme(scene, :linewidth), + range=1.5, + whiskerwidth=0.0, + whiskercolor=theme(scene, :linecolor), + whiskerlinewidth=theme(scene, :linewidth), # outliers points - show_outliers = true, - marker = theme(scene, :marker), - markersize = theme(scene, :markersize), - outliercolor = automatic, - outlierstrokecolor = theme(scene, :markerstrokecolor), - outlierstrokewidth = theme(scene, :markerstrokewidth), - cycle = [:color => :patchcolor], - inspectable = theme(scene, :inspectable) + show_outliers=true, + marker=theme(scene, :marker), + markersize=theme(scene, :markersize), + outliercolor=automatic, + outlierstrokecolor=theme(scene, :markerstrokecolor), + outlierstrokewidth=theme(scene, :markerstrokewidth), + cycle=[:color => :patchcolor], + inspectable=theme(scene, :inspectable), ) end @@ -79,14 +79,39 @@ flip_xy(p::Point2f) = reverse(p) flip_xy(r::Rect{2,T}) where {T} = Rect{2,T}(reverse(r.origin), reverse(r.widths)) function Makie.plot!(plot::BoxPlot) - args = @extract plot (weights, width, range, show_outliers, whiskerwidth, show_notch, orientation, gap, dodge, n_dodge, dodge_gap) + args = @extract plot ( + weights, + width, + range, + show_outliers, + whiskerwidth, + show_notch, + orientation, + gap, + dodge, + n_dodge, + dodge_gap, + ) signals = lift( plot[1], plot[2], plot[:color], args..., - ) do x, y, color, weights, width, range, show_outliers, whiskerwidth, show_notch, orientation, gap, dodge, n_dodge, dodge_gap + ) do x, + y, + color, + weights, + width, + range, + show_outliers, + whiskerwidth, + show_notch, + orientation, + gap, + dodge, + n_dodge, + dodge_gap x̂, boxwidth = compute_x_and_width(x, width, gap, dodge, n_dodge, dodge_gap) if !(whiskerwidth == :match || whiskerwidth >= 0) error("whiskerwidth must be :match or a positive number. Found: $whiskerwidth") @@ -122,7 +147,7 @@ function Makie.plot!(plot::BoxPlot) if Float64(range) != 0.0 # if the range is 0.0, the whiskers will extend to the data limit = range * (q4 - q2) inside = Float64[] - for (value, idx) in zip(values,idxs) + for (value, idx) in zip(values, idxs) if (value < (q2 - limit)) || (value > (q4 + limit)) if show_outliers push!(outlier_points, (center, value)) @@ -162,17 +187,17 @@ function Makie.plot!(plot::BoxPlot) end return ( - centers = centers, - boxmin = boxmin, - boxmax = boxmax, - medians = medians, - notchmin = notchmin, - notchmax = notchmax, - outliers = outlier_points, - t_segments = t_segments, - boxwidth = boxwidth, - outlier_indices = outlier_indices, - boxcolor = boxcolor, + centers=centers, + boxmin=boxmin, + boxmax=boxmax, + medians=medians, + notchmin=notchmin, + notchmax=notchmax, + outliers=outlier_points, + t_segments=t_segments, + boxwidth=boxwidth, + outlier_indices=outlier_indices, + boxcolor=boxcolor, ) end centers = @lift($signals.centers) @@ -187,51 +212,52 @@ function Makie.plot!(plot::BoxPlot) outlier_indices = @lift($signals.outlier_indices) boxcolor = @lift($signals.boxcolor) - outliercolor = lift(plot[:outliercolor], plot[:color], outlier_indices) do outliercolor, color, outlier_indices - c = outliercolor === automatic ? color : outliercolor - if c isa AbstractVector - return c[outlier_indices] - else - return c + outliercolor = + lift(plot[:outliercolor], plot[:color], outlier_indices) do outliercolor, color, outlier_indices + c = outliercolor === automatic ? color : outliercolor + if c isa AbstractVector + return c[outlier_indices] + else + return c + end end - end scatter!( plot, - color = outliercolor, - marker = plot[:marker], - markersize = plot[:markersize], - strokecolor = plot[:outlierstrokecolor], - strokewidth = plot[:outlierstrokewidth], + color=outliercolor, + marker=plot[:marker], + markersize=plot[:markersize], + strokecolor=plot[:outlierstrokecolor], + strokewidth=plot[:outlierstrokewidth], outliers, - inspectable = plot[:inspectable], - colorrange = @lift($boxcolor isa AbstractArray{<:Real} ? extrema($boxcolor) : automatic), # if only one group has outliers, the colorrange will be width 0 otherwise, if it's not an array, it shouldn't matter + inspectable=plot[:inspectable], + colorrange=@lift($boxcolor isa AbstractArray{<:Real} ? extrema($boxcolor) : automatic), # if only one group has outliers, the colorrange will be width 0 otherwise, if it's not an array, it shouldn't matter ) linesegments!( plot, - color = plot[:whiskercolor], - linewidth = plot[:whiskerlinewidth], + color=plot[:whiskercolor], + linewidth=plot[:whiskerlinewidth], t_segments, - inspectable = plot[:inspectable] + inspectable=plot[:inspectable], ) - crossbar!( + return crossbar!( plot, - color = boxcolor, - colorrange = plot[:colorrange], - colormap = plot[:colormap], - strokecolor = plot[:strokecolor], - strokewidth = plot[:strokewidth], - midlinecolor = plot[:mediancolor], - midlinewidth = plot[:medianlinewidth], - show_midline = plot[:show_median], - orientation = orientation, - width = boxwidth, - gap = 0, - show_notch = show_notch, - notchmin = notchmin, - notchmax = notchmax, - notchwidth = plot[:notchwidth], - inspectable = plot[:inspectable], + color=boxcolor, + colorrange=plot[:colorrange], + colormap=plot[:colormap], + strokecolor=plot[:strokecolor], + strokewidth=plot[:strokewidth], + midlinecolor=plot[:mediancolor], + midlinewidth=plot[:medianlinewidth], + show_midline=plot[:show_median], + orientation=orientation, + width=boxwidth, + gap=0, + show_notch=show_notch, + notchmin=notchmin, + notchmax=notchmax, + notchwidth=plot[:notchwidth], + inspectable=plot[:inspectable], centers, medians, boxmin, diff --git a/src/stats/conversions.jl b/src/stats/conversions.jl index ae48ecbec2b..88c735fb77a 100644 --- a/src/stats/conversions.jl +++ b/src/stats/conversions.jl @@ -1,9 +1,5 @@ struct SampleBased <: ConversionTrait end -function convert_arguments(::SampleBased, args::NTuple{N,AbstractVector{<:Number}}) where {N} - return args -end +convert_arguments(::SampleBased, args::NTuple{N,AbstractVector{<:Number}}) where {N} = args -function convert_arguments(P::SampleBased, positions::Vararg{AbstractVector}) - return convert_arguments(P, positions) -end +convert_arguments(P::SampleBased, positions::Vararg{AbstractVector}) = convert_arguments(P, positions) diff --git a/src/stats/crossbar.jl b/src/stats/crossbar.jl index 683b341ecba..2f4eac30a54 100644 --- a/src/stats/crossbar.jl +++ b/src/stats/crossbar.jl @@ -23,35 +23,46 @@ It is most commonly used as part of the `boxplot`. """ @recipe(CrossBar, x, y, ymin, ymax) do scene t = Theme( - color=theme(scene, :patchcolor), - colormap=theme(scene, :colormap), - colorrange=automatic, - orientation=:vertical, - # box and dodging - width = automatic, - dodge = automatic, - n_dodge = automatic, - gap = 0.2, - dodge_gap = 0.03, - strokecolor = theme(scene, :patchstrokecolor), - strokewidth = theme(scene, :patchstrokewidth), - # notch - show_notch=false, - notchmin=automatic, - notchmax=automatic, - notchwidth=0.5, - # median line - show_midline=true, - midlinecolor=automatic, - midlinewidth=theme(scene, :linewidth), - inspectable = theme(scene, :inspectable), - cycle = [:color => :patchcolor], -) - t + color=theme(scene, :patchcolor), + colormap=theme(scene, :colormap), + colorrange=automatic, + orientation=:vertical, + # box and dodging + width=automatic, + dodge=automatic, + n_dodge=automatic, + gap=0.2, + dodge_gap=0.03, + strokecolor=theme(scene, :patchstrokecolor), + strokewidth=theme(scene, :patchstrokewidth), + # notch + show_notch=false, + notchmin=automatic, + notchmax=automatic, + notchwidth=0.5, + # median line + show_midline=true, + midlinecolor=automatic, + midlinewidth=theme(scene, :linewidth), + inspectable=theme(scene, :inspectable), + cycle=[:color => :patchcolor], + ) + return t end function Makie.plot!(plot::CrossBar) - args = @extract plot (width, dodge, n_dodge, gap, dodge_gap, show_notch, notchmin, notchmax, notchwidth, orientation) + args = @extract plot ( + width, + dodge, + n_dodge, + gap, + dodge_gap, + show_notch, + notchmin, + notchmax, + notchwidth, + orientation, + ) signals = lift( plot[1], @@ -79,19 +90,25 @@ function Makie.plot!(plot::CrossBar) end # when notchmin = ymin || notchmax == ymax, fill disappears from # half the box. first ∘ StatsBase.rle removes adjacent duplicates. - points = first.(StatsBase.rle.(Base.vect.(fpoint.(l, ymin), - fpoint.(r, ymin), - fpoint.(r, nmin), - fpoint.(m .+ nw .* hw, y), # notch right - fpoint.(r, nmax), - fpoint.(r, ymax), - fpoint.(l, ymax), - fpoint.(l, nmax), - fpoint.(m .- nw .* hw, y), # notch left - fpoint.(l, nmin), - fpoint.(l, ymin) - ))) - boxes = if points isa AbstractVector{<: Point} # poly + points = + first.( + StatsBase.rle.( + Base.vect.( + fpoint.(l, ymin), + fpoint.(r, ymin), + fpoint.(r, nmin), + fpoint.(m .+ nw .* hw, y), # notch right + fpoint.(r, nmax), + fpoint.(r, ymax), + fpoint.(l, ymax), + fpoint.(l, nmax), + fpoint.(m .- nw .* hw, y), # notch left + fpoint.(l, nmin), + fpoint.(l, ymin), + ) + ) + ) + boxes = if points isa AbstractVector{<:Point} # poly [GeometryBasics.triangle_mesh(points)] else # multiple polys (Vector{Vector{<:Point}}) GeometryBasics.triangle_mesh.(points) @@ -113,18 +130,14 @@ function Makie.plot!(plot::CrossBar) colormap=plot.colormap, strokecolor=plot.strokecolor, strokewidth=plot.strokewidth, - inspectable = plot[:inspectable] + inspectable=plot[:inspectable], ) - linesegments!( + return linesegments!( plot, - color=lift( - (mc, sc) -> mc === automatic ? sc : mc, - plot.midlinecolor, - plot.strokecolor, - ), + color=lift((mc, sc) -> mc === automatic ? sc : mc, plot.midlinecolor, plot.strokecolor), linewidth=plot[:midlinewidth], visible=plot[:show_midline], - inspectable = plot[:inspectable], + inspectable=plot[:inspectable], midlines, ) end diff --git a/src/stats/density.jl b/src/stats/density.jl index 4d19df179fa..2fee72edcf2 100644 --- a/src/stats/density.jl +++ b/src/stats/density.jl @@ -1,19 +1,19 @@ function convert_arguments(P::PlotFunc, d::KernelDensity.UnivariateKDE) ptype = plottype(P, Lines) # choose the more concrete one - to_plotspec(ptype, convert_arguments(ptype, d.x, d.density)) + return to_plotspec(ptype, convert_arguments(ptype, d.x, d.density)) end function convert_arguments(::Type{<:Poly}, d::KernelDensity.UnivariateKDE) points = Vector{Point2f}(undef, length(d.x) + 2) points[1] = Point2f(d.x[1], 0) - points[2:end-1] .= Point2f.(d.x, d.density) + points[2:(end - 1)] .= Point2f.(d.x, d.density) points[end] = Point2f(d.x[end], 0) - (points,) + return (points,) end function convert_arguments(P::PlotFunc, d::KernelDensity.BivariateKDE) ptype = plottype(P, Heatmap) - to_plotspec(ptype, convert_arguments(ptype, d.x, d.y, d.density)) + return to_plotspec(ptype, convert_arguments(ptype, d.x, d.y, d.density)) end """ @@ -34,36 +34,43 @@ note that only 2-element colormaps can work correctly. $(ATTRIBUTES) """ @recipe(Density) do scene - Theme( - color = theme(scene, :patchcolor), - colormap = theme(scene, :colormap), - colorrange = Makie.automatic, - strokecolor = theme(scene, :patchstrokecolor), - strokewidth = theme(scene, :patchstrokewidth), - linestyle = nothing, - strokearound = false, - npoints = 200, - offset = 0.0, - direction = :x, - boundary = automatic, - bandwidth = automatic, - weights = automatic, - cycle = [:color => :patchcolor], - inspectable = theme(scene, :inspectable) + return Theme( + color=theme(scene, :patchcolor), + colormap=theme(scene, :colormap), + colorrange=Makie.automatic, + strokecolor=theme(scene, :patchstrokecolor), + strokewidth=theme(scene, :patchstrokewidth), + linestyle=nothing, + strokearound=false, + npoints=200, + offset=0.0, + direction=:x, + boundary=automatic, + bandwidth=automatic, + weights=automatic, + cycle=[:color => :patchcolor], + inspectable=theme(scene, :inspectable), ) end function plot!(plot::Density{<:Tuple{<:AbstractVector}}) x = plot[1] - lowerupper = lift(x, plot.direction, plot.boundary, plot.offset, - plot.npoints, plot.bandwidth, plot.weights) do x, dir, bound, offs, n, bw, weights - - k = KernelDensity.kde(x; - npoints = n, - (bound === automatic ? NamedTuple() : (boundary = bound,))..., - (bw === automatic ? NamedTuple() : (bandwidth = bw,))..., - (weights === automatic ? NamedTuple() : (weights = StatsBase.weights(weights),))... + lowerupper = lift( + x, + plot.direction, + plot.boundary, + plot.offset, + plot.npoints, + plot.bandwidth, + plot.weights, + ) do x, dir, bound, offs, n, bw, weights + k = KernelDensity.kde( + x; + npoints=n, + (bound === automatic ? NamedTuple() : (boundary=bound,))..., + (bw === automatic ? NamedTuple() : (bandwidth=bw,))..., + (weights === automatic ? NamedTuple() : (weights=StatsBase.weights(weights),))..., ) if dir === :x @@ -75,7 +82,7 @@ function plot!(plot::Density{<:Tuple{<:AbstractVector}}) else error("Invalid direction $dir, only :x or :y allowed") end - (lowerv, upperv) + return (lowerv, upperv) end linepoints = lift(lowerupper, plot.strokearound) do lu, sa @@ -95,7 +102,7 @@ function plot!(plot::Density{<:Tuple{<:AbstractVector}}) on(lowerupper) do (l, u) lower.val = l - upper[] = u + return upper[] = u end notify(lowerupper) @@ -107,16 +114,31 @@ function plot!(plot::Density{<:Tuple{<:AbstractVector}}) elseif (dir == :y && c == :x) || (dir == :x && c == :y) o = Float32(plot.offset[]) dim = dir == :x ? 2 : 1 - return vcat(Float32[l[dim] - o for l in lu[1]], Float32[l[dim] - o for l in lu[2]])::Vector{Float32} + return vcat( + Float32[l[dim] - o for l in lu[1]], + Float32[l[dim] - o for l in lu[2]], + )::Vector{Float32} else return to_color(c) end end - band!(plot, lower, upper, color = colorobs, colormap = plot.colormap, - colorrange = plot.colorrange, inspectable = plot.inspectable) - l = lines!(plot, linepoints, color = plot.strokecolor, - linestyle = plot.linestyle, linewidth = plot.strokewidth, - inspectable = plot.inspectable) - plot + band!( + plot, + lower, + upper, + color=colorobs, + colormap=plot.colormap, + colorrange=plot.colorrange, + inspectable=plot.inspectable, + ) + l = lines!( + plot, + linepoints, + color=plot.strokecolor, + linestyle=plot.linestyle, + linewidth=plot.strokewidth, + inspectable=plot.inspectable, + ) + return plot end diff --git a/src/stats/distributions.jl b/src/stats/distributions.jl index da7b65cc154..753bbd15d17 100644 --- a/src/stats/distributions.jl +++ b/src/stats/distributions.jl @@ -7,7 +7,7 @@ The StatMakie.jl package is licensed under the MIT "Expat" License: function default_range(dist::Distribution, alpha=0.0001) minval = isfinite(minimum(dist)) ? minimum(dist) : quantile(dist, alpha) maxval = isfinite(maximum(dist)) ? maximum(dist) : quantile(dist, 1 - alpha) - minval..maxval + return minval .. maxval end isdiscrete(::Distribution) = false @@ -21,7 +21,7 @@ convert_arguments(P::PlotFunc, dist::Distribution) = convert_arguments(P, suppor function convert_arguments(P::PlotFunc, x::Union{Interval,AbstractVector}, dist::Distribution) default_ptype = isdiscrete(dist) ? ScatterLines : Lines ptype = plottype(P, default_ptype) - to_plotspec(ptype, convert_arguments(ptype, x, x -> pdf(dist, x))) + return to_plotspec(ptype, convert_arguments(ptype, x, x -> pdf(dist, x))) end # ----------------------------------------------------------------------------- # qqplots (M. K. Borregaard implementation from StatPlots) @@ -58,17 +58,17 @@ Graphical attributes are @recipe(QQPlot) do scene s_theme = default_theme(scene, Scatter) l_theme = default_theme(scene, Lines) - Attributes( - color = l_theme.color, - linestyle = l_theme.linestyle, - linewidth = l_theme.linewidth, - markercolor = automatic, - markersize = s_theme.markersize, - strokecolor = s_theme.strokecolor, - strokewidth = s_theme.strokewidth, - marker = s_theme.marker, - inspectable = theme(scene, :inspectable), - cycle = [:color], + return Attributes( + color=l_theme.color, + linestyle=l_theme.linestyle, + linewidth=l_theme.linewidth, + markercolor=automatic, + markersize=s_theme.markersize, + strokecolor=s_theme.strokecolor, + strokewidth=s_theme.strokewidth, + marker=s_theme.marker, + inspectable=theme(scene, :inspectable), + cycle=[:color], ) end @@ -79,14 +79,16 @@ Shorthand for `qqplot(Normal(0,1), y)`, i.e., draw a Q-Q plot of `y` against the standard normal distribution. See `qqplot` for more details. """ @recipe(QQNorm) do scene - default_theme(scene, QQPlot) + return default_theme(scene, QQPlot) end # Compute points and line for the qqplot -function fit_qqplot(x, y; qqline = :none) +function fit_qqplot(x, y; qqline=:none) if !(qqline in (:identity, :fit, :fitrobust, :none)) - msg = "valid values for qqline are :identity, :fit, :fitrobust or :none, " * - "encountered " * repr(qqline) + msg = + "valid values for qqline are :identity, :fit, :fitrobust or :none, " * + "encountered " * + repr(qqline) throw(ArgumentError(msg)) end h = qqbuild(x, y) @@ -110,20 +112,20 @@ end maybefit(D::Type{<:Distribution}, y) = Distributions.fit(D, y) maybefit(x, _) = x -function convert_arguments(::Type{<:QQPlot}, x′, y; qqline = :none) +function convert_arguments(::Type{<:QQPlot}, x′, y; qqline=:none) x = maybefit(x′, y) - points, line = fit_qqplot(x, y; qqline = qqline) + points, line = fit_qqplot(x, y; qqline=qqline) return PlotSpec{QQPlot}(points, line) end -convert_arguments(::Type{<:QQNorm}, y; qqline = :none) = - convert_arguments(QQPlot, Distributions.Normal(0, 1), y; qqline = qqline) +function convert_arguments(::Type{<:QQNorm}, y; qqline=:none) + return convert_arguments(QQPlot, Distributions.Normal(0, 1), y; qqline=qqline) +end used_attributes(::Type{<:QQNorm}, y) = (:qqline,) used_attributes(::Type{<:QQPlot}, x, y) = (:qqline,) function Makie.plot!(p::QQPlot) - points, line = p[1], p[2] real_markercolor = Observable{RGBColors}() @@ -131,18 +133,22 @@ function Makie.plot!(p::QQPlot) return to_color(markercolor === automatic ? color : markercolor) end - scatter!(p, points; - color = real_markercolor, - strokecolor = p.strokecolor, - strokewidth = p.strokewidth, - marker = p.marker, - markersize = p.markersize, - inspectable = p.inspectable + scatter!( + p, + points; + color=real_markercolor, + strokecolor=p.strokecolor, + strokewidth=p.strokewidth, + marker=p.marker, + markersize=p.markersize, + inspectable=p.inspectable, ) - linesegments!(p, line; - color = p.color, - linestyle = p.linestyle, - linewidth = p.linewidth, - inspectable = p.inspectable + return linesegments!( + p, + line; + color=p.color, + linestyle=p.linestyle, + linewidth=p.linewidth, + inspectable=p.inspectable, ) end diff --git a/src/stats/ecdf.jl b/src/stats/ecdf.jl index 6494ca58df9..13144e144ce 100644 --- a/src/stats/ecdf.jl +++ b/src/stats/ecdf.jl @@ -29,7 +29,7 @@ function convert_arguments(P::PlotFunc, x0::AbstractInterval, ecdf::StatsBase.EC z = ecdf_xvalues(ecdf, Inf) n = length(z) imin, imax = findfirst(>(xmin), z), findlast(<(xmax), z) - idx_min = imin === nothing ? n+1 : imin + idx_min = imin === nothing ? n + 1 : imin idx_max = imax === nothing ? -1 : imax x = [xmin - eps(oftype(z[1], xmin)); xmin; view(z, idx_min:idx_max); xmax] return convert_arguments(P, x, ecdf) @@ -47,7 +47,7 @@ If `weights` for the values are provided, a weighted ECDF is plotted. $(ATTRIBUTES) """ @recipe(ECDFPlot) do scene - default_theme(scene, Stairs) + return default_theme(scene, Stairs) end used_attributes(::Type{<:ECDFPlot}, ::AbstractVector) = (:npoints, :weights) diff --git a/src/stats/hexbin.jl b/src/stats/hexbin.jl index 21527975726..ebee7276528 100644 --- a/src/stats/hexbin.jl +++ b/src/stats/hexbin.jl @@ -19,14 +19,15 @@ Plots a heatmap with hexagonal bins for the observations `xs` and `ys`. """ @recipe(Hexbin) do scene return Attributes(; - colormap=theme(scene, :colormap), - colorrange=Makie.automatic, - bins=20, - cellsize=nothing, - threshold=1, - scale=identity, - strokewidth=0, - strokecolor=:black) + colormap=theme(scene, :colormap), + colorrange=Makie.automatic, + bins=20, + cellsize=nothing, + threshold=1, + scale=identity, + strokewidth=0, + strokecolor=:black, + ) end function spacings_offsets_nbins(bins::Tuple{Int,Int}, cellsize::Nothing, xmi, xma, ymi, yma) @@ -51,8 +52,12 @@ function spacings_offsets_nbins(bins, cellsizes::Tuple{<:Real,<:Real}, xmi, xma, xspacing = cellsizes[1] / 2 yspacing = cellsizes[2] * 3 / 4 (nx, restx), (ny, resty) = fldmod.((x_diff, y_diff), (xspacing, yspacing)) - return xspacing, yspacing, xmi - (restx > 0 ? (xspacing - restx) / 2 : 0), - ymi - (resty > 0 ? (yspacing - resty) / 2 : 0), Int(nx) + (restx > 0), Int(ny) + (resty > 0) + return xspacing, + yspacing, + xmi - (restx > 0 ? (xspacing - restx) / 2 : 0), + ymi - (resty > 0 ? (yspacing - resty) / 2 : 0), + Int(nx) + (restx > 0), + Int(ny) + (resty > 0) end Makie.conversion_trait(::Type{<:Hexbin}) = PointBased() @@ -93,8 +98,8 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) x_diff = xma - xmi y_diff = yma - ymi - xspacing, yspacing, xoff, yoff, nbinsx, nbinsy = spacings_offsets_nbins(bins, cellsize, xmi, xma, ymi, - yma) + xspacing, yspacing, xoff, yoff, nbinsx, nbinsy = + spacings_offsets_nbins(bins, cellsize, xmi, xma, ymi, yma) ysize = yspacing / 3 * 4 ry = ysize / 2 @@ -119,26 +124,20 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) is_grid1 = d1 < d2 # _xy = is_grid1 ? (nx, ny) : (nxs, nys) - + id = if is_grid1 - ( - cld(dvx, 2), - iseven(dvy) ? dvy : dvy+1 - ) + (cld(dvx, 2), iseven(dvy) ? dvy : dvy + 1) else - ( - fld(dvx, 2), - iseven(dvy) ? dvy+1 : dvy, - ) + (fld(dvx, 2), iseven(dvy) ? dvy + 1 : dvy) end d[id] = get(d, id, 0) + 1 end if threshold == 0 - for iy in 0:nbinsy-1 + for iy in 0:(nbinsy - 1) _nx = isodd(iy) ? fld(nbinsx, 2) : cld(nbinsx, 2) - for ix in 0:_nx-1 + for ix in 0:(_nx - 1) _x = xoff + 2 * ix * xspacing + (isodd(iy) * xspacing) _y = yoff + iy * yspacing c = get(d, (ix, iy), 0) @@ -176,28 +175,30 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) hexmarker = Polygon(Point2f[(cos(a), sin(a)) for a in range(pi / 6, 13pi / 6; length=7)[1:6]]) - return scatter!(hb, points; - colorrange=hb.colorrange, - color=count_hex, - colormap=hb.colormap, - marker=hexmarker, - markersize=markersize, - markerspace=:data, - strokewidth=hb.strokewidth, - strokecolor=hb.strokecolor) + return scatter!( + hb, + points; + colorrange=hb.colorrange, + color=count_hex, + colormap=hb.colormap, + marker=hexmarker, + markersize=markersize, + markerspace=:data, + strokewidth=hb.strokewidth, + strokecolor=hb.strokecolor, + ) end -function center_value(dv, spacing, offset, is_grid1) +center_value(dv, spacing, offset, is_grid1) = if is_grid1 offset + spacing * (dv + isodd(dv)) else offset + spacing * (dv + iseven(dv)) end -end function nearest_center(val, spacing, offset) dv = Int(fld(val - offset, spacing)) rounded = offset + spacing * (dv + isodd(dv)) rounded_scaled = offset + spacing * (dv + iseven(dv)) return rounded, rounded_scaled, dv -end \ No newline at end of file +end diff --git a/src/stats/hist.jl b/src/stats/hist.jl index 3ab8d0f281a..0d1afd8888a 100644 --- a/src/stats/hist.jl +++ b/src/stats/hist.jl @@ -1,13 +1,12 @@ const histogram_plot_types = [BarPlot, Heatmap, Volume] -function convert_arguments(P::Type{<:AbstractPlot}, h::StatsBase.Histogram{<:Any, N}) where N +function convert_arguments(P::Type{<:AbstractPlot}, h::StatsBase.Histogram{<:Any,N}) where {N} ptype = plottype(P, histogram_plot_types[N]) - f(edges) = edges[1:end-1] .+ diff(edges)./2 - kwargs = N == 1 ? (; width = step(h.edges[1]), gap = 0, dodge_gap = 0) : NamedTuple() - to_plotspec(ptype, convert_arguments(ptype, map(f, h.edges)..., Float64.(h.weights)); kwargs...) + f(edges) = edges[1:(end - 1)] .+ diff(edges) ./ 2 + kwargs = N == 1 ? (; width=step(h.edges[1]), gap=0, dodge_gap=0) : NamedTuple() + return to_plotspec(ptype, convert_arguments(ptype, map(f, h.edges)..., Float64.(h.weights)); kwargs...) end - """ hist(values; bins = 15, normalization = :none) @@ -44,29 +43,28 @@ Color can either be: $(ATTRIBUTES) """ @recipe(Hist, values) do scene - Attributes( - bins = 15, # Int or iterable of edges - normalization = :none, - weights = automatic, - cycle = [:color => :patchcolor], - color = theme(scene, :patchcolor), - offset = 0.0, - fillto = automatic, - scale_to = nothing, - - bar_labels = nothing, - flip_labels_at = Inf, - label_color = theme(scene, :textcolor), - over_background_color = automatic, - over_bar_color = automatic, - label_offset = 5, - label_font = theme(scene, :font), - label_size = 20, - label_formatter = bar_label_formatter + return Attributes( + bins=15, # Int or iterable of edges + normalization=:none, + weights=automatic, + cycle=[:color => :patchcolor], + color=theme(scene, :patchcolor), + offset=0.0, + fillto=automatic, + scale_to=nothing, + bar_labels=nothing, + flip_labels_at=Inf, + label_color=theme(scene, :textcolor), + over_background_color=automatic, + over_bar_color=automatic, + label_offset=5, + label_font=theme(scene, :font), + label_size=20, + label_formatter=bar_label_formatter, ) end -function pick_hist_edges(vals, bins) +pick_hist_edges(vals, bins) = if bins isa Int mi, ma = float.(extrema(vals)) if mi == ma @@ -74,32 +72,31 @@ function pick_hist_edges(vals, bins) end # hist is right-open, so to include the upper data point, make the last bin a tiny bit bigger ma = nextfloat(ma) - return range(mi, ma, length = bins+1) + return range(mi, ma, length=bins + 1) else if !issorted(bins) error("Histogram bins are not sorted: $bins") end return bins end -end function Makie.plot!(plot::Hist) - values = plot.values - edges = lift(pick_hist_edges, values, plot.bins) - - points = lift(edges, plot.normalization, plot.scale_to, plot.weights) do edges, normalization, scale_to, wgts - w = wgts === automatic ? () : (StatsBase.weights(wgts),) - h = StatsBase.fit(StatsBase.Histogram, values[], w..., edges) - h_norm = StatsBase.normalize(h, mode = normalization) - centers = edges[1:end-1] .+ (diff(edges) ./ 2) - weights = h_norm.weights - if !isnothing(scale_to) - max = maximum(weights) - weights .= weights ./ max .* scale_to + edges = lift(pick_hist_edges, values, plot.bins) + + points = + lift(edges, plot.normalization, plot.scale_to, plot.weights) do edges, normalization, scale_to, wgts + w = wgts === automatic ? () : (StatsBase.weights(wgts),) + h = StatsBase.fit(StatsBase.Histogram, values[], w..., edges) + h_norm = StatsBase.normalize(h, mode=normalization) + centers = edges[1:(end - 1)] .+ (diff(edges) ./ 2) + weights = h_norm.weights + if !isnothing(scale_to) + max = maximum(weights) + weights .= weights ./ max .* scale_to + end + return Point2f.(centers, weights) end - return Point2f.(centers, weights) - end widths = lift(diff, edges) color = lift(plot.color) do color if color === :values @@ -110,15 +107,25 @@ function Makie.plot!(plot::Hist) end bar_labels = map(plot.bar_labels) do x - x === :values ? :y : x + return x === :values ? :y : x end # plot the values, not the observables, to be in control of updating - bp = barplot!(plot, points[]; width = widths[], gap = 0, plot.attributes..., fillto=plot.fillto, offset=plot.offset, bar_labels=bar_labels, color=color) + bp = barplot!( + plot, + points[]; + width=widths[], + gap=0, + plot.attributes..., + fillto=plot.fillto, + offset=plot.offset, + bar_labels=bar_labels, + color=color, + ) # update the barplot points without triggering, then trigger with `width` on(widths) do w bp[1].val = points[] - bp.width = w + return bp.width = w end - plot + return plot end diff --git a/src/stats/violin.jl b/src/stats/violin.jl index 0361ef246c6..d83e5de9ca6 100644 --- a/src/stats/violin.jl +++ b/src/stats/violin.jl @@ -14,24 +14,24 @@ Draw a violin plot. - `datalimits`: specify values to trim the `violin`. Can be a `Tuple` or a `Function` (e.g. `datalimits=extrema`) """ @recipe(Violin, x, y) do scene - Theme(; + return Theme(; default_theme(scene, Poly)..., - npoints = 200, - boundary = automatic, - bandwidth = automatic, - weights = automatic, - side = :both, - orientation = :vertical, - width = automatic, - dodge = automatic, - n_dodge = automatic, - gap = 0.2, - dodge_gap = 0.03, - datalimits = (-Inf, Inf), - max_density = automatic, - show_median = false, - mediancolor = theme(scene, :linecolor), - medianlinewidth = theme(scene, :linewidth), + npoints=200, + boundary=automatic, + bandwidth=automatic, + weights=automatic, + side=:both, + orientation=:vertical, + width=automatic, + dodge=automatic, + n_dodge=automatic, + gap=0.2, + dodge_gap=0.03, + datalimits=(-Inf, Inf), + max_density=automatic, + show_median=false, + mediancolor=theme(scene, :linecolor), + medianlinewidth=theme(scene, :linewidth), ) end @@ -49,9 +49,44 @@ end function plot!(plot::Violin) x, y = plot[1], plot[2] - args = @extract plot (width, side, color, show_median, npoints, boundary, bandwidth, weights, - datalimits, max_density, dodge, n_dodge, gap, dodge_gap, orientation) - signals = lift(x, y, args...) do x, y, width, vside, color, show_median, n, bound, bw, w, limits, max_density, dodge, n_dodge, gap, dodge_gap, orientation + args = @extract plot ( + width, + side, + color, + show_median, + npoints, + boundary, + bandwidth, + weights, + datalimits, + max_density, + dodge, + n_dodge, + gap, + dodge_gap, + orientation, + ) + signals = lift( + x, + y, + args..., + ) do x, + y, + width, + vside, + color, + show_median, + n, + bound, + bw, + w, + limits, + max_density, + dodge, + n_dodge, + gap, + dodge_gap, + orientation x̂, violinwidth = compute_x_and_width(x, width, gap, dodge, n_dodge, dodge_gap) # for horizontal violin just flip all componentes @@ -62,24 +97,25 @@ function plot!(plot::Violin) # Allow `side` to be either scalar or vector sides = broadcast(x̂, vside) do _, s - return s == :left ? - 1 : s == :right ? 1 : 0 + return s == :left ? -1 : s == :right ? 1 : 0 end - sa = StructArray((x = x̂, side = sides)) + sa = StructArray((x=x̂, side=sides)) specs = map(StructArrays.finduniquesorted(sa)) do (key, idxs) v = view(y, idxs) - k = KernelDensity.kde(v; - npoints = n, - (bound === automatic ? NamedTuple() : (boundary = bound,))..., - (bw === automatic ? NamedTuple() : (bandwidth = bw,))..., - (w === automatic ? NamedTuple() : (weights = StatsBase.weights(view(w, idxs)),))... + k = KernelDensity.kde( + v; + npoints=n, + (bound === automatic ? NamedTuple() : (boundary=bound,))..., + (bw === automatic ? NamedTuple() : (bandwidth=bw,))..., + (w === automatic ? NamedTuple() : (weights=StatsBase.weights(view(w, idxs)),))..., ) l1, l2 = limits isa Function ? limits(v) : limits i1, i2 = searchsortedfirst(k.x, l1), searchsortedlast(k.x, l2) - kde = (x = view(k.x, i1:i2), density = view(k.density, i1:i2)) + kde = (x=view(k.x, i1:i2), density=view(k.density, i1:i2)) c = getuniquevalue(color, idxs) - return (x = key.x, side = key.side, color = to_color(c), kde = kde, median = median(v)) + return (x=key.x, side=key.side, color=to_color(c), kde=kde, median=median(v)) end max = if max_density === automatic @@ -92,11 +128,11 @@ function plot!(plot::Violin) end vertices = Vector{Point2f}[] - lines = Pair{Point2f, Point2f}[] + lines = Pair{Point2f,Point2f}[] colors = RGBA{Float32}[] for spec in specs - scale = 0.5*violinwidth/max + scale = 0.5 * violinwidth / max xl = reverse(spec.x .- spec.kde.density .* scale) xr = spec.x .+ spec.kde.density .* scale yl = reverse(spec.kde.x) @@ -116,8 +152,8 @@ function plot!(plot::Violin) # interpolate median bounds between corresponding points xm = spec.median ip = findfirst(>(xm), spec.kde.x) - ym₋, ym₊ = spec.kde.density[ip-1], spec.kde.density[ip] - xm₋, xm₊ = spec.kde.x[ip-1], spec.kde.x[ip] + ym₋, ym₊ = spec.kde.density[ip - 1], spec.kde.density[ip] + xm₋, xm₊ = spec.kde.x[ip - 1], spec.kde.x[ip] ym = (xm * (ym₊ - ym₋) + xm₊ * ym₋ - xm₋ * ym₊) / (xm₊ - xm₋) median_left = point_func(spec.side == 1 ? spec.x : spec.x - ym * scale, xm) median_right = point_func(spec.side == -1 ? spec.x : spec.x + ym * scale, xm) @@ -127,22 +163,22 @@ function plot!(plot::Violin) push!(colors, spec.color) end - return (vertices = vertices, lines = lines, colors = colors) + return (vertices=vertices, lines=lines, colors=colors) end poly!( plot, lift(s -> s.vertices, signals), - color = lift(s -> s.colors, signals), - strokecolor = plot[:strokecolor], - strokewidth = plot[:strokewidth], + color=lift(s -> s.colors, signals), + strokecolor=plot[:strokecolor], + strokewidth=plot[:strokewidth], ) - linesegments!( + return linesegments!( plot, lift(s -> s.lines, signals), - color = plot[:mediancolor], - linewidth = plot[:medianlinewidth], - visible = plot[:show_median], - inspectable = plot[:inspectable] + color=plot[:mediancolor], + linewidth=plot[:medianlinewidth], + visible=plot[:show_median], + inspectable=plot[:inspectable], ) end diff --git a/src/themes/theme_black.jl b/src/themes/theme_black.jl index 1f0b9965b59..40865a22800 100644 --- a/src/themes/theme_black.jl +++ b/src/themes/theme_black.jl @@ -1,50 +1,47 @@ function theme_black() - Theme( - backgroundcolor = :black, - textcolor = :white, - linecolor = :white, - Axis = ( - backgroundcolor = :transparent, - bottomspinecolor = :white, - topspinecolor = :white, - leftspinecolor = :white, - rightspinecolor = :white, - xgridcolor = RGBAf(1, 1, 1, 0.16), - ygridcolor = RGBAf(1, 1, 1, 0.16), - xtickcolor = :white, - ytickcolor = :white, + return Theme( + backgroundcolor=:black, + textcolor=:white, + linecolor=:white, + Axis=( + backgroundcolor=:transparent, + bottomspinecolor=:white, + topspinecolor=:white, + leftspinecolor=:white, + rightspinecolor=:white, + xgridcolor=RGBAf(1, 1, 1, 0.16), + ygridcolor=RGBAf(1, 1, 1, 0.16), + xtickcolor=:white, + ytickcolor=:white, ), - Legend = ( - framecolor = :white, - bgcolor = :black, + Legend=(framecolor=:white, bgcolor=:black), + Axis3=( + xgridcolor=RGBAf(1, 1, 1, 0.16), + ygridcolor=RGBAf(1, 1, 1, 0.16), + zgridcolor=RGBAf(1, 1, 1, 0.16), + xspinecolor_1=:white, + yspinecolor_1=:white, + zspinecolor_1=:white, + xspinecolor_2=:white, + yspinecolor_2=:white, + zspinecolor_2=:white, + xspinecolor_3=:white, + yspinecolor_3=:white, + zspinecolor_3=:white, + xticklabelpad=3, + yticklabelpad=3, + zticklabelpad=6, + xtickcolor=:white, + ytickcolor=:white, + ztickcolor=:white, ), - Axis3 = ( - xgridcolor = RGBAf(1, 1, 1, 0.16), - ygridcolor = RGBAf(1, 1, 1, 0.16), - zgridcolor = RGBAf(1, 1, 1, 0.16), - xspinecolor_1 = :white, - yspinecolor_1 = :white, - zspinecolor_1 = :white, - xspinecolor_2 = :white, - yspinecolor_2 = :white, - zspinecolor_2 = :white, - xspinecolor_3 = :white, - yspinecolor_3 = :white, - zspinecolor_3 = :white, - xticklabelpad = 3, - yticklabelpad = 3, - zticklabelpad = 6, - xtickcolor = :white, - ytickcolor = :white, - ztickcolor = :white, + Colorbar=( + tickcolor=:white, + spinecolor=:white, + topspinecolor=:white, + bottomspinecolor=:white, + leftspinecolor=:white, + rightspinecolor=:white, ), - Colorbar = ( - tickcolor = :white, - spinecolor = :white, - topspinecolor = :white, - bottomspinecolor = :white, - leftspinecolor = :white, - rightspinecolor = :white, - ) ) end diff --git a/src/themes/theme_dark.jl b/src/themes/theme_dark.jl index b284e95ca3a..8bae46a7aa6 100644 --- a/src/themes/theme_dark.jl +++ b/src/themes/theme_dark.jl @@ -1,42 +1,35 @@ function theme_dark() - Theme( - backgroundcolor = :gray10, - textcolor = :gray45, - linecolor = :gray60, - Axis = ( - backgroundcolor = :transparent, - xgridcolor = (:white, 0.09), - ygridcolor = (:white, 0.09), - leftspinevisible = false, - rightspinevisible = false, - bottomspinevisible = false, - topspinevisible = false, - xminorticksvisible = false, - yminorticksvisible = false, - xticksvisible = false, - yticksvisible = false, - xlabelpadding = 3, - ylabelpadding = 3 + return Theme( + backgroundcolor=:gray10, + textcolor=:gray45, + linecolor=:gray60, + Axis=( + backgroundcolor=:transparent, + xgridcolor=(:white, 0.09), + ygridcolor=(:white, 0.09), + leftspinevisible=false, + rightspinevisible=false, + bottomspinevisible=false, + topspinevisible=false, + xminorticksvisible=false, + yminorticksvisible=false, + xticksvisible=false, + yticksvisible=false, + xlabelpadding=3, + ylabelpadding=3, ), - Legend = ( - framevisible = false, - padding = (0, 0, 0, 0), + Legend=(framevisible=false, padding=(0, 0, 0, 0)), + Axis3=( + xgridcolor=(:white, 0.09), + ygridcolor=(:white, 0.09), + zgridcolor=(:white, 0.09), + xspinesvisible=false, + yspinesvisible=false, + zspinesvisible=false, + xticksvisible=false, + yticksvisible=false, + zticksvisible=false, ), - Axis3 = ( - xgridcolor = (:white, 0.09), - ygridcolor = (:white, 0.09), - zgridcolor = (:white, 0.09), - xspinesvisible = false, - yspinesvisible = false, - zspinesvisible = false, - xticksvisible = false, - yticksvisible = false, - zticksvisible = false, - ), - Colorbar = ( - ticksvisible = false, - spinewidth = 0, - ticklabelpad = 5, - ) + Colorbar=(ticksvisible=false, spinewidth=0, ticklabelpad=5), ) end diff --git a/src/themes/theme_ggplot2.jl b/src/themes/theme_ggplot2.jl index d3166c8c8bd..554158ae1ea 100644 --- a/src/themes/theme_ggplot2.jl +++ b/src/themes/theme_ggplot2.jl @@ -1,58 +1,48 @@ function theme_ggplot2() - Theme( - Axis = ( - backgroundcolor = :gray92, - xgridcolor = :white, - ygridcolor = :white, - xminorgridcolor = (:white, 0.5), - xminorgridvisible = true, - yminorgridcolor = (:white, 0.5), - yminorgridvisible = true, - leftspinevisible = false, - rightspinevisible = false, - bottomspinevisible = false, - topspinevisible = false, - xminorticksvisible = false, - yminorticksvisible = false, - xtickcolor = :gray21, - ytickcolor = :gray21, - spinewidth = 0, - xticklabelcolor = :gray31, - yticklabelcolor = :gray31, - xticksize = 4, - yticksize = 4, - xtickwidth = 1.5, - ytickwidth = 1.5, - xgridwidth = 1.5, - ygridwidth = 1.5, - xlabelpadding = 3, - ylabelpadding = 3 + return Theme( + Axis=( + backgroundcolor=:gray92, + xgridcolor=:white, + ygridcolor=:white, + xminorgridcolor=(:white, 0.5), + xminorgridvisible=true, + yminorgridcolor=(:white, 0.5), + yminorgridvisible=true, + leftspinevisible=false, + rightspinevisible=false, + bottomspinevisible=false, + topspinevisible=false, + xminorticksvisible=false, + yminorticksvisible=false, + xtickcolor=:gray21, + ytickcolor=:gray21, + spinewidth=0, + xticklabelcolor=:gray31, + yticklabelcolor=:gray31, + xticksize=4, + yticksize=4, + xtickwidth=1.5, + ytickwidth=1.5, + xgridwidth=1.5, + ygridwidth=1.5, + xlabelpadding=3, + ylabelpadding=3, ), - Legend = ( - framevisible = false, - padding = (0, 0, 0, 0), - patchcolor = :gray92, + Legend=(framevisible=false, padding=(0, 0, 0, 0), patchcolor=:gray92), + Axis3=( + xgridcolor=:white, + ygridcolor=:white, + zgridcolor=:white, + xspinesvisible=false, + yspinesvisible=false, + zspinesvisible=false, + yzpanelcolor=:gray92, + xzpanelcolor=:gray92, + xypanelcolor=:gray92, + xticklabelcolor=:gray31, + yticklabelcolor=:gray31, + zticklabelcolor=:gray31, ), - Axis3 = ( - xgridcolor = :white, - ygridcolor = :white, - zgridcolor = :white, - xspinesvisible = false, - yspinesvisible = false, - zspinesvisible = false, - yzpanelcolor = :gray92, - xzpanelcolor = :gray92, - xypanelcolor = :gray92, - xticklabelcolor = :gray31, - yticklabelcolor = :gray31, - zticklabelcolor = :gray31, - ), - Colorbar = ( - tickcolor = :white, - tickalign = 1, - ticklabelcolor = :gray31, - spinewidth = 0, - ticklabelpad = 5, - ) + Colorbar=(tickcolor=:white, tickalign=1, ticklabelcolor=:gray31, spinewidth=0, ticklabelpad=5), ) end diff --git a/src/themes/theme_light.jl b/src/themes/theme_light.jl index 83bc2313207..5bdc82f7400 100644 --- a/src/themes/theme_light.jl +++ b/src/themes/theme_light.jl @@ -1,40 +1,33 @@ function theme_light() - Theme( - textcolor = :gray50, - Axis = ( - backgroundcolor = :transparent, - xgridcolor = (:black, 0.07), - ygridcolor = (:black, 0.07), - leftspinevisible = false, - rightspinevisible = false, - bottomspinevisible = false, - topspinevisible = false, - xminorticksvisible = false, - yminorticksvisible = false, - xticksvisible = false, - yticksvisible = false, - xlabelpadding = 3, - ylabelpadding = 3 + return Theme( + textcolor=:gray50, + Axis=( + backgroundcolor=:transparent, + xgridcolor=(:black, 0.07), + ygridcolor=(:black, 0.07), + leftspinevisible=false, + rightspinevisible=false, + bottomspinevisible=false, + topspinevisible=false, + xminorticksvisible=false, + yminorticksvisible=false, + xticksvisible=false, + yticksvisible=false, + xlabelpadding=3, + ylabelpadding=3, ), - Legend = ( - framevisible = false, - padding = (0, 0, 0, 0), + Legend=(framevisible=false, padding=(0, 0, 0, 0)), + Axis3=( + xgridcolor=(:black, 0.07), + ygridcolor=(:black, 0.07), + zgridcolor=(:black, 0.07), + xspinesvisible=false, + yspinesvisible=false, + zspinesvisible=false, + xticksvisible=false, + yticksvisible=false, + zticksvisible=false, ), - Axis3 = ( - xgridcolor = (:black, 0.07), - ygridcolor = (:black, 0.07), - zgridcolor = (:black, 0.07), - xspinesvisible = false, - yspinesvisible = false, - zspinesvisible = false, - xticksvisible = false, - yticksvisible = false, - zticksvisible = false, - ), - Colorbar = ( - ticksvisible = false, - spinewidth = 0, - ticklabelpad = 5, - ) + Colorbar=(ticksvisible=false, spinewidth=0, ticklabelpad=5), ) end diff --git a/src/themes/theme_minimal.jl b/src/themes/theme_minimal.jl index 4c3ac1af7e6..23ede359b42 100644 --- a/src/themes/theme_minimal.jl +++ b/src/themes/theme_minimal.jl @@ -1,53 +1,46 @@ function theme_minimal() - Theme( - Axis = ( - backgroundcolor = :transparent, - xgridvisible = false, - ygridvisible = false, - xminorgridvisible = false, - yminorgridvisible = false, - leftspinevisible = true, - rightspinevisible = false, - bottomspinevisible = true, - topspinevisible = false, - xminorticksvisible = false, - yminorticksvisible = false, - xticksvisible = false, - yticksvisible = false, - xlabelpadding = 3, - ylabelpadding = 3 + return Theme( + Axis=( + backgroundcolor=:transparent, + xgridvisible=false, + ygridvisible=false, + xminorgridvisible=false, + yminorgridvisible=false, + leftspinevisible=true, + rightspinevisible=false, + bottomspinevisible=true, + topspinevisible=false, + xminorticksvisible=false, + yminorticksvisible=false, + xticksvisible=false, + yticksvisible=false, + xlabelpadding=3, + ylabelpadding=3, ), - Legend = ( - framevisible = false, - padding = (0, 0, 0, 0), + Legend=(framevisible=false, padding=(0, 0, 0, 0)), + Axis3=( + xgridvisible=false, + ygridvisible=false, + zgridvisible=false, + xspinesvisible=true, + yspinesvisible=true, + zspinesvisible=true, + yzpanelvisible=false, + xzpanelvisible=false, + xypanelvisible=false, + xticksvisible=false, + yticksvisible=false, + zticksvisible=false, + xticklabelpad=3, + yticklabelpad=3, + zticklabelpad=6, + xspinecolor_2=:transparent, + xspinecolor_3=:transparent, + yspinecolor_2=:transparent, + yspinecolor_3=:transparent, + zspinecolor_2=:transparent, + zspinecolor_3=:transparent, ), - Axis3 = ( - xgridvisible = false, - ygridvisible = false, - zgridvisible = false, - xspinesvisible = true, - yspinesvisible = true, - zspinesvisible = true, - yzpanelvisible = false, - xzpanelvisible = false, - xypanelvisible = false, - xticksvisible = false, - yticksvisible = false, - zticksvisible = false, - xticklabelpad = 3, - yticklabelpad = 3, - zticklabelpad = 6, - xspinecolor_2 = :transparent, - xspinecolor_3 = :transparent, - yspinecolor_2 = :transparent, - yspinecolor_3 = :transparent, - zspinecolor_2 = :transparent, - zspinecolor_3 = :transparent, - ), - Colorbar = ( - ticksvisible = false, - spinewidth = 0, - ticklabelpad = 5, - ) + Colorbar=(ticksvisible=false, spinewidth=0, ticklabelpad=5), ) end diff --git a/src/theming.jl b/src/theming.jl index 7193ef849de..822deaf5ccc 100644 --- a/src/theming.jl +++ b/src/theming.jl @@ -4,15 +4,15 @@ if Sys.iswindows() function primary_resolution() dc = ccall((:GetDC, :user32), Ptr{Cvoid}, (Ptr{Cvoid},), C_NULL) ntuple(2) do i - Int(ccall((:GetDeviceCaps, :gdi32), Cint, (Ptr{Cvoid}, Cint), dc, (2 - i) + 117)) + return Int(ccall((:GetDeviceCaps, :gdi32), Cint, (Ptr{Cvoid}, Cint), dc, (2 - i) + 117)) end end elseif Sys.isapple() const _CoreGraphics = "CoreGraphics.framework/CoreGraphics" function primary_resolution() - dispid = ccall((:CGMainDisplayID, _CoreGraphics), UInt32,()) - height = ccall((:CGDisplayPixelsHigh,_CoreGraphics), Int, (UInt32,), dispid) - width = ccall((:CGDisplayPixelsWide,_CoreGraphics), Int, (UInt32,), dispid) + dispid = ccall((:CGMainDisplayID, _CoreGraphics), UInt32, ()) + height = ccall((:CGDisplayPixelsHigh, _CoreGraphics), Int, (UInt32,), dispid) + width = ccall((:CGDisplayPixelsWide, _CoreGraphics), Int, (UInt32,), dispid) return (width, height) end else @@ -26,132 +26,118 @@ If the primary monitor can't be accessed, returns (1920, 1080) (full hd) """ function primary_resolution end - #= Conservative 7-color palette from Points of view: Color blindness, Bang Wong - Nature Methods https://www.nature.com/articles/nmeth.1618?WT.ec_id=NMETH-201106 =# -function wong_colors(alpha = 1.0) +function wong_colors(alpha=1.0) colors = [ - RGB(0/255, 114/255, 178/255), # blue - RGB(230/255, 159/255, 0/255), # orange - RGB(0/255, 158/255, 115/255), # green - RGB(204/255, 121/255, 167/255), # reddish purple - RGB(86/255, 180/255, 233/255), # sky blue - RGB(213/255, 94/255, 0/255), # vermillion - RGB(240/255, 228/255, 66/255), # yellow + RGB(0 / 255, 114 / 255, 178 / 255), # blue + RGB(230 / 255, 159 / 255, 0 / 255), # orange + RGB(0 / 255, 158 / 255, 115 / 255), # green + RGB(204 / 255, 121 / 255, 167 / 255), # reddish purple + RGB(86 / 255, 180 / 255, 233 / 255), # sky blue + RGB(213 / 255, 94 / 255, 0 / 255), # vermillion + RGB(240 / 255, 228 / 255, 66 / 255), # yellow ] @. RGBAf(red(colors), green(colors), blue(colors), alpha) end const default_palettes = Attributes( - color = wong_colors(1), - patchcolor = Makie.wong_colors(0.8), - marker = [:circle, :utriangle, :cross, :rect, :diamond, :dtriangle, :pentagon, :xcross], - linestyle = [nothing, :dash, :dot, :dashdot, :dashdotdot], - side = [:left, :right] + color=wong_colors(1), + patchcolor=Makie.wong_colors(0.8), + marker=[:circle, :utriangle, :cross, :rect, :diamond, :dtriangle, :pentagon, :xcross], + linestyle=[nothing, :dash, :dot, :dashdot, :dashdotdot], + side=[:left, :right], ) const minimal_default = Attributes( - palette = default_palettes, - font = :regular, - fonts = Attributes( + palette=default_palettes, + font=:regular, + fonts=Attributes( :regular => "TeX Gyre Heros Makie", :bold => "TeX Gyre Heros Makie Bold", :italic => "TeX Gyre Heros Makie Italic", :bold_italic => "TeX Gyre Heros Makie Bold Italic", ), - fontsize = 16, - textcolor = :black, - padding = Vec3f(0.05), - figure_padding = 16, - rowgap = 24, - colgap = 24, - backgroundcolor = :white, - colormap = :viridis, - marker = :circle, - markersize = 12, - markercolor = :black, - markerstrokecolor = :black, - markerstrokewidth = 0, - linecolor = :black, - linewidth = 1.5, - linestyle = nothing, - patchcolor = RGBAf(0, 0, 0, 0.6), - patchstrokecolor = :black, - patchstrokewidth = 0, - resolution = (800, 600), # 4/3 aspect ratio - visible = true, - axis = Attributes(), - axis3d = Attributes(), - legend = Attributes(), - axis_type = automatic, - camera = automatic, - limits = automatic, - SSAO = Attributes( + fontsize=16, + textcolor=:black, + padding=Vec3f(0.05), + figure_padding=16, + rowgap=24, + colgap=24, + backgroundcolor=:white, + colormap=:viridis, + marker=:circle, + markersize=12, + markercolor=:black, + markerstrokecolor=:black, + markerstrokewidth=0, + linecolor=:black, + linewidth=1.5, + linestyle=nothing, + patchcolor=RGBAf(0, 0, 0, 0.6), + patchstrokecolor=:black, + patchstrokewidth=0, + resolution=(800, 600), # 4/3 aspect ratio + visible=true, + axis=Attributes(), + axis3d=Attributes(), + legend=Attributes(), + axis_type=automatic, + camera=automatic, + limits=automatic, + SSAO=Attributes( # enable = false, - bias = 0.025f0, # z threshhold for occlusion - radius = 0.5f0, # range of sample positions (in world space) - blur = Int32(2), # A (2blur+1) by (2blur+1) range is used for blurring + bias=0.025f0, # z threshhold for occlusion + radius=0.5f0, # range of sample positions (in world space) + blur=Int32(2), # A (2blur+1) by (2blur+1) range is used for blurring # N_samples = 64, # number of samples (requires shader reload) ), - ambient = RGBf(0.55, 0.55, 0.55), - lightposition = :eyeposition, - inspectable = true, - - CairoMakie = Attributes( - px_per_unit = 1.0, - pt_per_unit = 0.75, - antialias = :best, - visible = true, - start_renderloop = false + ambient=RGBf(0.55, 0.55, 0.55), + lightposition=:eyeposition, + inspectable=true, + CairoMakie=Attributes( + px_per_unit=1.0, + pt_per_unit=0.75, + antialias=:best, + visible=true, + start_renderloop=false, ), - - GLMakie = Attributes( + GLMakie=Attributes( # Renderloop - renderloop = automatic, - pause_renderloop = false, - vsync = false, - render_on_demand = true, - framerate = 30.0, + renderloop=automatic, + pause_renderloop=false, + vsync=false, + render_on_demand=true, + framerate=30.0, # GLFW window attributes - float = false, - focus_on_show = false, - decorated = true, - title = "Makie", - fullscreen = false, - debugging = false, - monitor = nothing, + float=false, + focus_on_show=false, + decorated=true, + title="Makie", + fullscreen=false, + debugging=false, + monitor=nothing, # Postproccessor - oit = true, - fxaa = true, - ssao = false, + oit=true, + fxaa=true, + ssao=false, # This adjusts a factor in the rendering shaders for order independent # transparency. This should be the same for all of them (within one rendering # pipeline) otherwise depth "order" will be broken. - transparency_weight_scale = 1000f0 - ), - - WGLMakie = Attributes( - framerate = 30.0 + transparency_weight_scale=1000.0f0, ), - - RPRMakie = Attributes( - iterations = 200, - resource = automatic, - plugin = automatic, - max_recursion = 10 - ) + WGLMakie=Attributes(framerate=30.0), + RPRMakie=Attributes(iterations=200, resource=automatic, plugin=automatic, max_recursion=10), ) const CURRENT_DEFAULT_THEME = deepcopy(minimal_default) -function current_default_theme(; kw_args...) - return merge!(Attributes(kw_args), deepcopy(CURRENT_DEFAULT_THEME)) -end +current_default_theme(; kw_args...) = merge!(Attributes(kw_args), deepcopy(CURRENT_DEFAULT_THEME)) """ set_theme(theme; kwargs...) @@ -159,7 +145,7 @@ end Set the global default theme to `theme` and add / override any attributes given as keyword arguments. """ -function set_theme!(new_theme = Theme()::Attributes; kwargs...) +function set_theme!(new_theme=Theme()::Attributes; kwargs...) empty!(CURRENT_DEFAULT_THEME) new_theme = merge!(deepcopy(new_theme), deepcopy(minimal_default)) new_theme = merge!(Theme(kwargs), new_theme) @@ -183,7 +169,7 @@ with_theme(my_theme, color = :blue, linestyle = :dashed) do end ``` """ -function with_theme(f, theme = Theme(); kwargs...) +function with_theme(f, theme=Theme(); kwargs...) previous_theme = Makie.current_default_theme() try set_theme!(theme; kwargs...) @@ -210,21 +196,18 @@ end Updates the current theme incrementally, that means only the keys given in `with_theme` or through keyword arguments are changed, the rest is left intact. Nested attributes are either also updated incrementally, or replaced if they are not attributes in the new theme. """ -function update_theme!(with_theme = Theme()::Attributes; kwargs...) +function update_theme!(with_theme=Theme()::Attributes; kwargs...) new_theme = merge!(with_theme, Theme(kwargs)) _update_attrs!(CURRENT_DEFAULT_THEME, new_theme) return end -function _update_attrs!(attrs1, attrs2) +_update_attrs!(attrs1, attrs2) = for (key, value) in attrs2 _update_key!(attrs1, key, value) end -end -function _update_key!(theme, key::Symbol, content) - theme[key] = content -end +_update_key!(theme, key::Symbol, content) = theme[key] = content function _update_key!(theme, key::Symbol, content::Attributes) if haskey(theme, key) && theme[key] isa Attributes @@ -232,5 +215,5 @@ function _update_key!(theme, key::Symbol, content::Attributes) else theme[key] = content end - theme + return theme end diff --git a/src/types.jl b/src/types.jl index c28e74df6a8..f80ed920c42 100644 --- a/src/types.jl +++ b/src/types.jl @@ -14,7 +14,6 @@ end include("interaction/iodevices.jl") - """ This struct provides accessible `Observable`s to monitor the events associated with a Scene. @@ -67,11 +66,11 @@ struct Events The position of the mouse as a `NTuple{2, Float64}`. Updates once per event poll/frame. """ - mouseposition::Observable{NTuple{2, Float64}} # why no Vec2? + mouseposition::Observable{NTuple{2,Float64}} # why no Vec2? """ The direction of scroll """ - scroll::Observable{NTuple{2, Float64}} # why no Vec2? + scroll::Observable{NTuple{2,Float64}} # why no Vec2? """ Most recently triggered `KeyEvent`. Contains the relevant `event.key` and @@ -118,12 +117,10 @@ function Events() Observable(Recti(0, 0, 0, 0)), Observable(100.0), Observable(false), - Observable(MouseButtonEvent(Mouse.none, Mouse.release)), Set{Mouse.Button}(), Observable((0.0, 0.0)), Observable((0.0, 0.0)), - Observable(KeyEvent(Keyboard.unknown, Keyboard.release)), Set{Keyboard.Button}(), Observable('\0'), @@ -137,7 +134,7 @@ function Events() end function connect_states!(e::Events) - on(e.mousebutton, priority = typemax(Int)) do event + on(e.mousebutton, priority=typemax(Int)) do event set = e.mousebuttonstate if event.action == Mouse.press push!(set, event.button) @@ -150,7 +147,7 @@ function connect_states!(e::Events) return Consume(false) end - on(e.keyboardbutton, priority = typemax(Int)) do event + on(e.keyboardbutton, priority=typemax(Int)) do event set = e.keyboardstate if event.key != Keyboard.unknown if event.action == Keyboard.press @@ -172,11 +169,17 @@ end # Compat only function Base.getproperty(e::Events, field::Symbol) if field === :mousebuttons - error("`events.mousebuttons` is deprecated. Use `events.mousebutton` to react to `MouseButtonEvent`s instead.") + error( + "`events.mousebuttons` is deprecated. Use `events.mousebutton` to react to `MouseButtonEvent`s instead.", + ) elseif field === :keyboardbuttons - error("`events.keyboardbuttons` is deprecated. Use `events.keyboardbutton` to react to `KeyEvent`s instead.") + error( + "`events.keyboardbuttons` is deprecated. Use `events.keyboardbutton` to react to `KeyEvent`s instead.", + ) elseif field === :mousedrag - error("`events.mousedrag` is deprecated. Use `events.mousebutton` or a mouse state machine (`addmouseevents!`) instead.") + error( + "`events.mousedrag` is deprecated. Use `events.mousebutton` or a mouse state machine (`addmouseevents!`) instead.", + ) else return getfield(e, field) end @@ -194,7 +197,6 @@ function Base.empty!(events::Events) return end - """ Camera(pixel_area) @@ -253,10 +255,7 @@ struct Transformation <: Transformable # data conversion observable, for e.g. log / log10 etc transform_func::Observable{Any} function Transformation(translation, scale, rotation, model, transform_func) - return new( - RefValue{Transformation}(), - translation, scale, rotation, model, transform_func - ) + return new(RefValue{Transformation}(), translation, scale, rotation, model, transform_func) end end @@ -277,27 +276,28 @@ PlotSpec(args...; kwargs...) = PlotSpec{Combined{Any}}(args...; kwargs...) Base.getindex(p::PlotSpec, i::Int) = getindex(p.args, i) Base.getindex(p::PlotSpec, i::Symbol) = getproperty(p.kwargs, i) -to_plotspec(::Type{P}, args; kwargs...) where {P} = - PlotSpec{P}(args...; kwargs...) +to_plotspec(::Type{P}, args; kwargs...) where {P} = PlotSpec{P}(args...; kwargs...) -to_plotspec(::Type{P}, p::PlotSpec{S}; kwargs...) where {P, S} = - PlotSpec{plottype(P, S)}(p.args...; p.kwargs..., kwargs...) +function to_plotspec(::Type{P}, p::PlotSpec{S}; kwargs...) where {P,S} + return PlotSpec{plottype(P, S)}(p.args...; p.kwargs..., kwargs...) +end plottype(::PlotSpec{P}) where {P} = P - struct ScalarOrVector{T} - sv::Union{T, Vector{T}} + sv::Union{T,Vector{T}} end -Base.convert(::Type{<:ScalarOrVector}, v::AbstractVector{T}) where T = ScalarOrVector{T}(collect(v)) -Base.convert(::Type{<:ScalarOrVector}, x::T) where T = ScalarOrVector{T}(x) -Base.convert(::Type{<:ScalarOrVector{T}}, x::ScalarOrVector{T}) where T = x +Base.convert(::Type{<:ScalarOrVector}, v::AbstractVector{T}) where {T} = ScalarOrVector{T}(collect(v)) +Base.convert(::Type{<:ScalarOrVector}, x::T) where {T} = ScalarOrVector{T}(x) +Base.convert(::Type{<:ScalarOrVector{T}}, x::ScalarOrVector{T}) where {T} = x function collect_vector(sv::ScalarOrVector, n::Int) if sv.sv isa Vector if length(sv.sv) != n - error("Requested collected vector with $n elements, contained vector had $(length(sv.sv)) elements.") + error( + "Requested collected vector with $n elements, contained vector had $(length(sv.sv)) elements.", + ) end sv.sv else @@ -355,9 +355,17 @@ struct GlyphCollection strokecolors::ScalarOrVector{RGBAf} strokewidths::ScalarOrVector{Float32} - function GlyphCollection(glyphs, fonts, origins, extents, scales, rotations, - colors, strokecolors, strokewidths) - + function GlyphCollection( + glyphs, + fonts, + origins, + extents, + scales, + rotations, + colors, + strokecolors, + strokewidths, + ) n = length(glyphs) @assert length(fonts) == n @assert length(origins) == n @@ -371,10 +379,9 @@ struct GlyphCollection colors = convert_attribute(colors, key"color"()) strokecolors = convert_attribute(strokecolors, key"color"()) strokewidths = Float32.(strokewidths) - new(glyphs, fonts, origins, extents, scales, rotations, colors, strokecolors, strokewidths) + return new(glyphs, fonts, origins, extents, scales, rotations, colors, strokecolors, strokewidths) end end - # The color type we ideally use for most color attributes -const RGBColors = Union{RGBAf, Vector{RGBAf}, Vector{Float32}} +const RGBColors = Union{RGBAf,Vector{RGBAf},Vector{Float32}} diff --git a/src/units.jl b/src/units.jl index d93d71f8331..e6387e89ff4 100644 --- a/src/units.jl +++ b/src/units.jl @@ -17,16 +17,14 @@ # struct DIP <: DisplaySpace end ######### -function to_screen(scene::Scene, mpos) - return Point2f(mpos) .- Point2f(minimum(pixelarea(scene)[])) -end +to_screen(scene::Scene, mpos) = Point2f(mpos) .- Point2f(minimum(pixelarea(scene)[])) number(x::Unit) = x.value number(x) = x Base.:(*)(a::T, b::Number) where {T<:Unit} = basetype(T)(number(a) * b) Base.:(*)(a::Number, b::T) where {T<:Unit} = basetype(T)(a * number(b)) -Base.convert(::Type{T}, x::Unit) where T<:Number = convert(T, number(x)) +Base.convert(::Type{T}, x::Unit) where {T<:Number} = convert(T, number(x)) """ Unit space of the scene it's displayed on. @@ -43,17 +41,17 @@ physical unit of measurement based on a coordinate system held by a computer and represents an abstraction of a pixel for use by an application that an underlying system then converts to physical pixels. """ -struct DeviceIndependentPixel{T <: Number} <: Unit{T} +struct DeviceIndependentPixel{T<:Number} <: Unit{T} value::T end -basetype(::Type{<: DeviceIndependentPixel}) = DeviceIndependentPixel +basetype(::Type{<:DeviceIndependentPixel}) = DeviceIndependentPixel const DIP = DeviceIndependentPixel const dip = DIP(1) const dip_in_millimeter = 0.15875 -const dip_in_inch = 1/160 +const dip_in_inch = 1 / 160 -basetype(::Type{<: Pixel}) = Pixel +basetype(::Type{<:Pixel}) = Pixel """ Millimeter on screen. This unit respects the dimension and pixel density of the screen @@ -64,7 +62,7 @@ a camera can change the actually displayed dimensions of any object using the mi struct Millimeter{T} <: Unit{T} value::T end -basetype(::Type{<: Millimeter}) = Millimeter +basetype(::Type{<:Millimeter}) = Millimeter const mm = Millimeter(1) Base.show(io::IO, x::DIP) = print(io, number(x), "dip") @@ -72,55 +70,51 @@ Base.:(*)(a::Number, b::DIP) = DIP(a * number(b)) dpi(scene::Scene) = events(scene).window_dpi[] -function pixel_per_mm(scene) - dpi(scene) ./ 25.4 -end +pixel_per_mm(scene) = dpi(scene) ./ 25.4 -function Base.convert(::Type{<: Millimeter}, scene::Scene, x::SceneSpace) +function Base.convert(::Type{<:Millimeter}, scene::Scene, x::SceneSpace) pixel = convert(Pixel, scene, x) - Millimeter(number(pixel_per_mm(scene) / pixel)) + return Millimeter(number(pixel_per_mm(scene) / pixel)) end -function Base.convert(::Type{<: SceneSpace}, scene::Scene, x::DIP) +function Base.convert(::Type{<:SceneSpace}, scene::Scene, x::DIP) mm = convert(Millimeter, scene, x) - SceneSpace(number(mm * dip_in_millimeter)) + return SceneSpace(number(mm * dip_in_millimeter)) end -function Base.convert(::Type{<: Millimeter}, scene::Scene, x::DIP) - Millimeter(number(x * dip_in_millimeter)) -end +Base.convert(::Type{<:Millimeter}, scene::Scene, x::DIP) = Millimeter(number(x * dip_in_millimeter)) -function Base.convert(::Type{<: Pixel}, scene::Scene, x::Millimeter) +function Base.convert(::Type{<:Pixel}, scene::Scene, x::Millimeter) px = pixel_per_mm(scene) * x - Pixel(number(px)) + return Pixel(number(px)) end -function Base.convert(::Type{<: Pixel}, scene::Scene, x::DIP) +function Base.convert(::Type{<:Pixel}, scene::Scene, x::DIP) inch = (x * dip_in_inch) dots = dpi(scene) * inch - Pixel(number(dots)) + return Pixel(number(dots)) end -function Base.convert(::Type{<: SceneSpace}, scene::Scene, x::Vec{2, <:Pixel}) +function Base.convert(::Type{<:SceneSpace}, scene::Scene, x::Vec{2,<:Pixel}) zero = to_world(scene, to_screen(scene, Point2f(0))) s = to_world(scene, to_screen(scene, number.(Point(x)))) - SceneSpace.(Vec(s .- zero)) + return SceneSpace.(Vec(s .- zero)) end -function Base.convert(::Type{<: SceneSpace}, scene::Scene, x::Pixel) +function Base.convert(::Type{<:SceneSpace}, scene::Scene, x::Pixel) zero = to_world(scene, to_screen(scene, Point2f(0))) s = to_world(scene, to_screen(scene, Point2f(number(x), 0.0))) - SceneSpace(norm(s .- zero)) + return SceneSpace(norm(s .- zero)) end -function Base.convert(::Type{<: SceneSpace}, scene::Scene, x::Millimeter) +function Base.convert(::Type{<:SceneSpace}, scene::Scene, x::Millimeter) pix = convert(Pixel, scene, x) - (SceneSpace, mm) + return (SceneSpace, mm) end to_2d_scale(x::Pixel) = Vec2f(number(x)) -to_2d_scale(x::Tuple{<:Pixel, <:Pixel}) = Vec2f(number.(x)) -to_2d_scale(x::VecTypes{2, <:Pixel}) = Vec2f(number.(x)) +to_2d_scale(x::Tuple{<:Pixel,<:Pixel}) = Vec2f(number.(x)) +to_2d_scale(x::VecTypes{2,<:Pixel}) = Vec2f(number.(x)) # Exports of units export px diff --git a/src/utilities/quaternions.jl b/src/utilities/quaternions.jl index bcae57f50de..8ca6eaa9b14 100644 --- a/src/utilities/quaternions.jl +++ b/src/utilities/quaternions.jl @@ -5,34 +5,34 @@ # TODO replace this file by just `using Quaternions` struct Quaternion{T} - data::NTuple{4, T} - Quaternion{T}(x::NTuple{4, Any}) where T = new{T}(T.(x)) - Quaternion{T}(x::NTuple{4, T}) where T = new{T}(x) + data::NTuple{4,T} + Quaternion{T}(x::NTuple{4,Any}) where {T} = new{T}(T.(x)) + Quaternion{T}(x::NTuple{4,T}) where {T} = new{T}(x) end -Base.eltype(::Quaternion{T}) where T = T -Base.eltype(::Type{Quaternion{T}}) where T = T -Base.length(::Type{<: Quaternion}) = 4 +Base.eltype(::Quaternion{T}) where {T} = T +Base.eltype(::Type{Quaternion{T}}) where {T} = T +Base.length(::Type{<:Quaternion}) = 4 Base.length(::Quaternion) = 4 const Quaternionf = Quaternion{Float32} -const SMat{N, L} = Mat{N, N, T, L} where T +const SMat{N,L} = Mat{N,N,T,L} where {T} function Base.show(io::IO, q::Quaternion) pm(x) = x < 0 ? " - $(-x)" : " + $x" - print(io, q[4], pm(q[1]), "im", pm(q[2]), "jm", pm(q[3]), "km") + return print(io, q[4], pm(q[1]), "im", pm(q[2]), "jm", pm(q[3]), "km") end Random.rand(mt::AbstractRNG, ::Random.SamplerType{Quaternion}) = rand(mt, Quaternion{Float64}) -Random.rand(mt::AbstractRNG, ::Random.SamplerType{Quaternion{T}}) where T = Quaternion(rand(mt, T), rand(mt, T), rand(mt, T), 1.0) - -Quaternion{T}(x1, x2, x3, s) where T = Quaternion{T}((x1, x2, x3, s)) -Base.convert(T::Type{<: Quaternion}, x::NTuple{4, Any}) = T(x) -function Base.convert(T::Type{Quaternion{T1}}, x::Quaternion{T2}) where {T1, T2} - T(T2.(x.data)) +function Random.rand(mt::AbstractRNG, ::Random.SamplerType{Quaternion{T}}) where {T} + return Quaternion(rand(mt, T), rand(mt, T), rand(mt, T), 1.0) end + +Quaternion{T}(x1, x2, x3, s) where {T} = Quaternion{T}((x1, x2, x3, s)) +Base.convert(T::Type{<:Quaternion}, x::NTuple{4,Any}) = T(x) +Base.convert(T::Type{Quaternion{T1}}, x::Quaternion{T2}) where {T1,T2} = T(T2.(x.data)) Quaternion(x1, x2, x3, s) = Quaternion(promote(x1, x2, x3, s)) -Quaternion(x::NTuple{4, T}) where T = Quaternion{T}(x) +Quaternion(x::NTuple{4,T}) where {T} = Quaternion{T}(x) Base.getindex(x::Quaternion, i::Integer) = x.data[i] Base.isapprox(x::Quaternion, y::Quaternion) = all((x.data .≈ y.data)) @@ -42,9 +42,7 @@ function qrotation(axis::StaticVector{3}, theta::Number) return Quaternion(s * u[1], s * u[2], s * u[3], cos(theta / 2)) end -function Base.broadcast(f, arg1::Quaternion, arg2::Quaternion) - Quaternion(f.(arg1.data, arg2.data)) -end +Base.broadcast(f, arg1::Quaternion, arg2::Quaternion) = Quaternion(f.(arg1.data, arg2.data)) Base.abs(q::Quaternion) = sqrt(sum(q.data .^ 2)) @@ -52,13 +50,13 @@ LinearAlgebra.normalize(q::Quaternion) = q / abs(q) Base.:(/)(q::Quaternion, x::Real) = Quaternion(q[1] / x, q[2] / x, q[3] / x, q[4] / x) -function Base.:(*)(quat::Quaternion, vec::P) where {P <: StaticVector{2}} +function Base.:(*)(quat::Quaternion, vec::P) where {P<:StaticVector{2}} T = eltype(vec) x3 = quat * Vec(vec[1], vec[2], T(0)) return P(x3[1], x3[2]) end -function Base.:(*)(quat::Quaternion{T}, vec::P) where {T, P <: StaticVector{3}} +function Base.:(*)(quat::Quaternion{T}, vec::P) where {T,P<:StaticVector{3}} num = quat[1] * T(2) num2 = quat[2] * T(2) num3 = quat[3] * T(2) @@ -76,9 +74,9 @@ function Base.:(*)(quat::Quaternion{T}, vec::P) where {T, P <: StaticVector{3}} num12 = quat[4] * num3 return P( - (1f0 - (num5 + num6)) * vec[1] + (num7 - num12) * vec[2] + (num8 + num11) * vec[3], - (num7 + num12) * vec[1] + (1f0 - (num4 + num6)) * vec[2] + (num9 - num10) * vec[3], - (num8 - num11) * vec[1] + (num9 + num10) * vec[2] + (1f0 - (num4 + num5)) * vec[3] + (1.0f0 - (num5 + num6)) * vec[1] + (num7 - num12) * vec[2] + (num8 + num11) * vec[3], + (num7 + num12) * vec[1] + (1.0f0 - (num4 + num6)) * vec[2] + (num9 - num10) * vec[3], + (num8 - num11) * vec[1] + (num9 + num10) * vec[2] + (1.0f0 - (num4 + num5)) * vec[3], ) end Base.conj(q::Quaternion) = Quaternion(-q[1], -q[2], -q[3], q[4]) @@ -92,45 +90,63 @@ function Base.:(*)(q::Quaternion, w::Quaternion) ) end -SMat{N, L}(q::Quaternion{T}) where {N, T, L} = Mat{N, N, T, L}(q) +SMat{N,L}(q::Quaternion{T}) where {N,T,L} = Mat{N,N,T,L}(q) -function Mat4{ET}(q::Quaternion{T}) where {T, ET} - sx, sy, sz = 2q[4]*q[1], 2q[4]*q[2], 2q[4]*q[3] - xx, xy, xz = 2q[1]^2, 2q[1]*q[2], 2q[1]*q[3] - yy, yz, zz = 2q[2]^2, 2q[2]*q[3], 2q[3]^2 +function Mat4{ET}(q::Quaternion{T}) where {T,ET} + sx, sy, sz = 2q[4] * q[1], 2q[4] * q[2], 2q[4] * q[3] + xx, xy, xz = 2q[1]^2, 2q[1] * q[2], 2q[1] * q[3] + yy, yz, zz = 2q[2]^2, 2q[2] * q[3], 2q[3]^2 T0, T1 = zero(ET), one(ET) - return Mat{4, 4, ET}( - T1-(yy+zz), xy+sz, xz-sy, T0, - xy-sz, T1-(xx+zz), yz+sx, T0, - xz+sy, yz-sx, T1-(xx+yy), T0, - T0, T0, T0, T1 + return Mat{4,4,ET}( + T1 - (yy + zz), + xy + sz, + xz - sy, + T0, + xy - sz, + T1 - (xx + zz), + yz + sx, + T0, + xz + sy, + yz - sx, + T1 - (xx + yy), + T0, + T0, + T0, + T0, + T1, ) end -concrete_type(::Type{Any}, ::Type{T}) where T = T -concrete_type(::Type{T}, x) where T = T +concrete_type(::Type{Any}, ::Type{T}) where {T} = T +concrete_type(::Type{T}, x) where {T} = T -function Mat3{ET}(q::Quaternion{T}) where {T, ET} - sx, sy, sz = 2q[4]*q[1], 2q[4]*q[2], 2q[4]*q[3] - xx, xy, xz = 2q[1]^2, 2q[1]*q[2], 2q[1]*q[3] - yy, yz, zz = 2q[2]^2, 2q[2]*q[3], 2q[3]^2 +function Mat3{ET}(q::Quaternion{T}) where {T,ET} + sx, sy, sz = 2q[4] * q[1], 2q[4] * q[2], 2q[4] * q[3] + xx, xy, xz = 2q[1]^2, 2q[1] * q[2], 2q[1] * q[3] + yy, yz, zz = 2q[2]^2, 2q[2] * q[3], 2q[3]^2 T0, T1 = zero(ET), one(ET) - return Mat{3, 3, ET}( - T1-(yy+zz), xy+sz, xz-sy, - xy-sz, T1-(xx+zz), yz+sx, - xz+sy, yz-sx, T1-(xx+yy) + return Mat{3,3,ET}( + T1 - (yy + zz), + xy + sz, + xz - sy, + xy - sz, + T1 - (xx + zz), + yz + sx, + xz + sy, + yz - sx, + T1 - (xx + yy), ) end -function orthogonal(v::T) where T <: StaticVector{3} +function orthogonal(v::T) where {T<:StaticVector{3}} x, y, z = abs.(v) other = x < y ? (x < z ? unit(T, 1) : unit(T, 3)) : (y < z ? unit(T, 2) : unit(T, 3)) return cross(v, other) end -function rotation_between(u::StaticVector{3, T}, v::StaticVector{3, T}) where T +function rotation_between(u::StaticVector{3,T}, v::StaticVector{3,T}) where {T} k_cos_theta = dot(u, v) - k = sqrt((norm(u) ^ 2) * (norm(v) ^ 2)) + k = sqrt((norm(u)^2) * (norm(v)^2)) if (k_cos_theta / k) ≈ T(-1) # 180 degree rotation around any orthogonal vector return Quaternion(normalize(orthogonal(u))..., T(0)) diff --git a/src/utilities/texture_atlas.jl b/src/utilities/texture_atlas.jl index 3730ab5c65f..5bcba99f230 100644 --- a/src/utilities/texture_atlas.jl +++ b/src/utilities/texture_atlas.jl @@ -2,7 +2,7 @@ struct TextureAtlas rectangle_packer::RectanglePacker{Int32} # hash of what we're rendering to index in `uv_rectangles` - mapping::Dict{UInt32, Int64} + mapping::Dict{UInt32,Int64} data::Matrix{Float16} # rectangles we rendered our glyphs into in normalized uv coordinates uv_rectangles::Vector{Vec4f} @@ -39,7 +39,9 @@ matr = Makie.get_uv_img(atlas, glyph_index, font) scatter(Point2f(0), distancefield=matr, uv_offset_width=Vec4f(0, 0, 1, 1), markersize=100) ``` """ -get_uv_img(atlas::TextureAtlas, glyph, font) = get_uv_img(atlas, primitive_uv_offset_width(atlas, glyph, font)) +function get_uv_img(atlas::TextureAtlas, glyph, font) + return get_uv_img(atlas, primitive_uv_offset_width(atlas, glyph, font)) +end get_uv_img(atlas::TextureAtlas, path) = get_uv_img(atlas, primitive_uv_offset_width(atlas, path, nothing)) function get_uv_img(atlas::TextureAtlas, uv_rect::Vec4f) xmin, ymin, xmax, ymax = round.(Int, uv_rect .* Vec4f(size(atlas)..., size(atlas)...)) @@ -49,14 +51,14 @@ end function TextureAtlas(; resolution=2048, pix_per_glyph=64, glyph_padding=12, downsample=5) return TextureAtlas( RectanglePacker(Rect2{Int32}(0, 0, resolution, resolution)), - Dict{UInt32, Int}(), + Dict{UInt32,Int}(), # We use the maximum distance of a glyph as a background to reduce texture bleed. See #2096 fill(Float16(0.5pix_per_glyph + glyph_padding), resolution, resolution), Vec4f[], pix_per_glyph, glyph_padding, downsample, - Function[] + Function[], ) end @@ -67,7 +69,7 @@ function Base.show(io::IO, atlas::TextureAtlas) println(io, " pix_per_glyph: ", atlas.pix_per_glyph) println(io, " glyph_padding: ", atlas.glyph_padding) println(io, " downsample: ", atlas.downsample) - println(io, " font_render_callback: ", length(atlas.font_render_callback)) + return println(io, " font_render_callback: ", length(atlas.font_render_callback)) end const SERIALIZATION_FORMAT_VERSION = "v1" @@ -75,8 +77,9 @@ const SERIALIZATION_FORMAT_VERSION = "v1" # basically a singleton for the textureatlas function get_cache_path(resolution::Int, pix_per_glyph::Int) path = abspath( - first(Base.DEPOT_PATH), "makie", - "$(SERIALIZATION_FORMAT_VERSION)_texture_atlas_$(resolution)_$(pix_per_glyph).bin" + first(Base.DEPOT_PATH), + "makie", + "$(SERIALIZATION_FORMAT_VERSION)_texture_atlas_$(resolution)_$(pix_per_glyph).bin", ) if !ispath(dirname(path)) mkpath(dirname(path)) @@ -113,7 +116,7 @@ end function write_array(io::IO, array::AbstractArray) write(io, Int32(ndims(array))) write(io, Int32.(size(array))...) - write(io, array) + return write(io, array) end function read_array(io::IO, T) @@ -125,7 +128,7 @@ function read_array(io::IO, T) return array end -function store_texture_atlas(path::AbstractString, atlas::TextureAtlas) +store_texture_atlas(path::AbstractString, atlas::TextureAtlas) = open(path, "w") do io write_node(io, atlas.rectangle_packer) write_array(io, collect(atlas.mapping)) @@ -133,26 +136,34 @@ function store_texture_atlas(path::AbstractString, atlas::TextureAtlas) write_array(io, atlas.uv_rectangles) write(io, atlas.pix_per_glyph) write(io, atlas.glyph_padding) - write(io, atlas.downsample) + return write(io, atlas.downsample) end -end function load_texture_atlas(path::AbstractString) open(path) do io packer = read_node(io, Int32) - mapping = read_array(io, Pair{UInt32, Int64}) + mapping = read_array(io, Pair{UInt32,Int64}) data = read_array(io, Float16) uv_rectangles = read_array(io, Vec4f) pix_per_glyph = read(io, Int32) glyph_padding = read(io, Int32) downsample = read(io, Int32) - return TextureAtlas(packer, Dict(mapping), data, uv_rectangles, pix_per_glyph, glyph_padding, downsample, Function[]) + return TextureAtlas( + packer, + Dict(mapping), + data, + uv_rectangles, + pix_per_glyph, + glyph_padding, + downsample, + Function[], + ) end end -const TEXTURE_ATLASES = Dict{Tuple{Int, Int}, TextureAtlas}() +const TEXTURE_ATLASES = Dict{Tuple{Int,Int},TextureAtlas}() -function get_texture_atlas(resolution::Int = 2048, pix_per_glyph::Int = 64) +function get_texture_atlas(resolution::Int=2048, pix_per_glyph::Int=64) return get!(TEXTURE_ATLASES, (resolution, pix_per_glyph)) do return cached_load(resolution, pix_per_glyph) # initialize only on demand end @@ -167,19 +178,23 @@ function cached_load(resolution::Int, pix_per_glyph::Int) url = CACHE_DOWNLOAD_URL * basename(path) Downloads.download(url, path) catch e - @warn "downloading texture atlas failed, need to re-create from scratch." exception=(e, Base.catch_backtrace()) + @warn "downloading texture atlas failed, need to re-create from scratch." exception = + (e, Base.catch_backtrace()) end end if isfile(path) try return load_texture_atlas(path) catch e - @warn "reading texture atlas on disk failed, need to re-create from scratch." exception=(e, Base.catch_backtrace()) + @warn "reading texture atlas on disk failed, need to re-create from scratch." exception = + (e, Base.catch_backtrace()) rm(path; force=true) end end atlas = TextureAtlas(; resolution=resolution, pix_per_glyph=pix_per_glyph) - @warn("Makie is caching fonts, this may take a while. This should usually not happen, unless you're getting your own texture atlas or are without internet!") + @warn( + "Makie is caching fonts, this may take a while. This should usually not happen, unless you're getting your own texture atlas or are without internet!" + ) render_default_glyphs!(atlas) store_texture_atlas(path, atlas) # cache it return atlas @@ -192,7 +207,7 @@ function defaultfont() if isempty(_default_font) push!(_default_font, to_font("TeX Gyre Heros Makie")) end - _default_font[] + return _default_font[] end function alternativefonts() @@ -203,7 +218,7 @@ function alternativefonts() "NotoSansCJKkr-Regular.otf", "NotoSansCuneiform-Regular.ttf", "NotoSansSymbols-Regular.ttf", - "FiraMono-Medium.ttf" + "FiraMono-Medium.ttf", ] for font in alternatives push!(_alternative_fonts, NativeFont(assetpath("fonts", font))) @@ -233,16 +248,15 @@ function regenerate_texture_atlas(resolution, pix_per_glyph) atlas = TextureAtlas(; resolution=resolution, pix_per_glyph=pix_per_glyph) render_default_glyphs!(atlas) store_texture_atlas(path, atlas) # cache it - atlas + return atlas end function regenerate_texture_atlas() empty!(TEXTURE_ATLASES) TEXTURE_ATLASES[(1024, 32)] = regenerate_texture_atlas(1024, 32) # for WGLMakie - TEXTURE_ATLASES[(2048, 64)] = regenerate_texture_atlas(2048, 64) # for GLMakie + return TEXTURE_ATLASES[(2048, 64)] = regenerate_texture_atlas(2048, 64) # for GLMakie end - """ find_font_for_char(c::Char, font::NativeFont) @@ -259,7 +273,7 @@ function find_font_for_char(glyph, font::NativeFont) return afont end end - error("Can't represent character $(glyph) with any fallback font nor $(font.family_name)!") + return error("Can't represent character $(glyph) with any fallback font nor $(font.family_name)!") end function glyph_index!(atlas::TextureAtlas, glyph, font::NativeFont) @@ -273,17 +287,13 @@ function glyph_index!(atlas::TextureAtlas, glyph, font::NativeFont) return insert_glyph!(atlas, glyph, font) end -function glyph_index!(atlas::TextureAtlas, b::BezierPath) - return insert_glyph!(atlas, b) -end +glyph_index!(atlas::TextureAtlas, b::BezierPath) = insert_glyph!(atlas, b) function glyph_uv_width!(atlas::TextureAtlas, glyph, font::NativeFont) return atlas.uv_rectangles[glyph_index!(atlas, glyph, font)] end -function glyph_uv_width!(atlas::TextureAtlas, b::BezierPath) - return atlas.uv_rectangles[glyph_index!(atlas, b)] -end +glyph_uv_width!(atlas::TextureAtlas, b::BezierPath) = atlas.uv_rectangles[glyph_index!(atlas, b)] function insert_glyph!(atlas::TextureAtlas, glyph, font::NativeFont) glyphindex = FreeTypeAbstraction.glyph_index(font, glyph) @@ -295,8 +305,11 @@ function insert_glyph!(atlas::TextureAtlas, path::BezierPath) return insert_glyph!(atlas, StableHashTraits.stable_hash(path), path) end - -function insert_glyph!(atlas::TextureAtlas, hash::UInt32, path_or_glyp::Union{BezierPath, Tuple{UInt64, NativeFont}}) +function insert_glyph!( + atlas::TextureAtlas, + hash::UInt32, + path_or_glyp::Union{BezierPath,Tuple{UInt64,NativeFont}}, +) return get!(atlas.mapping, hash) do uv_pixel = render(atlas, path_or_glyp) tex_size = Vec2f(size(atlas)) @@ -336,22 +349,18 @@ function sdistancefield(img, downsample, pad) in_or_out = fill(false, dividable_size) # the size we fill the image up to wend, hend = size(img) .+ pad - in_or_out[pad+1:wend, pad+1:hend] .= img .> (0.5 * 255) + in_or_out[(pad + 1):wend, (pad + 1):hend] .= img .> (0.5 * 255) yres, xres = dividable_size .÷ downsample # divide by downsample to normalize distances! return Float32.(sdf(in_or_out, xres, yres) ./ downsample) end -function font_render_callback!(f, atlas::TextureAtlas) - push!(atlas.font_render_callback, f) -end +font_render_callback!(f, atlas::TextureAtlas) = push!(atlas.font_render_callback, f) -function remove_font_render_callback!(atlas::TextureAtlas, f) - filter!(f2-> f2 != f, atlas.font_render_callback) -end +remove_font_render_callback!(atlas::TextureAtlas, f) = filter!(f2 -> f2 != f, atlas.font_render_callback) -function render(atlas::TextureAtlas, (glyph_index, font)::Tuple{UInt64, NativeFont}) +function render(atlas::TextureAtlas, (glyph_index, font)::Tuple{UInt64,NativeFont}) downsample = atlas.downsample pad = atlas.glyph_padding # the target pixel size of our distance field @@ -371,7 +380,9 @@ function render(atlas::TextureAtlas, (glyph_index, font)::Tuple{UInt64, NativeFo sd = sdistancefield(bitmap, downsample, pad) rect = Rect2{Int32}(0, 0, size(sd)...) uv = push!(atlas.rectangle_packer, rect) # find out where to place the rectangle - uv == nothing && error("texture atlas is too small. Resizing not implemented yet. Please file an issue at Makie if you encounter this") #TODO resize surface + uv == nothing && error( + "texture atlas is too small. Resizing not implemented yet. Please file an issue at Makie if you encounter this", + ) #TODO resize surface # write distancefield into texture atlas.data[uv.area] = sd for f in atlas.font_render_callback @@ -397,7 +408,9 @@ function render(atlas::TextureAtlas, b::BezierPath) rect = Rect2{Int32}(0, 0, size(sd)...) uv = push!(atlas.rectangle_packer, rect) # find out where to place the rectangle - uv == nothing && error("texture atlas is too small. Resizing not implemented yet. Please file an issue at Makie if you encounter this") #TODO resize surface + uv == nothing && error( + "texture atlas is too small. Resizing not implemented yet. Please file an issue at Makie if you encounter this", + ) #TODO resize surface # write distancefield into texture atlas.data[uv.area] = sd for f in atlas.font_render_callback @@ -416,9 +429,9 @@ returns the Shape type for the distancefield shader marker_to_sdf_shape(x) = error("$(x) is not a valid scatter marker shape.") marker_to_sdf_shape(::AbstractMatrix) = RECTANGLE # Image marker -marker_to_sdf_shape(::Union{BezierPath, Char}) = DISTANCEFIELD -marker_to_sdf_shape(::Type{T}) where {T <: Circle} = CIRCLE -marker_to_sdf_shape(::Type{T}) where {T <: Rect} = RECTANGLE +marker_to_sdf_shape(::Union{BezierPath,Char}) = DISTANCEFIELD +marker_to_sdf_shape(::Type{T}) where {T<:Circle} = CIRCLE +marker_to_sdf_shape(::Type{T}) where {T<:Rect} = RECTANGLE marker_to_sdf_shape(x::Shape) = x function marker_to_sdf_shape(arr::AbstractVector) @@ -426,32 +439,34 @@ function marker_to_sdf_shape(arr::AbstractVector) shape1 = marker_to_sdf_shape(first(arr)) for elem in arr shape2 = marker_to_sdf_shape(elem) - shape1 !== shape2 && error("Can't use an array of markers that require different primitive_shapes $(typeof.(arr)).") + shape1 !== shape2 && + error("Can't use an array of markers that require different primitive_shapes $(typeof.(arr)).") end return shape1 end -function marker_to_sdf_shape(marker::Observable) - return lift(marker; ignore_equal_values=true) do marker +marker_to_sdf_shape(marker::Observable) = + lift(marker; ignore_equal_values=true) do marker return Cint(marker_to_sdf_shape(to_spritemarker(marker))) end -end """ Extracts the offset from a primitive. """ primitive_offset(x, scale::Nothing) = Vec2f(0) # default offset -primitive_offset(x, scale) = scale ./ -2f0 # default offset +primitive_offset(x, scale) = scale ./ -2.0f0 # default offset """ Extracts the uv offset and width from a primitive. """ -primitive_uv_offset_width(atlas::TextureAtlas, x, font) = Vec4f(0,0,1,1) +primitive_uv_offset_width(atlas::TextureAtlas, x, font) = Vec4f(0, 0, 1, 1) primitive_uv_offset_width(atlas::TextureAtlas, b::BezierPath, font) = glyph_uv_width!(atlas, b) -primitive_uv_offset_width(atlas::TextureAtlas, b::Union{UInt64, Char}, font) = glyph_uv_width!(atlas, b, font) -primitive_uv_offset_width(atlas::TextureAtlas, x::AbstractVector, font) = map(m-> primitive_uv_offset_width(atlas, m, font), x) +primitive_uv_offset_width(atlas::TextureAtlas, b::Union{UInt64,Char}, font) = glyph_uv_width!(atlas, b, font) +function primitive_uv_offset_width(atlas::TextureAtlas, x::AbstractVector, font) + return map(m -> primitive_uv_offset_width(atlas, m, font), x) +end function primitive_uv_offset_width(atlas::TextureAtlas, marker::Observable, font::Observable) - return lift((m, f)-> primitive_uv_offset_width(atlas, m, f), marker, font; ignore_equal_values=true) + return lift((m, f) -> primitive_uv_offset_width(atlas, m, f), marker, font; ignore_equal_values=true) end _bcast(x::Vec) = (x,) @@ -473,21 +488,26 @@ function bezierpath_pad_scale_factor(atlas::TextureAtlas, bp) uv_width = Vec(lbrt[3] - lbrt[1], lbrt[4] - lbrt[2]) full_pixel_size_in_atlas = uv_width * Vec2f(size(atlas)) # left + right pad - cutoff from pixel centering - full_pad = 2f0 * atlas.glyph_padding - 1 + full_pad = 2.0f0 * atlas.glyph_padding - 1 return full_pad ./ (full_pixel_size_in_atlas .- full_pad) end function marker_scale_factor(atlas::TextureAtlas, path::BezierPath) # padded_width = (unpadded_target_width + unpadded_target_width * pad_per_unit) path_width = widths(Makie.bbox(path)) - return (1f0 .+ bezierpath_pad_scale_factor(atlas, path)) .* path_width + return (1.0f0 .+ bezierpath_pad_scale_factor(atlas, path)) .* path_width end function rescale_marker(atlas::TextureAtlas, pathmarker::BezierPath, font, markersize) return markersize .* marker_scale_factor(atlas, pathmarker) end -function rescale_marker(atlas::TextureAtlas, pathmarker::AbstractVector{T}, font, markersize) where T <: BezierPath +function rescale_marker( + atlas::TextureAtlas, + pathmarker::AbstractVector{T}, + font, + markersize, +) where {T<:BezierPath} return _bcast(markersize) .* marker_scale_factor.(Ref(atlas), pathmarker) end @@ -513,11 +533,23 @@ function offset_bezierpath(atlas::TextureAtlas, bp, scale, offset) return offset_bezierpath.(Ref(atlas), bp, _bcast(scale), _bcast(offset)) end -function offset_marker(atlas::TextureAtlas, marker::Union{T, AbstractVector{T}}, font, markersize, markeroffset) where T <: BezierPath +function offset_marker( + atlas::TextureAtlas, + marker::Union{T,AbstractVector{T}}, + font, + markersize, + markeroffset, +) where {T<:BezierPath} return offset_bezierpath(atlas, marker, markersize, markeroffset) end -function offset_marker(atlas::TextureAtlas, marker::Union{T, AbstractVector{T}}, font, markersize, markeroffset) where T <: Char +function offset_marker( + atlas::TextureAtlas, + marker::Union{T,AbstractVector{T}}, + font, + markersize, + markeroffset, +) where {T<:Char} return rescale_marker(atlas, marker, font, markeroffset) end @@ -526,7 +558,8 @@ offset_marker(atlas, marker, font, markersize, markeroffset) = markeroffset function marker_attributes(atlas::TextureAtlas, marker, markersize, font, marker_offset) atlas_obs = Observable(atlas) # for map to work scale = map(rescale_marker, atlas_obs, marker, font, markersize; ignore_equal_values=true) - quad_offset = map(offset_marker, atlas_obs, marker, font, markersize, marker_offset; ignore_equal_values=true) + quad_offset = + map(offset_marker, atlas_obs, marker, font, markersize, marker_offset; ignore_equal_values=true) return scale, quad_offset end diff --git a/src/utilities/utilities.jl b/src/utilities/utilities.jl index d2a92459a3a..ffc560840c6 100644 --- a/src/utilities/utilities.jl +++ b/src/utilities/utilities.jl @@ -1,6 +1,5 @@ - -function to_image(image::AbstractMatrix{<: AbstractFloat}, colormap::AbstractVector{<: Colorant}, colorrange) +function to_image(image::AbstractMatrix{<:AbstractFloat}, colormap::AbstractVector{<:Colorant}, colorrange) return interpolated_getindex.((to_value(colormap),), image, (to_value(colorrange),)) end @@ -13,7 +12,6 @@ function resample(A::AbstractVector, len::Integer) return interpolated_getindex.((A,), range(0.0, stop=1.0, length=len)) end - """ resample_cmap(cmap, ncolors::Integer; alpha=1.0) @@ -24,14 +22,14 @@ end function resample_cmap(cmap, ncolors::Integer; alpha=1.0) cols = to_colormap(cmap) r = range(0.0, stop=1.0, length=ncolors) - if alpha isa Tuple{<:Number, <:Number} + if alpha isa Tuple{<:Number,<:Number} alphas = LinRange(alpha..., ncolors) else alphas = alpha end return broadcast(r, alphas) do i, a c = interpolated_getindex(cols, i) - return RGBAf(Colors.color(c), Colors.alpha(c) * a) + return RGBAf(Colors.color(c), Colors.alpha(c) * a) end end @@ -42,7 +40,7 @@ Resample the color attribute from `attributes`. Resamples `:colormap` if present or repeats `:color`. """ function resampled_colors(attributes, levels::Integer) - cols = if haskey(attributes, :color) + return cols = if haskey(attributes, :color) c = get_attribute(attributes, :color) c isa AbstractVector ? resample(c, levels) : repeated(c, levels) else @@ -51,7 +49,6 @@ function resampled_colors(attributes, levels::Integer) end end - """ Like `get!(f, dict, key)` but also calls `f` and replaces `key` when the corresponding value is nothing @@ -60,7 +57,7 @@ function replace_automatic!(f, dict, key) haskey(dict, key) || return (dict[key] = f()) val = dict[key] to_value(val) == automatic && return (dict[key] = f()) - val + return val end is_unitrange(x) = (false, 0:0) @@ -78,9 +75,9 @@ function is_unitrange(x::AbstractVector) end function ngrid(x::AbstractVector, y::AbstractVector) - xgrid = [Float32(x[i]) for i = 1:length(x), j = 1:length(y)] - ygrid = [Float32(y[j]) for i = 1:length(x), j = 1:length(y)] - xgrid, ygrid + xgrid = [Float32(x[i]) for i in 1:length(x), j in 1:length(y)] + ygrid = [Float32(y[j]) for i in 1:length(x), j in 1:length(y)] + return xgrid, ygrid end function nan_extrema(array) @@ -90,7 +87,7 @@ function nan_extrema(array) mini = min(mini, elem) maxi = max(maxi, elem) end - Vec2f(mini, maxi) + return Vec2f(mini, maxi) end function extract_expr(extract_func, dictlike, args) @@ -102,14 +99,14 @@ function extract_expr(extract_func, dictlike, args) push!(expr.args, :($(esc(elem)) = $(extract_func)($(esc(dictlike)), $(QuoteNode(elem))))) end push!(expr.args, esc(args)) - expr + return expr end """ usage @exctract scene (a, b, c, d) """ macro extract(scene, args) - extract_expr(getindex, scene, args) + return extract_expr(getindex, scene, args) end """ @@ -130,7 +127,7 @@ end ``` """ macro get_attribute(scene, args) - extract_expr(get_attribute, scene, args) + return extract_expr(get_attribute, scene, args) end @inline getindex_value(x::Union{Dict,Attributes,AbstractPlot}, key::Symbol) = to_value(x[key]) @@ -149,10 +146,9 @@ end ``` """ macro extractvalue(scene, args) - extract_expr(getindex_value, scene, args) + return extract_expr(getindex_value, scene, args) end - attr_broadcast_length(x::NativeFont) = 1 # these are our rules, and for what we do, Vecs are usually scalars attr_broadcast_length(x::VecTypes) = 1 # these are our rules, and for what we do, Vecs are usually scalars attr_broadcast_length(x::AbstractArray) = length(x) @@ -191,7 +187,9 @@ The length of an attribute is determined with `attr_broadcast_length` and elemen maxlen = maximum(lengths) any_wrong_length = Base.Cartesian.@nany $N i -> lengths[i] ∉ (0, 1, maxlen) if any_wrong_length - error("All non scalars need same length, Found lengths for each argument: $lengths, $(map(typeof, args))") + error( + "All non scalars need same length, Found lengths for each argument: $lengths, $(map(typeof, args))", + ) end # skip if there's a zero length element (like an empty annotations collection, etc) # this differs from standard broadcasting logic in which all non-scalar shapes have to match @@ -205,29 +203,28 @@ The length of an attribute is determined with `attr_broadcast_length` and elemen end end - """ from_dict(::Type{T}, dict) Creates the type `T` from the fields in dict. Automatically converts to the correct types. """ -function from_dict(::Type{T}, dict) where T - T(map(fieldnames(T)) do name - convert(fieldtype(T, name), dict[name]) - end...) -end +from_dict(::Type{T}, dict) where {T} = T(map(fieldnames(T)) do name + return convert(fieldtype(T, name), dict[name]) +end...) same_length_array(array, value::NativeFont) = repeated(value, length(array)) same_length_array(array, value) = repeated(value, length(array)) function same_length_array(arr, value::Vector) if length(arr) != length(value) - error("Array lengths do not match. Found: $(length(arr)) of $(eltype(arr)) but $(length(value)) $(eltype(value))") + error( + "Array lengths do not match. Found: $(length(arr)) of $(eltype(arr)) but $(length(value)) $(eltype(value))", + ) end - value + return value end same_length_array(arr, value, key) = same_length_array(arr, convert_attribute(value, key)) -function to_ndim(T::Type{<: VecTypes{N,ET}}, vec::VecTypes{N2}, fillval) where {N,ET,N2} +function to_ndim(T::Type{<:VecTypes{N,ET}}, vec::VecTypes{N2}, fillval) where {N,ET,N2} T(ntuple(Val(N)) do i i > N2 && return ET(fillval) @inbounds return vec[i] @@ -260,7 +257,7 @@ function to_vector(x::AbstractArray, len, T) end function to_vector(x::ClosedInterval, len, T) a, b = T.(extrema(x)) - range(a, stop=b, length=len) + return range(a, stop=b, length=len) end """ @@ -270,15 +267,12 @@ x = ColorSampler(colormap, (0.0, 1.0)) x[0.5] # returns color at half point of colormap ``` """ -struct ColorSampler{Data <: AbstractArray} +struct ColorSampler{Data<:AbstractArray} colormap::Data color_range::Tuple{Float64,Float64} end -function Base.getindex(cs::ColorSampler, value::Number) - return interpolated_getindex(cs.colormap, value, cs.color_range) -end - +Base.getindex(cs::ColorSampler, value::Number) = interpolated_getindex(cs.colormap, value, cs.color_range) # This function was copied from GR.jl, # written by Josef Heinen. @@ -290,10 +284,11 @@ Return a nonlinear function on a grid. Useful for test cases. function peaks(n=49) x = LinRange(-3, 3, n) y = LinRange(-3, 3, n) - 3 * (1 .- x').^2 .* exp.(-(x'.^2) .- (y .+ 1).^2) .- 10 * (x' / 5 .- x'.^3 .- y.^5) .* exp.(-x'.^2 .- y.^2) .- 1 / 3 * exp.(-(x' .+ 1).^2 .- y.^2) + return 3 * (1 .- x') .^ 2 .* exp.(-(x' .^ 2) .- (y .+ 1) .^ 2) .- + 10 * (x' / 5 .- x' .^ 3 .- y .^ 5) .* exp.(-x' .^ 2 .- y .^ 2) .- + 1 / 3 * exp.(-(x' .+ 1) .^ 2 .- y .^ 2) end - function attribute_names(PlotType) # TODO, have all plot types store their attribute names return keys(default_theme(nothing, PlotType)) @@ -335,7 +330,7 @@ function matrix_grid(f, x::AbstractArray, y::AbstractArray, z::AbstractMatrix) end function matrix_grid(f, x::ClosedInterval, y::ClosedInterval, z::AbstractMatrix) - matrix_grid(f, LinRange(extrema(x)..., size(z, 1)), LinRange(extrema(x)..., size(z, 2)), z) + return matrix_grid(f, LinRange(extrema(x)..., size(z, 1)), LinRange(extrema(x)..., size(z, 2)), z) end function extract_keys(attributes, keys) diff --git a/test/boundingboxes.jl b/test/boundingboxes.jl index 266548725d8..920bcb86a51 100644 --- a/test/boundingboxes.jl +++ b/test/boundingboxes.jl @@ -8,7 +8,7 @@ @test bb.origin ≈ Point3f(-0.1678, -0.002068, -0.358661) @test bb.widths ≈ Vec3f(0.339423, 0.92186, 1.3318559) - fig, ax, p = surface([x*y for x in 1:10, y in 1:10]) + fig, ax, p = surface([x * y for x in 1:10, y in 1:10]) bb = boundingbox(p) @test bb.origin ≈ Point3f(0.0, 0.0, 1.0) @test bb.widths ≈ Vec3f(10.0, 10.0, 99.0) @@ -42,17 +42,17 @@ bb = boundingbox(p) @test bb.origin ≈ Point3f(0.5, 0.5, 0) @test bb.widths ≈ Vec3f(10.0, 10.0, 0) - + fig, ax, p = image(rand(10, 10)) bb = boundingbox(p) @test bb.origin ≈ Point3f(0) @test bb.widths ≈ Vec3f(10.0, 10.0, 0) # text transforms to pixel space atm (TODO) - fig = Figure(resolution = (400, 400)) + fig = Figure(resolution=(400, 400)) ax = Axis(fig[1, 1]) - p = text!(ax, Point2f(10), text = "test", fontsize = 20) + p = text!(ax, Point2f(10), text="test", fontsize=20) bb = boundingbox(p) @test bb.origin ≈ Point3f(340, 341, 0) @test bb.widths ≈ Vec3f(32.24, 23.3, 0) -end \ No newline at end of file +end diff --git a/test/conversions.jl b/test/conversions.jl index 8c01def1a27..9a1b0502aec 100644 --- a/test/conversions.jl +++ b/test/conversions.jl @@ -11,57 +11,55 @@ using Makie: struct NoConversionTestType end conversion_trait(::NoConversionTestType) = NoConversion() - let nctt = NoConversionTestType(), - ncttt = conversion_trait(nctt) + let nctt = NoConversionTestType(), ncttt = conversion_trait(nctt) @test convert_arguments(ncttt, 1, 2, 3) == (1, 2, 3) end - end @testset "changing input types" begin - input = Observable{Any}(decompose(Point2f, Circle(Point2f(0), 2f0))) + input = Observable{Any}(decompose(Point2f, Circle(Point2f(0), 2.0f0))) f, ax, pl = mesh(input) - m = Makie.triangle_mesh(Circle(Point2f(0), 1f0)) + m = Makie.triangle_mesh(Circle(Point2f(0), 1.0f0)) input[] = m @test pl[1][] == m end @testset "to_vertices" begin - X1 = [Point(rand(3)...) for i = 1:10] + X1 = [Point(rand(3)...) for i in 1:10] V1 = to_vertices(X1) @test Float32(X1[7][1]) == V1[7][1] - X2 = [tuple(rand(3)...) for i = 1:10] + X2 = [tuple(rand(3)...) for i in 1:10] V2 = to_vertices(X2) @test Float32(X2[7][1]) == V2[7][1] - X4 = rand(2,10) + X4 = rand(2, 10) V4 = to_vertices(X4) - @test Float32(X4[1,7]) == V4[7][1] + @test Float32(X4[1, 7]) == V4[7][1] @test V4[7][3] == 0 - X5 = rand(3,10) + X5 = rand(3, 10) V5 = to_vertices(X5) - @test Float32(X5[1,7]) == V5[7][1] + @test Float32(X5[1, 7]) == V5[7][1] - X6 = rand(10,2) + X6 = rand(10, 2) V6 = to_vertices(X6) - @test Float32(X6[7,1]) == V6[7][1] + @test Float32(X6[7, 1]) == V6[7][1] @test V6[7][3] == 0 - X7 = rand(10,3) + X7 = rand(10, 3) V7 = to_vertices(X7) - @test Float32(X7[7,1]) == V7[7][1] + @test Float32(X7[7, 1]) == V7[7][1] end @testset "functions" begin - x = -pi..pi + x = -pi .. pi s = convert_arguments(Lines, x, sin) xy = s.args[1] @test xy[1][1] ≈ -pi @test xy[end][1] ≈ pi for (val, fval) in xy - @test fval ≈ sin(val) atol=1f-6 + @test fval ≈ sin(val) atol = 1.0f-6 end x = range(-pi, stop=pi, length=100) @@ -70,15 +68,15 @@ end @test xy[1][1] ≈ -pi @test xy[end][1] ≈ pi for (val, fval) in xy - @test fval ≈ sin(val) atol=1f-6 + @test fval ≈ sin(val) atol = 1.0f-6 end - pts = [Point(1, 2), Point(4,5), Point(10, 8), Point(1, 2)] - ls=LineString(pts) + pts = [Point(1, 2), Point(4, 5), Point(10, 8), Point(1, 2)] + ls = LineString(pts) p = convert_arguments(Makie.PointBased(), ls) @test p[1] == pts - pts1 = [Point(5, 2), Point(4,8), Point(2, 8), Point(5, 2)] + pts1 = [Point(5, 2), Point(4, 8), Point(2, 8), Point(5, 2)] ls1 = LineString(pts1) lsa = [ls, ls1] p1 = convert_arguments(Makie.PointBased(), lsa) @@ -92,16 +90,16 @@ end pol_e = Polygon(ls) p3_e = convert_arguments(Makie.PointBased(), pol_e) - @test p3_e[1][1:end-1] == pts # for poly we repeat last point + @test p3_e[1][1:(end - 1)] == pts # for poly we repeat last point pol = Polygon(ls, [ls1]) p3 = convert_arguments(Makie.PointBased(), pol) @test p3[1][1:4] == pts @test p3[1][7:10] == pts1 - pts2 = Point{2, Int}[(5, 1), (3, 3), (4, 8), (1, 2), (5, 1)] - pts3 = Point{2, Int}[(2, 2), (2, 3),(3, 4), (2, 2)] - pts4 = Point{2, Int}[(2, 2), (3, 8),(5, 6), (3, 4), (2, 2)] + pts2 = Point{2,Int}[(5, 1), (3, 3), (4, 8), (1, 2), (5, 1)] + pts3 = Point{2,Int}[(2, 2), (2, 3), (3, 4), (2, 2)] + pts4 = Point{2,Int}[(2, 2), (3, 8), (5, 6), (3, 4), (2, 2)] ls2 = LineString(pts2) ls3 = LineString(pts3) ls4 = LineString(pts4) @@ -126,23 +124,21 @@ using Makie: check_line_pattern, line_diff_pattern # for readability, the length of dash and dot dash, dot = 3.0, 1.0 - @test line_diff_pattern(:dash) == - line_diff_pattern("-", :normal) == [dash, 3.0] - @test line_diff_pattern(:dot) == - line_diff_pattern(".", :normal) == [dot, 2.0] - @test line_diff_pattern(:dashdot) == - line_diff_pattern("-.", :normal) == [dash, 3.0, dot, 3.0] - @test line_diff_pattern(:dashdotdot) == - line_diff_pattern("-..", :normal) == [dash, 3.0, dot, 2.0, dot, 3.0] - - @test line_diff_pattern(:dash, :loose) == [dash, 6.0] - @test line_diff_pattern(:dot, :loose) == [dot, 4.0] - @test line_diff_pattern("-", :dense) == [dash, 2.0] - @test line_diff_pattern(".", :dense) == [dot, 1.0] - @test line_diff_pattern(:dash, 0.5) == [dash, 0.5] - @test line_diff_pattern(:dot, 0.5) == [dot, 0.5] - @test line_diff_pattern("-", (0.4, 0.6)) == [dash, 0.6] - @test line_diff_pattern(:dot, (0.4, 0.6)) == [dot, 0.4] + @test line_diff_pattern(:dash) == line_diff_pattern("-", :normal) == [dash, 3.0] + @test line_diff_pattern(:dot) == line_diff_pattern(".", :normal) == [dot, 2.0] + @test line_diff_pattern(:dashdot) == line_diff_pattern("-.", :normal) == [dash, 3.0, dot, 3.0] + @test line_diff_pattern(:dashdotdot) == + line_diff_pattern("-..", :normal) == + [dash, 3.0, dot, 2.0, dot, 3.0] + + @test line_diff_pattern(:dash, :loose) == [dash, 6.0] + @test line_diff_pattern(:dot, :loose) == [dot, 4.0] + @test line_diff_pattern("-", :dense) == [dash, 2.0] + @test line_diff_pattern(".", :dense) == [dot, 1.0] + @test line_diff_pattern(:dash, 0.5) == [dash, 0.5] + @test line_diff_pattern(:dot, 0.5) == [dot, 0.5] + @test line_diff_pattern("-", (0.4, 0.6)) == [dash, 0.6] + @test line_diff_pattern(:dot, (0.4, 0.6)) == [dot, 0.4] @test line_diff_pattern("-..", (0.4, 0.6)) == [dash, 0.6, dot, 0.4, dot, 0.6] # gaps must be Symbol, a number, or two numbers @@ -169,14 +165,11 @@ end @test convert_arguments(Lines, myvector, mynestedvector) == (Point2f.(1:10, 11:20),) - @test isequal( - convert_arguments(Lines, [1, missing, 2]), - (Point2f[(1, 1), (2, NaN), (3, 2)],) - ) + @test isequal(convert_arguments(Lines, [1, missing, 2]), (Point2f[(1, 1), (2, NaN), (3, 2)],)) @test isequal( convert_arguments(Lines, [Point(1, 2), missing, Point(3, 4)]), - (Point2f[(1.0, 2.0), (NaN, NaN), (3.0, 4.0)],) + (Point2f[(1.0, 2.0), (NaN, NaN), (3.0, 4.0)],), ) end @@ -198,10 +191,10 @@ end cs = Makie.resample_cmap(:viridis, 10; alpha=LinRange(0, 1, 10)) @test Colors.alpha.(cs) == Float32.(LinRange(0, 1, 10)) cs = Makie.resample_cmap(:viridis, 2; alpha=0.5) - @test all(x-> x == 0.5, Colors.alpha.(cs)) + @test all(x -> x == 0.5, Colors.alpha.(cs)) @test Colors.color.(cs) == Colors.color.(Makie.resample(to_colormap(:viridis), 2)) cs = Makie.resample_cmap(:Set1, 100) - @test all(x-> x == 1.0, Colors.alpha.(cs)) + @test all(x -> x == 1.0, Colors.alpha.(cs)) @test Colors.color.(cs) == Colors.color.(Makie.resample(to_colormap(:Set1), 100)) cs = Makie.resample_cmap(:Set1, 10; alpha=(0, 1)) @test Colors.alpha.(cs) == Float32.(LinRange(0, 1, 10)) @@ -212,7 +205,6 @@ end @test to_color(["red", "green"]) == [to_color("red"), to_color("green")] end - @testset "heatmap from three vectors" begin x = [2, 1, 2] y = [2, 3, 3] @@ -243,7 +235,6 @@ end @test alpha(to_colormap(cgrad(:cividis, 8; alpha=0.5))[1]) == 0.5 @test alpha(to_colormap(cgrad(:cividis, 8; alpha=0.5, categorical=true))[1]) == 0.5 - @inferred to_colormap([HSL(0, 10, 20)]) @inferred to_colormap([:red, :green]) @inferred to_colormap([(:red, 0.1), (:green, 0.2)]) @@ -257,14 +248,13 @@ end @inferred to_colormap(cgrad(:cividis, 8; alpha=0.5, categorical=true)) end - @testset "empty poly" begin - f, ax, pl = poly(Rect2f[]); - pl[1] = [Rect2f(0, 0, 1, 1)]; + f, ax, pl = poly(Rect2f[]) + pl[1] = [Rect2f(0, 0, 1, 1)] @test pl.plots[1][1][] == [GeometryBasics.triangle_mesh(Rect2f(0, 0, 1, 1))] f, ax, pl = poly(Vector{Point2f}[]) - points = decompose(Point2f, Circle(Point2f(0),1)) + points = decompose(Point2f, Circle(Point2f(0), 1)) pl[1] = [points] @test pl.plots[1][1][] == Makie.poly_convert(points) end diff --git a/test/events.jl b/test/events.jl index 31b2b484eb8..d35863c6de4 100644 --- a/test/events.jl +++ b/test/events.jl @@ -50,9 +50,9 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right @test !ispressed(events, Mouse.right) # Collections - @test ispressed(events, (Keyboard.a, )) - @test ispressed(events, [Keyboard.a, ]) - @test ispressed(events, Set((Keyboard.a, ))) + @test ispressed(events, (Keyboard.a,)) + @test ispressed(events, [Keyboard.a]) + @test ispressed(events, Set((Keyboard.a,))) @test !ispressed(events, (Keyboard.a, Keyboard.b)) @test !ispressed(events, [Keyboard.a, Keyboard.b]) @@ -83,14 +83,12 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right @test Exclusively(Keyboard.a & Mouse.left) == Exclusively((Keyboard.a, Mouse.left)) @test ispressed(events, Exclusively(Keyboard.a & Mouse.left)) - @test Exclusively(Keyboard.a | Mouse.left) == Makie.Or(Exclusively(Keyboard.a), Exclusively(Mouse.left)) + @test Exclusively(Keyboard.a | Mouse.left) == + Makie.Or(Exclusively(Keyboard.a), Exclusively(Mouse.left)) @test !ispressed(events, Exclusively(Keyboard.a | Mouse.left)) expr = Mouse.left & (Keyboard.a | (Keyboard.a & Keyboard.b)) - lowered = Or( - Exclusively((Mouse.left, Keyboard.a)), - Exclusively((Mouse.left, Keyboard.a, Keyboard.b)) - ) + lowered = Or(Exclusively((Mouse.left, Keyboard.a)), Exclusively((Mouse.left, Keyboard.a, Keyboard.b))) @test ispressed(events, expr) @test Exclusively(expr) == lowered @test ispressed(events, Exclusively(expr)) @@ -135,8 +133,8 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right clipboard() = CLIP[] end @testset "copy_paste" begin - f = Figure(resolution=(640,480)) - tb = Textbox(f[1,1], placeholder="Copy/paste into me") + f = Figure(resolution=(640, 480)) + tb = Textbox(f[1, 1], placeholder="Copy/paste into me") e = events(f.scene) # Initial state @@ -162,12 +160,11 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right @test tb.stored_string[] == "test string" - # Refresh figure to test right control + v combination empty!(f) - f = Figure(resolution=(640,480)) - tb = Textbox(f[1,1], placeholder="Copy/paste into me") + f = Figure(resolution=(640, 480)) + tb = Textbox(f[1, 1], placeholder="Copy/paste into me") e = events(f.scene) # Initial state @@ -196,109 +193,108 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right # This testset is based on the results the current camera system has. If # cam3d! is updated this is likely to break. @testset "cam3d!" begin - scene = Scene(resolution=(800, 600)); + scene = Scene(resolution=(800, 600)) e = events(scene) cam3d!(scene, fixed_axis=true, cad=false, zoom_shift_lookat=false) cc = cameracontrols(scene) # Verify initial camera state - @test cc.lookat[] == Vec3f(0) - @test cc.eyeposition[] == Vec3f(3) - @test cc.upvector[] == Vec3f(0, 0, 1) + @test cc.lookat[] == Vec3f(0) + @test cc.eyeposition[] == Vec3f(3) + @test cc.upvector[] == Vec3f(0, 0, 1) # Rotation # 1) In scene, in drag e.mouseposition[] = (400, 250) e.mousebutton[] = MouseButtonEvent(Mouse.left, Mouse.press) e.mouseposition[] = (600, 250) - @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(4.14532, -0.9035063, 3.0) - @test cc.upvector[] ≈ Vec3f(0, 0, 1) + @test cc.lookat[] ≈ Vec3f(0) + @test cc.eyeposition[] ≈ Vec3f(4.14532, -0.9035063, 3.0) + @test cc.upvector[] ≈ Vec3f(0, 0, 1) # 2) Outside scene, in drag e.mouseposition[] = (1000, 450) - @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(-2.8912058, -3.8524969, -1.9491522) - @test cc.upvector[] ≈ Vec3f(-0.5050875, -0.6730229, 0.5403024) + @test cc.lookat[] ≈ Vec3f(0) + @test cc.eyeposition[] ≈ Vec3f(-2.8912058, -3.8524969, -1.9491522) + @test cc.upvector[] ≈ Vec3f(-0.5050875, -0.6730229, 0.5403024) # 3) not in drag e.mousebutton[] = MouseButtonEvent(Mouse.left, Mouse.release) e.mouseposition[] = (400, 250) - @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(-2.8912058, -3.8524969, -1.9491522) - @test cc.upvector[] ≈ Vec3f(-0.5050875, -0.6730229, 0.5403024) - - + @test cc.lookat[] ≈ Vec3f(0) + @test cc.eyeposition[] ≈ Vec3f(-2.8912058, -3.8524969, -1.9491522) + @test cc.upvector[] ≈ Vec3f(-0.5050875, -0.6730229, 0.5403024) # Reset state so this is indepentent from the last checks - scene = Scene(resolution=(800, 600)); + scene = Scene(resolution=(800, 600)) e = events(scene) cam3d!(scene, fixed_axis=true, cad=false, zoom_shift_lookat=false) cc = cameracontrols(scene) # Verify initial camera state - @test cc.lookat[] == Vec3f(0) - @test cc.eyeposition[] == Vec3f(3) - @test cc.upvector[] == Vec3f(0, 0, 1) + @test cc.lookat[] == Vec3f(0) + @test cc.eyeposition[] == Vec3f(3) + @test cc.upvector[] == Vec3f(0, 0, 1) # translation # 1) In scene, in drag e.mousebutton[] = MouseButtonEvent(Mouse.right, Mouse.press) e.mouseposition[] = (600, 250) - @test cc.lookat[] ≈ Vec3f(5.4697413, -3.3484206, -2.1213205) - @test cc.eyeposition[] ≈ Vec3f(8.469742, -0.34842062, 0.8786795) - @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) + @test cc.lookat[] ≈ Vec3f(5.4697413, -3.3484206, -2.1213205) + @test cc.eyeposition[] ≈ Vec3f(8.469742, -0.34842062, 0.8786795) + @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) # 2) Outside scene, in drag e.mouseposition[] = (1000, 450) - @test cc.lookat[] ≈ Vec3f(9.257657, -5.4392805, -3.818377) - @test cc.eyeposition[] ≈ Vec3f(12.257658, -2.4392805, -0.81837714) - @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) + @test cc.lookat[] ≈ Vec3f(9.257657, -5.4392805, -3.818377) + @test cc.eyeposition[] ≈ Vec3f(12.257658, -2.4392805, -0.81837714) + @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) # 3) not in drag e.mousebutton[] = MouseButtonEvent(Mouse.right, Mouse.release) e.mouseposition[] = (400, 250) - @test cc.lookat[] ≈ Vec3f(9.257657, -5.4392805, -3.818377) - @test cc.eyeposition[] ≈ Vec3f(12.257658, -2.4392805, -0.81837714) - @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) - - + @test cc.lookat[] ≈ Vec3f(9.257657, -5.4392805, -3.818377) + @test cc.eyeposition[] ≈ Vec3f(12.257658, -2.4392805, -0.81837714) + @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) # Reset state - scene = Scene(resolution=(800, 600)); + scene = Scene(resolution=(800, 600)) e = events(scene) cam3d!(scene, fixed_axis=true, cad=false, zoom_shift_lookat=false) cc = cameracontrols(scene) # Verify initial camera state - @test cc.lookat[] == Vec3f(0) - @test cc.eyeposition[] == Vec3f(3) - @test cc.upvector[] == Vec3f(0, 0, 1) - @test cc.zoom_mult[] == 1f0 + @test cc.lookat[] == Vec3f(0) + @test cc.eyeposition[] == Vec3f(3) + @test cc.upvector[] == Vec3f(0, 0, 1) + @test cc.zoom_mult[] == 1.0f0 # Zoom e.scroll[] = (0.0, 4.0) - @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(3) - @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) - @test cc.zoom_mult[] ≈ 0.6830134f0 + @test cc.lookat[] ≈ Vec3f(0) + @test cc.eyeposition[] ≈ Vec3f(3) + @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) + @test cc.zoom_mult[] ≈ 0.6830134f0 # should not work outside the scene e.mouseposition[] = (1000, 450) e.scroll[] = (0.0, 4.0) - @test cc.lookat[] ≈ Vec3f(0) - @test cc.eyeposition[] ≈ Vec3f(3) - @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) - @test cc.zoom_mult[] ≈ 0.6830134f0 + @test cc.lookat[] ≈ Vec3f(0) + @test cc.eyeposition[] ≈ Vec3f(3) + @test cc.upvector[] ≈ Vec3f(0.0, 0.0, 1.0) + @test cc.zoom_mult[] ≈ 0.6830134f0 end @testset "mouse state machine" begin - scene = Scene(resolution=(800, 600)); + scene = Scene(resolution=(800, 600)) e = events(scene) bbox = Observable(Rect2(200, 200, 400, 300)) msm = addmouseevents!(scene, bbox, priority=typemax(Int)) eventlog = MouseEvent[] - on(x -> begin push!(eventlog, x); false end, msm.obs) + on(x -> begin + push!(eventlog, x) + false + end, msm.obs) e.mouseposition[] = (0, 200) @test isempty(eventlog) @@ -325,10 +321,10 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right e.mousebutton[] = MouseButtonEvent(getfield(Mouse, button), Mouse.release) @test length(eventlog) == 3 for (i, t) in enumerate(( - getfield(MouseEventTypes, Symbol(button, :down)), - getfield(MouseEventTypes, Symbol(button, :click)), - getfield(MouseEventTypes, Symbol(button, :up)) - )) + getfield(MouseEventTypes, Symbol(button, :down)), + getfield(MouseEventTypes, Symbol(button, :click)), + getfield(MouseEventTypes, Symbol(button, :up)), + )) @test eventlog[i].type == t @test eventlog[i].px == Point2f(300, 300) @test eventlog[i].prev_px == Point2f(300, 300) @@ -340,10 +336,10 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right e.mousebutton[] = MouseButtonEvent(getfield(Mouse, button), Mouse.release) @test length(eventlog) == 3 for (i, t) in enumerate(( - getfield(MouseEventTypes, Symbol(button, :down)), - getfield(MouseEventTypes, Symbol(button, :doubleclick)), - getfield(MouseEventTypes, Symbol(button, :up)) - )) + getfield(MouseEventTypes, Symbol(button, :down)), + getfield(MouseEventTypes, Symbol(button, :doubleclick)), + getfield(MouseEventTypes, Symbol(button, :up)), + )) @test eventlog[i].type == t @test eventlog[i].px == Point2f(300, 300) @test eventlog[i].prev_px == Point2f(300, 300) @@ -355,10 +351,10 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right e.mousebutton[] = MouseButtonEvent(getfield(Mouse, button), Mouse.release) @test length(eventlog) == 3 for (i, t) in enumerate(( - getfield(MouseEventTypes, Symbol(button, :down)), - getfield(MouseEventTypes, Symbol(button, :click)), - getfield(MouseEventTypes, Symbol(button, :up)) - )) + getfield(MouseEventTypes, Symbol(button, :down)), + getfield(MouseEventTypes, Symbol(button, :click)), + getfield(MouseEventTypes, Symbol(button, :up)), + )) @test eventlog[i].type == t @test eventlog[i].px == Point2f(300, 300) @test eventlog[i].prev_px == Point2f(300, 300) @@ -372,16 +368,16 @@ Base.:(==)(l::Or, r::Or) = l.left == r.left && l.right == r.right e.mousebutton[] = MouseButtonEvent(getfield(Mouse, button), Mouse.release) @test length(eventlog) == 6 prev_px = Point2f[(300, 300), (300, 300), (300, 300), (500, 300), (700, 200), (700, 200)] - px = Point2f[(300, 300), (500, 300), (500, 300), (700, 200), (700, 200), (700, 200)] + px = Point2f[(300, 300), (500, 300), (500, 300), (700, 200), (700, 200), (700, 200)] for (i, t) in enumerate(( - getfield(MouseEventTypes, Symbol(button, :down)), - getfield(MouseEventTypes, Symbol(button, :dragstart)), - getfield(MouseEventTypes, Symbol(button, :drag)), - getfield(MouseEventTypes, Symbol(button, :drag)), - getfield(MouseEventTypes, Symbol(button, :dragstop)), - getfield(MouseEventTypes, :out), - # TODO this is kinda missing an "up outside" - )) + getfield(MouseEventTypes, Symbol(button, :down)), + getfield(MouseEventTypes, Symbol(button, :dragstart)), + getfield(MouseEventTypes, Symbol(button, :drag)), + getfield(MouseEventTypes, Symbol(button, :drag)), + getfield(MouseEventTypes, Symbol(button, :dragstop)), + getfield(MouseEventTypes, :out), + # TODO this is kinda missing an "up outside" + )) @test eventlog[i].type == t @test eventlog[i].px == px[i] @test eventlog[i].prev_px == prev_px[i] diff --git a/test/figures.jl b/test/figures.jl index 4d844d115af..ff94ff6a5a9 100644 --- a/test/figures.jl +++ b/test/figures.jl @@ -99,34 +99,34 @@ end @testset "Getting figure content" begin fig = Figure() ax = fig[1, 1] = Axis(fig) - @test contents(fig[1, 1], exact = true) == [ax] - @test contents(fig[1, 1], exact = false) == [ax] - @test contents(fig[1:2, 1:2], exact = true) == [] - @test contents(fig[1:2, 1:2], exact = false) == [ax] + @test contents(fig[1, 1], exact=true) == [ax] + @test contents(fig[1, 1], exact=false) == [ax] + @test contents(fig[1:2, 1:2], exact=true) == [] + @test contents(fig[1:2, 1:2], exact=false) == [ax] @test content(fig[1, 1]) == ax @test_throws ErrorException content(fig[2, 2]) @test_throws ErrorException content(fig[1:2, 1:2]) label = fig[1, 1] = Label(fig) - @test contents(fig[1, 1], exact = true) == [ax, label] - @test contents(fig[1, 1], exact = false) == [ax, label] - @test contents(fig[1:2, 1:2], exact = true) == [] - @test contents(fig[1:2, 1:2], exact = false) == [ax, label] + @test contents(fig[1, 1], exact=true) == [ax, label] + @test contents(fig[1, 1], exact=false) == [ax, label] + @test contents(fig[1:2, 1:2], exact=true) == [] + @test contents(fig[1:2, 1:2], exact=false) == [ax, label] @test_throws ErrorException content(fig[1, 1]) ax2 = fig[1, 2][1, 1] = Axis(fig) - @test contents(fig[1, 2][1, 1], exact = true) == [ax2] - @test contents(fig[1, 2][1, 1], exact = false) == [ax2] - @test contents(fig[1, 2][1:2, 1:2], exact = true) == [] - @test contents(fig[1, 2][1:2, 1:2], exact = false) == [ax2] + @test contents(fig[1, 2][1, 1], exact=true) == [ax2] + @test contents(fig[1, 2][1, 1], exact=false) == [ax2] + @test contents(fig[1, 2][1:2, 1:2], exact=true) == [] + @test contents(fig[1, 2][1:2, 1:2], exact=false) == [ax2] label2 = fig[1, 2][1, 1] = Label(fig) - @test contents(fig[1, 2][1, 1], exact = true) == [ax2, label2] - @test contents(fig[1, 2][1, 1], exact = false) == [ax2, label2] - @test contents(fig[1, 2][1:2, 1:2], exact = true) == [] - @test contents(fig[1, 2][1:2, 1:2], exact = false) == [ax2, label2] + @test contents(fig[1, 2][1, 1], exact=true) == [ax2, label2] + @test contents(fig[1, 2][1, 1], exact=false) == [ax2, label2] + @test contents(fig[1, 2][1:2, 1:2], exact=true) == [] + @test contents(fig[1, 2][1:2, 1:2], exact=false) == [ax2, label2] @test_throws ErrorException content(fig[1, 2][1, 1]) end @@ -151,20 +151,22 @@ end end @testset "Not implemented error" begin - @test_throws ErrorException("Not implemented for scatter. You might want to put: `using Makie` into your code!") scatter() + @test_throws ErrorException( + "Not implemented for scatter. You might want to put: `using Makie` into your code!", + ) scatter() end @testset "Figure and axis kwargs validation" begin - @test_throws ArgumentError lines(1:10, axis = (aspect = DataAspect()), figure = (resolution = (100, 100))) - @test_throws ArgumentError lines(1:10, figure = (resolution = (100, 100))) - @test_throws ArgumentError lines(1:10, axis = (aspect = DataAspect())) - + @test_throws ArgumentError lines(1:10, axis=(aspect = DataAspect()), figure=(resolution = (100, 100))) + @test_throws ArgumentError lines(1:10, figure=(resolution = (100, 100))) + @test_throws ArgumentError lines(1:10, axis=(aspect = DataAspect())) + # these just shouldn't error - lines(1:10, axis = (aspect = DataAspect(),)) - lines(1:10, axis = Attributes(aspect = DataAspect())) - lines(1:10, axis = Dict(:aspect => DataAspect())) + lines(1:10, axis=(aspect=DataAspect(),)) + lines(1:10, axis=Attributes(aspect=DataAspect())) + lines(1:10, axis=Dict(:aspect => DataAspect())) f = Figure() - @test_throws ArgumentError lines(f[1, 1], 1:10, axis = (aspect = DataAspect())) - @test_throws ArgumentError lines(f[1, 1][2, 2], 1:10, axis = (aspect = DataAspect())) -end \ No newline at end of file + @test_throws ArgumentError lines(f[1, 1], 1:10, axis=(aspect = DataAspect())) + @test_throws ArgumentError lines(f[1, 1][2, 2], 1:10, axis=(aspect = DataAspect())) +end diff --git a/test/liftmacro.jl b/test/liftmacro.jl index 195febf5cd2..d7ef34c17a3 100644 --- a/test/liftmacro.jl +++ b/test/liftmacro.jl @@ -1,8 +1,8 @@ @testset "lift macro" begin x = Observable(1.0) y = Observable(2.0) - z = (x = x, y = y) - + z = (x=x, y=y) + t1 = @lift($x + $y) @test t1[] == 3.0 t2 = @lift($(z.x) - $(z.y)) diff --git a/test/makielayout.jl b/test/makielayout.jl index 92008f2bc0c..9d2bc59fc31 100644 --- a/test/makielayout.jl +++ b/test/makielayout.jl @@ -42,8 +42,8 @@ end _, hm = heatmap(fig[1, 1], xs, ys, zs) cb = Colorbar(fig[1, 2], hm) - @test hm.attributes[:colorrange][] == (-.5, .5) - @test cb.limits[] == (-.5, .5) + @test hm.attributes[:colorrange][] == (-0.5, 0.5) + @test cb.limits[] == (-0.5, 0.5) hm.attributes[:colorrange][] = Float32.((-1, 1)) @test cb.limits[] == (-1, 1) @@ -55,7 +55,7 @@ end @testset "Axis limits basics" begin f = Figure() - ax = Axis(f[1, 1], limits = (nothing, nothing)) + ax = Axis(f[1, 1], limits=(nothing, nothing)) ax.targetlimits[] = BBox(0, 10, 0, 20) @test ax.finallimits[] == BBox(0, 10, 0, 20) @test ax.limits[] == (nothing, nothing) @@ -117,7 +117,7 @@ end @testset "Colorbar plot object kwarg clash" begin for attr in (:colormap, :limits) - f, ax, p = scatter(1:10, 1:10, color = 1:10, colorrange = (1, 10)) + f, ax, p = scatter(1:10, 1:10, color=1:10, colorrange=(1, 10)) Colorbar(f[2, 1], p) @test_throws ErrorException Colorbar(f[2, 1], p; Dict(attr => nothing)...) end @@ -149,21 +149,23 @@ end numbers = [1.0, 1.5, 2.0] @test get_ticks(numbers, func, automatic, 0, 5) == (numbers, ["1.0", "1.5", "2.0"]) - @test get_ticks(numbers, func, xs -> string.(xs) .* "kg", 0, 5) == (numbers, ["1.0kg", "1.5kg", "2.0kg"]) + @test get_ticks(numbers, func, xs -> string.(xs) .* "kg", 0, 5) == + (numbers, ["1.0kg", "1.5kg", "2.0kg"]) - @test get_ticks(WilkinsonTicks(5), identity, automatic, 1, 5) == ([1, 2, 3, 4, 5], ["1", "2", "3", "4", "5"]) + @test get_ticks(WilkinsonTicks(5), identity, automatic, 1, 5) == + ([1, 2, 3, 4, 5], ["1", "2", "3", "4", "5"]) end end @testset "Colorbars" begin fig = Figure() hmap = heatmap!(Axis(fig[1, 1]), rand(4, 4)) - cb1 = Colorbar(fig[1,2], hmap; height = Relative(0.65)) + cb1 = Colorbar(fig[1, 2], hmap; height=Relative(0.65)) @test cb1.height[] == Relative(0.65) @testset "conversion" begin # https://github.com/MakieOrg/Makie.jl/issues/2278 fig = Figure() - cbar = Colorbar(fig[1,1], colormap=:viridis, colorrange=Vec2f(0, 1)) + cbar = Colorbar(fig[1, 1], colormap=:viridis, colorrange=Vec2f(0, 1)) ticklabel_strings = first.(cbar.axis.elements[:ticklabels][1][]) @test ticklabel_strings[1] == "0.0" @test ticklabel_strings[end] == "1.0" @@ -172,10 +174,10 @@ end @testset "cycling" begin fig = Figure() - ax = Axis(fig[1, 1], palette = (patchcolor = [:blue, :green],)) - pl = density!(rand(10); color = Cycled(2)) + ax = Axis(fig[1, 1], palette=(patchcolor=[:blue, :green],)) + pl = density!(rand(10); color=Cycled(2)) @test pl.color[] == :green - pl = density!(rand(10); color = Cycled(1)) + pl = density!(rand(10); color=Cycled(1)) @test pl.color[] == :blue end @@ -185,16 +187,16 @@ end # triggering a conversion error # So we just check that the same scenario doesn't error again f = Figure() - ax = Axis(f[1,1], xticks = 20:10:80) - scatter!(ax, 30:10:100, rand(Float64, 8), color = :red) + ax = Axis(f[1, 1], xticks=20:10:80) + scatter!(ax, 30:10:100, rand(Float64, 8), color=:red) end # issues 1958 and 2006 @testset "axislegend number align" begin f = Figure() - ax = Axis(f[1,1], xticks = 20:10:80) - lines!(ax, 1:10, label = "A line") - leg = axislegend(ax, position = (0.4, 0.8)) + ax = Axis(f[1, 1], xticks=20:10:80) + lines!(ax, 1:10, label="A line") + leg = axislegend(ax, position=(0.4, 0.8)) @test leg.halign[] == 0.4 @test leg.valign[] == 0.8 end @@ -203,20 +205,20 @@ end @testset "invalid plotting function keyword arguments" begin for T in [Axis, Axis3, LScene] f = Figure() - kw = (; backgroundcolor = :red) - @test_throws ArgumentError lines(f[1, 1], 1:10, figure = kw) - @test_nowarn lines(f[1, 2], 1:10, axis = kw) - @test_throws ArgumentError lines(f[1, 3][1, 1], 1:10, figure = kw) - @test_nowarn lines(f[1, 4][1, 2], 1:10, axis = kw) + kw = (; backgroundcolor=:red) + @test_throws ArgumentError lines(f[1, 1], 1:10, figure=kw) + @test_nowarn lines(f[1, 2], 1:10, axis=kw) + @test_throws ArgumentError lines(f[1, 3][1, 1], 1:10, figure=kw) + @test_nowarn lines(f[1, 4][1, 2], 1:10, axis=kw) ax = T(f[1, 5]) - @test_throws ArgumentError lines!(ax, 1:10, axis = kw) - @test_throws ArgumentError lines!(ax, 1:10, axis = kw) - @test_throws ArgumentError lines!(1:10, axis = kw) - @test_throws ArgumentError lines!(1:10, figure = kw) - @test_nowarn lines!(1:10) - @test_throws ArgumentError lines!(f[1, 5], 1:10, figure = kw) - @test_throws ArgumentError lines!(f[1, 5], 1:10, axis = kw) - @test_nowarn lines!(f[1, 5], 1:10) + @test_throws ArgumentError lines!(ax, 1:10, axis=kw) + @test_throws ArgumentError lines!(ax, 1:10, axis=kw) + @test_throws ArgumentError lines!(1:10, axis=kw) + @test_throws ArgumentError lines!(1:10, figure=kw) + @test_nowarn lines!(1:10) + @test_throws ArgumentError lines!(f[1, 5], 1:10, figure=kw) + @test_throws ArgumentError lines!(f[1, 5], 1:10, axis=kw) + @test_nowarn lines!(f[1, 5], 1:10) end end @@ -225,8 +227,8 @@ end # don't change because the second axis has limits contained inside those # of the first, so the axis linking didn't proliferate f = Figure() - ax1 = Axis(f[1, 1], xautolimitmargin = (0, 0), yautolimitmargin = (0, 0)) - ax2 = Axis(f[2, 1], xautolimitmargin = (0, 0), yautolimitmargin = (0, 0)) + ax1 = Axis(f[1, 1], xautolimitmargin=(0, 0), yautolimitmargin=(0, 0)) + ax2 = Axis(f[2, 1], xautolimitmargin=(0, 0), yautolimitmargin=(0, 0)) scatter!(ax1, 1:5, 2:6) scatter!(ax2, 2:3, 3:4) reset_limits!(ax1) diff --git a/test/pipeline.jl b/test/pipeline.jl index 3faf0ca29ff..ff00b0a8a63 100644 --- a/test/pipeline.jl +++ b/test/pipeline.jl @@ -1,25 +1,20 @@ # extracted from interfaces.jl function test_copy(; kw...) scene = Scene() - return Makie.merged_get!( - ()-> Makie.default_theme(scene, Lines), - :lines, scene, Attributes(kw) - ) + return Makie.merged_get!(() -> Makie.default_theme(scene, Lines), :lines, scene, Attributes(kw)) end -function test_copy2(attr; kw...) - return merge!(Attributes(kw), attr) -end +test_copy2(attr; kw...) = merge!(Attributes(kw), attr) @testset "don't copy in theme merge" begin x = Observable{Any}(1) - res=test_copy(linewidth=x) + res = test_copy(linewidth=x) res.linewidth === x end @testset "don't copy observables in when calling merge!" begin x = Observable{Any}(1) - res=test_copy2(Attributes(linewidth=x)) + res = test_copy2(Attributes(linewidth=x)) res.linewidth === x end @@ -29,7 +24,7 @@ end list = Observable{Any}([1, 2, 3, 4]) xmax = Observable{Any}([0.25, 0.5, 0.75, 1]) - p = hlines!(ax, list, xmax = xmax, color = :blue) + p = hlines!(ax, list, xmax=xmax, color=:blue) @test getfield(p, :input_args)[1] === list @test p.xmax === xmax fig diff --git a/test/projection_math.jl b/test/projection_math.jl index 946f4e6adf0..3aef948d3f6 100644 --- a/test/projection_math.jl +++ b/test/projection_math.jl @@ -1,4 +1,4 @@ @testset "Projection math" begin @test eltype(Makie.rotationmatrix_x(1)) == Float64 - @test eltype(Makie.rotationmatrix_x(1f0)) == Float32 + @test eltype(Makie.rotationmatrix_x(1.0f0)) == Float32 end diff --git a/test/quaternions.jl b/test/quaternions.jl index 77fd813a030..e51ec5e3c06 100644 --- a/test/quaternions.jl +++ b/test/quaternions.jl @@ -2,28 +2,30 @@ struct Degree{T} <: Number θ::T end Base.:/(θ::Degree, x::Number) = Degree(θ.θ / x) -Base.sin(θ::Degree) = sin(θ.θ * π/180) -Base.cos(θ::Degree) = cos(θ.θ * π/180) +Base.sin(θ::Degree) = sin(θ.θ * π / 180) +Base.cos(θ::Degree) = cos(θ.θ * π / 180) @testset "Quaternions" begin - qx = qrotation(Vec(1, 0, 0), pi / 4) @test qx * qx ≈ qrotation(Vec(1.0, 0.0, 0.0), pi / 2) @test Base.power_by_squaring(qx, 2) ≈ qrotation(Vec(1.0, 0.0, 0.0), pi / 2) theta = pi / 8 qx = qrotation(Vec(1.0, 0.0, 0.0), theta) - c = cos(theta); s = sin(theta) + c = cos(theta) + s = sin(theta) Rx = [1 0 0; 0 c -s; 0 s c] @test Mat3f(qx) ≈ Rx theta = pi / 6 qy = qrotation(Vec(0.0, 1.0, 0.0), theta) - c = cos(theta); s = sin(theta) + c = cos(theta) + s = sin(theta) Ry = [c 0 s; 0 1 0; -s 0 c] @test Mat3f(qy) ≈ Ry theta = 4pi / 3 qz = qrotation(Vec(0.0, 0.0, 1.0), theta) - c = cos(theta); s = sin(theta) + c = cos(theta) + s = sin(theta) Rz = [c -s 0; s c 0; 0 0 1] @test Mat3f(qz) ≈ Rz @@ -54,6 +56,6 @@ Base.cos(θ::Degree) = cos(θ.θ * π/180) # `π` is not an `AbstractFloat` but it is a `Number` @test to_rotation(π) == to_rotation(1.0π) @test to_rotation((v, π)) == to_rotation((v, 1.0π)) - @test to_rotation(Degree(90)) == to_rotation(π/2) - @test to_rotation((v, Degree(90))) == to_rotation((v, π/2)) + @test to_rotation(Degree(90)) == to_rotation(π / 2) + @test to_rotation((v, Degree(90))) == to_rotation((v, π / 2)) end diff --git a/test/record.jl b/test/record.jl index 9e2310a28ed..e99d69a85b8 100644 --- a/test/record.jl +++ b/test/record.jl @@ -1,25 +1,23 @@ using Logging module VideoBackend - using Makie - struct Screen <: MakieScreen - size::Tuple{Int, Int} - end - struct ScreenConfig - end - Base.size(screen::Screen) = screen.size - Screen(scene::Scene, config::ScreenConfig, ::Makie.ImageStorageFormat) = Screen(size(scene)) - Makie.backend_showable(::Type{Screen}, ::MIME"text/html") = true - Makie.backend_showable(::Type{Screen}, ::MIME"image/png") = true - Makie.colorbuffer(screen::Screen) = zeros(RGBf, reverse(screen.size)...) - Base.display(::Screen, ::Scene; kw...) = nothing +using Makie +struct Screen <: MakieScreen + size::Tuple{Int,Int} +end +struct ScreenConfig end +Base.size(screen::Screen) = screen.size +Screen(scene::Scene, config::ScreenConfig, ::Makie.ImageStorageFormat) = Screen(size(scene)) +Makie.backend_showable(::Type{Screen}, ::MIME"text/html") = true +Makie.backend_showable(::Type{Screen}, ::MIME"image/png") = true +Makie.colorbuffer(screen::Screen) = zeros(RGBf, reverse(screen.size)...) +Base.display(::Screen, ::Scene; kw...) = nothing end Makie.set_active_backend!(VideoBackend) # We need a screenconfig in the theme for every backend! set_theme!(VideoBackend=Attributes()) - mktempdir() do tempdir @testset "Video encoding" begin n = 2 @@ -41,12 +39,11 @@ mktempdir() do tempdir # test that the proper warnings are thrown @testset "Warnings" begin - function run_record(dst; kwargs...) + run_record(dst; kwargs...) = record(fig, dst, 1:n; kwargs...) do i lines!(ax, sin.(i .* x)) return nothing end - end # kwarg => (value, (should_warn => format)) warn_tests = [ diff --git a/test/runtests.jl b/test/runtests.jl index 5d46b19a92e..2f8a425ac98 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,7 +15,7 @@ using Makie: volume lims = Makie.data_limits(vplot) lo, hi = extrema(lims) @test all(lo .<= 1) - @test all(hi .>= (8,8,10)) + @test all(hi .>= (8, 8, 10)) end include("pipeline.jl") diff --git a/test/stack.jl b/test/stack.jl index e03b5779a8b..f798da07048 100644 --- a/test/stack.jl +++ b/test/stack.jl @@ -1,27 +1,27 @@ using Makie: stack_grouped_from_to @testset "grouped bar: stack" begin - x1 = [1, 1, 1, 1] - grp_dodge1 = [2, 2, 1, 1] - grp_stack1 = [1, 2, 1, 2] - y1 = [2, 3, -3, -2] + x1 = [1, 1, 1, 1] + grp_dodge1 = [2, 2, 1, 1] + grp_stack1 = [1, 2, 1, 2] + y1 = [2, 3, -3, -2] - x2 = [2, 2, 2, 2] - grp_dodge2 = [3, 4, 3, 4] - grp_stack2 = [3, 4, 3, 4] - y2 = [2, 3, -3, -2] + x2 = [2, 2, 2, 2] + grp_dodge2 = [3, 4, 3, 4] + grp_stack2 = [3, 4, 3, 4] + y2 = [2, 3, -3, -2] - from, to = stack_grouped_from_to(grp_stack1, y1, (; x1 = x1, grp_dodge1 = grp_dodge1)) - from1 = [0.0, 2.0, 0.0, -3.0] - to1 = [2.0, 5.0, -3.0, -5.0] + from, to = stack_grouped_from_to(grp_stack1, y1, (; x1=x1, grp_dodge1=grp_dodge1)) + from1 = [0.0, 2.0, 0.0, -3.0] + to1 = [2.0, 5.0, -3.0, -5.0] @test from == from1 - @test to == to1 + @test to == to1 - from, to = stack_grouped_from_to(grp_stack2, y2, (; x2 = x2, grp_dodge2 = grp_dodge2)) - from2 = [0.0, 0.0, 0.0, 0.0] - to2 = [2.0, 3.0, -3.0, -2.0] + from, to = stack_grouped_from_to(grp_stack2, y2, (; x2=x2, grp_dodge2=grp_dodge2)) + from2 = [0.0, 0.0, 0.0, 0.0] + to2 = [2.0, 3.0, -3.0, -2.0] @test from == from2 - @test to == to2 + @test to == to2 perm = [1, 4, 2, 7, 5, 3, 8, 6] x = [x1; x2][perm] @@ -32,7 +32,7 @@ using Makie: stack_grouped_from_to from_test = [from1; from2][perm] to_test = [to1; to2][perm] - from, to = stack_grouped_from_to(grp_stack, y, (; x = x, grp_dodge = grp_dodge)) + from, to = stack_grouped_from_to(grp_stack, y, (; x=x, grp_dodge=grp_dodge)) @test from == from_test @test to == to_test end diff --git a/test/statistical_tests.jl b/test/statistical_tests.jl index ca47a2f3cc9..6cba059483a 100644 --- a/test/statistical_tests.jl +++ b/test/statistical_tests.jl @@ -15,24 +15,24 @@ seed!(0) @test plt isa BarPlot x = h.edges[1] - @test plt[1][] ≈ Point{2, Float32}.(x[1:end-1] .+ step(x)/2, h.weights) + @test plt[1][] ≈ Point{2,Float32}.(x[1:(end - 1)] .+ step(x) / 2, h.weights) v = (randn(1000), randn(1000)) - h = fit(Histogram, v, nbins = 30) + h = fit(Histogram, v, nbins=30) fig, ax, plt = plot(h) @test plt isa Heatmap x = h.edges[1] y = h.edges[2] - @test plt[1][] ≈ x[1:end-1] .+ step(x)/2 - @test plt[2][] ≈ y[1:end-1] .+ step(y)/2 + @test plt[1][] ≈ x[1:(end - 1)] .+ step(x) / 2 + @test plt[2][] ≈ y[1:(end - 1)] .+ step(y) / 2 @test plt[3][] ≈ h.weights fig, ax, plt = surface(h) @test plt isa Surface x = h.edges[1] y = h.edges[2] - @test plt[1][] ≈ x[1:end-1] .+ step(x)/2 - @test plt[2][] ≈ y[1:end-1] .+ step(y)/2 + @test plt[1][] ≈ x[1:(end - 1)] .+ step(x) / 2 + @test plt[2][] ≈ y[1:(end - 1)] .+ step(y) / 2 @test plt[3][] ≈ h.weights v = (randn(1000), randn(1000), randn(1000)) @@ -43,9 +43,9 @@ seed!(0) x = h.edges[1] y = h.edges[2] z = h.edges[3] - @test plt[1][] ≈ x[1:end-1] .+ step(x)/2 - @test plt[2][] ≈ y[1:end-1] .+ step(y)/2 - @test plt[3][] ≈ z[1:end-1] .+ step(z)/2 + @test plt[1][] ≈ x[1:(end - 1)] .+ step(x) / 2 + @test plt[2][] ≈ y[1:(end - 1)] .+ step(y) / 2 + @test plt[3][] ≈ z[1:(end - 1)] .+ step(z) / 2 @test plt[4][] == h.weights end @@ -83,11 +83,11 @@ end fix, ax, plt = plot(d) @test plt isa Lines @test !Makie.isdiscrete(d) - @test first(plt[1][][1]) ≈ minimum(rg) rtol = 1f-6 - @test first(plt[1][][end]) ≈ maximum(rg) rtol = 1f-6 + @test first(plt[1][][1]) ≈ minimum(rg) rtol = 1.0f-6 + @test first(plt[1][][end]) ≈ maximum(rg) rtol = 1.0f-6 for (x, pd) in plt[1][] - @test pd ≈ Distributions.pdf(d, x) rtol = 1f-6 + @test pd ≈ Distributions.pdf(d, x) rtol = 1.0f-6 end d = Distributions.Poisson() @@ -118,14 +118,14 @@ end @test first.(plt[1][]) ≈ [extrema(q.qx)...] rtol = 1e-6 @test last.(plt[1][]) ≈ [extrema(q.qx)...] rtol = 1e-6 - fig, ax, p = qqnorm(v, qqline = nothing) + fig, ax, p = qqnorm(v, qqline=nothing) @test length(p.plots) == 1 plt = p.plots[1] @test plt isa Scatter @test first.(plt[1][]) ≈ q.qx rtol = 1e-6 @test last.(plt[1][]) ≈ q.qy rtol = 1e-6 - fig, ax, p = qqnorm(v, qqline = :fit) + fig, ax, p = qqnorm(v, qqline=:fit) plt = p.plots[2] itc, slp = hcat(fill!(similar(q.qx), 1), q.qx) \ q.qy xs = [extrema(q.qx)...] @@ -133,7 +133,7 @@ end @test first.(plt[1][]) ≈ xs rtol = 1e-6 @test last.(plt[1][]) ≈ ys rtol = 1e-6 - fig, ax, p = qqnorm(v, qqline = :quantile) + fig, ax, p = qqnorm(v, qqline=:quantile) plt = p.plots[2] xs = [extrema(q.qx)...] quantx, quanty = quantile(q.qx, [0.25, 0.75]), quantile(q.qy, [0.25, 0.75]) @@ -162,7 +162,7 @@ end @test pts[1] == Point2f0(vmin - eps(vmin), 0) @test pts[11][2] == 1 - fig, ax, p5 = plot(2..3, ecdf(1:10)) + fig, ax, p5 = plot(2 .. 3, ecdf(1:10)) pts = p5[1][] @test pts[1] == Point2f0(2 - eps(2.0), 0.1) @test pts[2] == Point2f0(2, 0.2) @@ -179,23 +179,33 @@ end fig, ax, p = crossbar(1, 3, 2, 4) @test p isa CrossBar @test p.plots[1] isa Poly - @test p.plots[1][1][] == [Rect2f(Float32[0.6, 2.0], Float32[0.8, 2.0]),] + @test p.plots[1][1][] == [Rect2f(Float32[0.6, 2.0], Float32[0.8, 2.0])] @test p.plots[2] isa LineSegments @test p.plots[2][1][] == Point{2,Float32}[Float32[0.6, 3.0], Float32[1.4, 3.0]] - fig, ax, p = crossbar(1, 3, 2, 4; show_notch = true, notchmin = 2.5, notchmax = 3.5); + fig, ax, p = crossbar(1, 3, 2, 4; show_notch=true, notchmin=2.5, notchmax=3.5) @test p isa CrossBar @test p.plots[1] isa Poly @test p.plots[1][1][][1] isa Makie.AbstractMesh - poly = Point{2,Float32}[[0.6, 2.0], [1.4, 2.0], [1.4, 2.5], [1.2, 3.0], [1.4, 3.5], - [1.4, 4.0], [0.6, 4.0], [0.6, 3.5], [0.8, 3.0], [0.6, 2.5]] + poly = Point{2,Float32}[ + [0.6, 2.0], + [1.4, 2.0], + [1.4, 2.5], + [1.2, 3.0], + [1.4, 3.5], + [1.4, 4.0], + [0.6, 4.0], + [0.6, 3.5], + [0.8, 3.0], + [0.6, 2.5], + ] @test map(Point2f, p.plots[1][1][][1].position) == poly @test p.plots[2] isa LineSegments @test p.plots[2][1][] == Point{2,Float32}[Float32[0.8, 3.0], Float32[1.2, 3.0]] end @testset "boxplot" begin - a = repeat(1:5, inner = 20) + a = repeat(1:5, inner=20) b = 1:100 fig, ax, p = boxplot(a, b) plts = p.plots @@ -204,24 +214,56 @@ end @test isempty(plts[1][1][]) # test categorical - a = repeat(["a", "b", "c", "d", "e"], inner = 20) + a = repeat(["a", "b", "c", "d", "e"], inner=20) b = 1:100 - fig, ax, p = boxplot(a, b; whiskerwidth = 1.0) + fig, ax, p = boxplot(a, b; whiskerwidth=1.0) plts = p.plots @test length(plts) == 3 @test plts[1] isa Scatter @test isempty(plts[1][1][]) @test plts[2] isa LineSegments - pts = Point{2, Float32}[ - [1.0, 5.75], [1.0, 1.0], [0.6, 1.0], [1.4, 1.0], [1.0, 15.25], - [1.0, 20.0], [1.4, 20.0], [0.6, 20.0], [2.0, 25.75], [2.0, 21.0], - [1.6, 21.0], [2.4, 21.0], [2.0, 35.25], [2.0, 40.0], [2.4, 40.0], - [1.6, 40.0], [3.0, 45.75], [3.0, 41.0], [2.6, 41.0], [3.4, 41.0], - [3.0, 55.25], [3.0, 60.0], [3.4, 60.0], [2.6, 60.0], [4.0, 65.75], - [4.0, 61.0], [3.6, 61.0], [4.4, 61.0], [4.0, 75.25], [4.0, 80.0], - [4.4, 80.0], [3.6, 80.0], [5.0, 85.75], [5.0, 81.0], [4.6, 81.0], - [5.4, 81.0], [5.0, 95.25], [5.0, 100.0], [5.4, 100.0], [4.6, 100.0] + pts = Point{2,Float32}[ + [1.0, 5.75], + [1.0, 1.0], + [0.6, 1.0], + [1.4, 1.0], + [1.0, 15.25], + [1.0, 20.0], + [1.4, 20.0], + [0.6, 20.0], + [2.0, 25.75], + [2.0, 21.0], + [1.6, 21.0], + [2.4, 21.0], + [2.0, 35.25], + [2.0, 40.0], + [2.4, 40.0], + [1.6, 40.0], + [3.0, 45.75], + [3.0, 41.0], + [2.6, 41.0], + [3.4, 41.0], + [3.0, 55.25], + [3.0, 60.0], + [3.4, 60.0], + [2.6, 60.0], + [4.0, 65.75], + [4.0, 61.0], + [3.6, 61.0], + [4.4, 61.0], + [4.0, 75.25], + [4.0, 80.0], + [4.4, 80.0], + [3.6, 80.0], + [5.0, 85.75], + [5.0, 81.0], + [4.6, 81.0], + [5.4, 81.0], + [5.0, 95.25], + [5.0, 100.0], + [5.4, 100.0], + [4.6, 100.0], ] @test plts[2][1][] == pts @@ -245,14 +287,46 @@ end @test length(plts) == 3 pts = Point{2,Float32}[ - [1.0, 5.75], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 15.25], - [1.0, 20.0], [1.0, 20.0], [1.0, 20.0], [2.0, 25.75], [2.0, 21.0], - [2.0, 21.0], [2.0, 21.0], [2.0, 35.25], [2.0, 40.0], [2.0, 40.0], - [2.0, 40.0], [3.0, 45.75], [3.0, 41.0], [3.0, 41.0], [3.0, 41.0], - [3.0, 55.25], [3.0, 60.0], [3.0, 60.0], [3.0, 60.0], [4.0, 65.75], - [4.0, 61.0], [4.0, 61.0], [4.0, 61.0], [4.0, 75.25], [4.0, 80.0], - [4.0, 80.0], [4.0, 80.0], [5.0, 85.75], [5.0, 81.0], [5.0, 81.0], - [5.0, 81.0], [5.0, 95.25], [5.0, 100.0], [5.0, 100.0], [5.0, 100.0], + [1.0, 5.75], + [1.0, 1.0], + [1.0, 1.0], + [1.0, 1.0], + [1.0, 15.25], + [1.0, 20.0], + [1.0, 20.0], + [1.0, 20.0], + [2.0, 25.75], + [2.0, 21.0], + [2.0, 21.0], + [2.0, 21.0], + [2.0, 35.25], + [2.0, 40.0], + [2.0, 40.0], + [2.0, 40.0], + [3.0, 45.75], + [3.0, 41.0], + [3.0, 41.0], + [3.0, 41.0], + [3.0, 55.25], + [3.0, 60.0], + [3.0, 60.0], + [3.0, 60.0], + [4.0, 65.75], + [4.0, 61.0], + [4.0, 61.0], + [4.0, 61.0], + [4.0, 75.25], + [4.0, 80.0], + [4.0, 80.0], + [4.0, 80.0], + [5.0, 85.75], + [5.0, 81.0], + [5.0, 81.0], + [5.0, 81.0], + [5.0, 95.25], + [5.0, 100.0], + [5.0, 100.0], + [5.0, 100.0], ] @test plts[2] isa LineSegments @@ -261,11 +335,83 @@ end @test plts[3] isa CrossBar @test plts[3].plots[1] isa Poly - notch_boxes = Vector{Point{2,Float32}}[map(Point2f, [[0.6, 5.75], [1.4, 5.75], [1.4, 7.14366], [1.2, 10.5], [1.4, 13.8563], [1.4, 15.25], [0.6, 15.25], [0.6, 13.8563], [0.8, 10.5], [0.6, 7.14366]]), - map(Point2f, [[1.6, 25.75], [2.4, 25.75], [2.4, 27.1437], [2.2, 30.5], [2.4, 33.8563], [2.4, 35.25], [1.6, 35.25], [1.6, 33.8563], [1.8, 30.5], [1.6, 27.1437]]), - map(Point2f, [[2.6, 45.75], [3.4, 45.75], [3.4, 47.1437], [3.2, 50.5], [3.4, 53.8563], [3.4, 55.25], [2.6, 55.25], [2.6, 53.8563], [2.8, 50.5], [2.6, 47.1437]]), - map(Point2f, [[3.6, 65.75], [4.4, 65.75], [4.4, 67.1437], [4.2, 70.5], [4.4, 73.8563], [4.4, 75.25], [3.6, 75.25], [3.6, 73.8563], [3.8, 70.5], [3.6, 67.1437]]), - map(Point2f, [[4.6, 85.75], [5.4, 85.75], [5.4, 87.1437], [5.2, 90.5], [5.4, 93.8563], [5.4, 95.25], [4.6, 95.25], [4.6, 93.8563], [4.8, 90.5], [4.6, 87.1437]])] + notch_boxes = Vector{Point{2,Float32}}[ + map( + Point2f, + [ + [0.6, 5.75], + [1.4, 5.75], + [1.4, 7.14366], + [1.2, 10.5], + [1.4, 13.8563], + [1.4, 15.25], + [0.6, 15.25], + [0.6, 13.8563], + [0.8, 10.5], + [0.6, 7.14366], + ], + ), + map( + Point2f, + [ + [1.6, 25.75], + [2.4, 25.75], + [2.4, 27.1437], + [2.2, 30.5], + [2.4, 33.8563], + [2.4, 35.25], + [1.6, 35.25], + [1.6, 33.8563], + [1.8, 30.5], + [1.6, 27.1437], + ], + ), + map( + Point2f, + [ + [2.6, 45.75], + [3.4, 45.75], + [3.4, 47.1437], + [3.2, 50.5], + [3.4, 53.8563], + [3.4, 55.25], + [2.6, 55.25], + [2.6, 53.8563], + [2.8, 50.5], + [2.6, 47.1437], + ], + ), + map( + Point2f, + [ + [3.6, 65.75], + [4.4, 65.75], + [4.4, 67.1437], + [4.2, 70.5], + [4.4, 73.8563], + [4.4, 75.25], + [3.6, 75.25], + [3.6, 73.8563], + [3.8, 70.5], + [3.6, 67.1437], + ], + ), + map( + Point2f, + [ + [4.6, 85.75], + [5.4, 85.75], + [5.4, 87.1437], + [5.2, 90.5], + [5.4, 93.8563], + [5.4, 95.25], + [4.6, 95.25], + [4.6, 93.8563], + [4.8, 90.5], + [4.6, 87.1437], + ], + ), + ] meshes = plts[3].plots[1][1][] @testset for (i, mesh) in enumerate(meshes) @test mesh isa Makie.AbstractMesh @@ -277,7 +423,7 @@ end @testset "violin" begin x = repeat(1:4, 250) y = x .+ randn.() - fig, ax, p = violin(x, y, side = :left, color = :blue) + fig, ax, p = violin(x, y, side=:left, color=:blue) @test p isa Violin @test p.plots[1] isa Poly @test p.plots[1][:color][] == :blue @@ -287,7 +433,7 @@ end # test categorical x = repeat(["a", "b", "c", "d"], 250) - fig2, ax2, p2 = violin(x, y, side = :left, color = :blue) + fig2, ax2, p2 = violin(x, y, side=:left, color=:blue) @test p2 isa Violin @test p2.plots[1] isa Poly @test p2.plots[1][:color][] == :blue diff --git a/test/test_primitives.jl b/test/test_primitives.jl index 851d56866a4..eec3aafca9c 100644 --- a/test/test_primitives.jl +++ b/test/test_primitives.jl @@ -10,12 +10,12 @@ fig, ax, p = surface(rand(4, 7)) fig, ax, p = volume(rand(4, 4, 4)) begin fig, ax, p = heatmap(rand(4, 4)) - scatter!(Makie.point_iterator(p) |> collect, color=:red, markersize=10) + scatter!(collect(Makie.point_iterator(p)), color=:red, markersize=10) display(fig) end fig, ax, p = image(rand(4, 5)) -scatter!(Makie.point_iterator(p) |> collect, color=:red, markersize=10) +scatter!(collect(Makie.point_iterator(p)), color=:red, markersize=10) display(fig) begin diff --git a/test/text.jl b/test/text.jl index c0b1f427eae..50f5546a349 100644 --- a/test/text.jl +++ b/test/text.jl @@ -9,7 +9,7 @@ scene = Scene() campixel!(scene) - p = text!(scene, Point2f(30, 37), text = str, align = (:left, :baseline), fontsize = 20) + p = text!(scene, Point2f(30, 37), text=str, align=(:left, :baseline), fontsize=20) glyph_collection = p.plots[1][1][][] # This doesn't work well because FreeTypeAbstraction doesn't quite scale @@ -33,21 +33,19 @@ # This is just repeating code from Makie unit_extents = [FreeTypeAbstraction.get_extent(font, char) for char in chars] - origins = cumsum(20f0 * Float32[ - 0, - unit_extents[1].advance[1], - unit_extents[2].advance[1], - unit_extents[3].advance[1] - ]) + origins = cumsum( + 20.0f0 * + Float32[0, unit_extents[1].advance[1], unit_extents[2].advance[1], unit_extents[3].advance[1]], + ) @test glyph_collection isa Makie.GlyphCollection @test glyph_collection.glyphs == FreeTypeAbstraction.glyph_index.(font, chars) @test glyph_collection.fonts == [font for _ in 1:4] - @test all(isapprox.(glyph_collection.origins, [Point3f(x, 0, 0) for x in origins], atol = 1e-10)) + @test all(isapprox.(glyph_collection.origins, [Point3f(x, 0, 0) for x in origins], atol=1e-10)) @test glyph_collection.scales.sv == [Vec2f(p.fontsize[]) for _ in 1:4] - @test glyph_collection.rotations.sv == [Quaternionf(0,0,0,1) for _ in 1:4] - @test glyph_collection.colors.sv == [RGBAf(0,0,0,1) for _ in 1:4] - @test glyph_collection.strokecolors.sv == [RGBAf(0,0,0,0) for _ in 1:4] + @test glyph_collection.rotations.sv == [Quaternionf(0, 0, 0, 1) for _ in 1:4] + @test glyph_collection.colors.sv == [RGBAf(0, 0, 0, 1) for _ in 1:4] + @test glyph_collection.strokecolors.sv == [RGBAf(0, 0, 0, 0) for _ in 1:4] @test glyph_collection.strokewidths.sv == Float32[0, 0, 0, 0] makie_hi_bb = Makie.height_insensitive_boundingbox.(glyph_collection.extents) @@ -60,8 +58,11 @@ # Test quad data positions, char_offsets, quad_offsets, uvs, scales = Makie.text_quads( atlas, - to_ndim(Point3f, p.position[], 0), glyph_collection, - Vec2f(0), Makie.transform_func_obs(scene)[], :data + to_ndim(Point3f, p.position[], 0), + glyph_collection, + Vec2f(0), + Makie.transform_func_obs(scene)[], + :data, ) # Also doesn't work @@ -75,33 +76,34 @@ # end fta_quad_offsets = map(chars) do c - mini = FreeTypeAbstraction.metrics_bb(c, font, 20.0)[1] |> minimum - Vec2f(mini .- atlas.glyph_padding * 20.0 / atlas.pix_per_glyph) + mini = minimum(FreeTypeAbstraction.metrics_bb(c, font, 20.0)[1]) + return Vec2f(mini .- atlas.glyph_padding * 20.0 / atlas.pix_per_glyph) end fta_scales = map(chars) do c - mini = FreeTypeAbstraction.metrics_bb(c, font, 20.0)[1] |> widths - Vec2f(mini .+ 2 * atlas.glyph_padding * 20.0 / atlas.pix_per_glyph) + mini = widths(FreeTypeAbstraction.metrics_bb(c, font, 20.0)[1]) + return Vec2f(mini .+ 2 * atlas.glyph_padding * 20.0 / atlas.pix_per_glyph) end - @test all(isequal(to_ndim(Point3f, p.position[], 0f0)), positions) + @test all(isequal(to_ndim(Point3f, p.position[], 0.0f0)), positions) @test char_offsets == glyph_collection.origins @test quad_offsets == fta_quad_offsets - @test scales == fta_scales + @test scales == fta_scales end - @testset "old text syntax" begin - text("text", position = Point2f(0, 0)) - text(["text"], position = [Point2f(0, 0)]) - text(["text", "text"], position = [Point2f(0, 0), Point2f(1, 1)]) + text("text", position=Point2f(0, 0)) + text(["text"], position=[Point2f(0, 0)]) + text(["text", "text"], position=[Point2f(0, 0), Point2f(1, 1)]) text(collect(zip(["text", "text"], [Point2f(0, 0), Point2f(1, 1)]))) - text(L"text", position = Point2f(0, 0)) - text([L"text"], position = [Point2f(0, 0)]) - text([L"text", L"text"], position = [Point2f(0, 0), Point2f(1, 1)]) + text(L"text", position=Point2f(0, 0)) + text([L"text"], position=[Point2f(0, 0)]) + text([L"text", L"text"], position=[Point2f(0, 0), Point2f(1, 1)]) text(collect(zip([L"text", L"text"], [Point2f(0, 0), Point2f(1, 1)]))) - err = ArgumentError("The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.") - @test_throws err Label(Figure()[1, 1], "hi", textsize = 30) - @test_throws err text(1, 2, text = "hi", textsize = 30) + err = ArgumentError( + "The attribute `textsize` has been renamed to `fontsize` in Makie v0.19. Please change all occurrences of `textsize` to `fontsize` or revert back to an earlier version.", + ) + @test_throws err Label(Figure()[1, 1], "hi", textsize=30) + @test_throws err text(1, 2, text="hi", textsize=30) end diff --git a/test/transformations.jl b/test/transformations.jl index fd568f82534..69f71f628b5 100644 --- a/test/transformations.jl +++ b/test/transformations.jl @@ -4,19 +4,15 @@ using LinearAlgebra function xyz_boundingbox(trans, points) bb_ref = Base.RefValue(Rect3f()) Makie.foreach_transformed(points, Mat4f(I), trans) do point - Makie.update_boundingbox!(bb_ref, point) + return Makie.update_boundingbox!(bb_ref, point) end return bb_ref[] end @testset "Basic transforms" begin - function fpoint2(x::Point2) - return Point2f(x[1] + 10, x[2] - 77) - end + fpoint2(x::Point2) = Point2f(x[1] + 10, x[2] - 77) - function fpoint3(x::Point3) - return Point3f(x[1] + 10, x[2] - 77, x[3] / 4) - end + fpoint3(x::Point3) = Point3f(x[1] + 10, x[2] - 77, x[3] / 4) trans2 = PointTrans{2}(fpoint2) trans3 = PointTrans{3}(fpoint3) points2 = [Point2f(0, 0), Point2f(0, 1)] @@ -77,14 +73,15 @@ end @test apply_transform(i2, 1) == 1 @test apply_transform(i3, 1) == 1 - @test apply_transform(identity, 1..2) == 1..2 - @test apply_transform(i2, 1..2) == 1..2 - @test apply_transform(i3, 1..2) == 1..2 + @test apply_transform(identity, 1 .. 2) == 1 .. 2 + @test apply_transform(i2, 1 .. 2) == 1 .. 2 + @test apply_transform(i3, 1 .. 2) == 1 .. 2 pa = Point2f(1, 2) pb = Point2f(3, 4) r2 = Rect2f(pa, pb .- pa) - @test apply_transform(t1, r2) == Rect2f(apply_transform(t1, pa), apply_transform(t1, pb) .- apply_transform(t1, pa) ) + @test apply_transform(t1, r2) == + Rect2f(apply_transform(t1, pa), apply_transform(t1, pb) .- apply_transform(t1, pa)) end @testset "Coordinate Systems" begin @@ -96,7 +93,7 @@ end end end - scene = Scene(cam = cam3d!) + scene = Scene(cam=cam3d!) scatter!(scene, [Point3f(-10), Point3f(10)]) for space in vcat(spaces...) @test Makie.clip_to_space(scene.camera, space) * Makie.space_to_clip(scene.camera, space) ≈ Mat4f(I) @@ -104,16 +101,14 @@ end end @testset "Bounding box utilities" begin - - box = Rect2f(0,0,1,1) + box = Rect2f(0, 0, 1, 1) @test Makie.rotatedrect(box, π) == Rect2f(-1, -1, 1, 1) - @test Makie.rotatedrect(box, π/2) == Rect2f(0, -1, 1, 1) - - @test all(Makie.rotatedrect(box, π/4).origin .≈ Rect2f(0, -1/(√2f0), √2f0, √2f0).origin) - @test all(Makie.rotatedrect(box, π/4).widths .≈ Rect2f(0, -1/(√2f0), √2f0, √2f0).widths) + @test Makie.rotatedrect(box, π / 2) == Rect2f(0, -1, 1, 1) + @test all(Makie.rotatedrect(box, π / 4).origin .≈ Rect2f(0, -1 / (√2.0f0), √2.0f0, √2.0f0).origin) + @test all(Makie.rotatedrect(box, π / 4).widths .≈ Rect2f(0, -1 / (√2.0f0), √2.0f0, √2.0f0).widths) end @testset "Space dependent transforms" begin @@ -125,10 +120,10 @@ end p3 = Point(2.0, 5.0, 4.0) spaces_and_desired_transforms = Dict( - :data => (x,y) -> y, # uses changes - :clip => (x,y) -> x, # no change - :relative => (x,y) -> x, # no change - :pixel => (x,y) -> x, # no transformation + :data => (x, y) -> y, # uses changes + :clip => (x, y) -> x, # no change + :relative => (x, y) -> x, # no change + :pixel => (x, y) -> x, # no transformation ) for (space, desired_transform) in spaces_and_desired_transforms @test apply_transform(identity, p2, space) == p2 @@ -140,6 +135,7 @@ end @test apply_transform(t2, p2, space) == desired_transform(p2, Point2f(sqrt(2.0), log(5.0))) @test apply_transform(t2, p3, space) == desired_transform(p3, Point3f(sqrt(2.0), log(5.0), 4.0)) - @test apply_transform(t3, p3, space) == desired_transform(p3, Point3f(sqrt(2.0), log(5.0), log10(4.0))) - end + @test apply_transform(t3, p3, space) == + desired_transform(p3, Point3f(sqrt(2.0), log(5.0), log10(4.0))) + end end diff --git a/test/zoom_pan.jl b/test/zoom_pan.jl index 8a5a3e5daa7..acd7adc6db2 100644 --- a/test/zoom_pan.jl +++ b/test/zoom_pan.jl @@ -13,17 +13,17 @@ end @testset "zoom Axis" begin ax, axbox, lim, e = cleanaxes() # Put the mouse in the center - e.mouseposition[] = Tuple(axbox.origin + axbox.widths/2) + e.mouseposition[] = Tuple(axbox.origin + axbox.widths / 2) # zoom in e.scroll[] = (0.0, -1.0) newlim = ax.finallimits[] @test newlim.widths ≈ 0.9 * lim.widths - @test newlim.origin ≈ lim.origin + (lim.widths - newlim.widths)/2 + @test newlim.origin ≈ lim.origin + (lim.widths - newlim.widths) / 2 # zoom out restores original position e.scroll[] = (0.0, 1.0) newlim = ax.finallimits[] @test newlim.widths ≈ lim.widths - @test all(abs.(newlim.origin - lim.origin) .< 1e-7*lim.widths) + @test all(abs.(newlim.origin - lim.origin) .< 1e-7 * lim.widths) ax.finallimits[] = lim # Put mouse in corner e.mouseposition[] = Tuple(axbox.origin) @@ -31,12 +31,12 @@ end e.scroll[] = (0.0, -1.0) newlim = ax.finallimits[] @test newlim.widths ≈ 0.9 * lim.widths - @test all(abs.(newlim.origin - lim.origin) .< 1e-7*lim.widths) + @test all(abs.(newlim.origin - lim.origin) .< 1e-7 * lim.widths) # zoom out e.scroll[] = (0.0, 1.0) newlim = ax.finallimits[] @test newlim.widths ≈ lim.widths - @test all(abs.(newlim.origin - lim.origin) .< 1e-7*lim.widths) + @test all(abs.(newlim.origin - lim.origin) .< 1e-7 * lim.widths) ax.finallimits[] = lim # Zoom only x or y @@ -45,17 +45,18 @@ end lock = getproperty(ax, lockname) @test !lock[] lock[] = true - e.mouseposition[] = Tuple(axbox.origin + axbox.widths/2) + e.mouseposition[] = Tuple(axbox.origin + axbox.widths / 2) e.scroll[] = (0.0, -1.0) newlim = ax.finallimits[] @test newlim.widths[idx] == lim.widths[idx] - @test newlim.widths[3-idx] ≈ 0.9 * lim.widths[3-idx] + @test newlim.widths[3 - idx] ≈ 0.9 * lim.widths[3 - idx] @test newlim.origin[idx] == lim.origin[idx] - @test newlim.origin[3-idx] ≈ lim.origin[3-idx] + (lim.widths[3-idx] - newlim.widths[3-idx])/2 + @test newlim.origin[3 - idx] ≈ + lim.origin[3 - idx] + (lim.widths[3 - idx] - newlim.widths[3 - idx]) / 2 e.scroll[] = (0.0, 1.0) newlim = ax.finallimits[] @test newlim.widths ≈ lim.widths - @test all(abs.(newlim.origin - lim.origin) .< 1e-7*lim.widths) + @test all(abs.(newlim.origin - lim.origin) .< 1e-7 * lim.widths) ax.finallimits[] = lim lock[] = false # Simulate pressing the keys @@ -66,13 +67,14 @@ end e.scroll[] = (0.0, -1.0) newlim = ax.finallimits[] @test newlim.widths[idx] == lim.widths[idx] - @test newlim.widths[3-idx] ≈ 0.9 * lim.widths[3-idx] + @test newlim.widths[3 - idx] ≈ 0.9 * lim.widths[3 - idx] @test newlim.origin[idx] == lim.origin[idx] - @test newlim.origin[3-idx] ≈ lim.origin[3-idx] + (lim.widths[3-idx] - newlim.widths[3-idx])/2 + @test newlim.origin[3 - idx] ≈ + lim.origin[3 - idx] + (lim.widths[3 - idx] - newlim.widths[3 - idx]) / 2 e.scroll[] = (0.0, 1.0) newlim = ax.finallimits[] @test newlim.widths ≈ lim.widths - @test all(abs.(newlim.origin - lim.origin) .< 1e-7*lim.widths) + @test all(abs.(newlim.origin - lim.origin) .< 1e-7 * lim.widths) end # Rubber band selection @@ -104,23 +106,23 @@ end empty!(e.mousebuttons[]) empty!(keypresses) newlim = ax.finallimits[] - @test all(lim.origin .>= newlim.origin) && all(lim.origin+lim.widths .<= newlim.origin+newlim.widths) + @test all(lim.origin .>= newlim.origin) && all(lim.origin + lim.widths .<= newlim.origin + newlim.widths) end @testset "pan Axis" begin ax, axbox, lim, e = cleanaxes() - e.mouseposition[] = Tuple(axbox.origin + axbox.widths/2) + e.mouseposition[] = Tuple(axbox.origin + axbox.widths / 2) e.scroll[] = (0.0, -1.0) newlim = ax.finallimits[] e.mouseposition[] = Tuple(axbox.origin) panbtn = ax.panbutton[] e.mousebuttons[] = Set([panbtn]) e.mousedrag[] = Mouse.down - e.mouseposition[] = Tuple(axbox.origin + axbox.widths/10) + e.mouseposition[] = Tuple(axbox.origin + axbox.widths / 10) e.mousedrag[] = Mouse.pressed e.mousebuttons[] = Set{typeof(panbtn)}() e.mousedrag[] = Mouse.up panlim = ax.finallimits[] @test panlim.widths == newlim.widths - @test (5/4)*panlim.origin ≈ -newlim.origin + @test (5 / 4) * panlim.origin ≈ -newlim.origin end