diff --git a/CairoMakie/Project.toml b/CairoMakie/Project.toml index 7ce30776da2..40a15c43faa 100644 --- a/CairoMakie/Project.toml +++ b/CairoMakie/Project.toml @@ -1,7 +1,7 @@ name = "CairoMakie" uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" author = ["Simon Danisch "] -version = "0.10.7" +version = "0.10.8" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" @@ -23,7 +23,7 @@ FFTW = "1" FileIO = "1.1" FreeType = "3, 4.0" GeometryBasics = "0.4.1" -Makie = "=0.19.7" +Makie = "=0.19.8" PrecompileTools = "1.0" julia = "1.3" diff --git a/CairoMakie/src/overrides.jl b/CairoMakie/src/overrides.jl index a124920c0be..25da6a9c9c6 100644 --- a/CairoMakie/src/overrides.jl +++ b/CairoMakie/src/overrides.jl @@ -102,6 +102,7 @@ function draw_poly(scene::Scene, screen::Screen, poly, rects::Vector{<:Rect2}) end function polypath(ctx, polygon) + isempty(polygon) && return nothing ext = decompose(Point2f, polygon.exterior) Cairo.set_fill_type(ctx, Cairo.CAIRO_FILL_RULE_EVEN_ODD) Cairo.move_to(ctx, ext[1]...) diff --git a/CairoMakie/src/primitives.jl b/CairoMakie/src/primitives.jl index e94d5156759..212b6ba1f62 100644 --- a/CairoMakie/src/primitives.jl +++ b/CairoMakie/src/primitives.jl @@ -58,8 +58,10 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Unio # stroke each segment separately, this means disjointed segments with probably # wonky dash patterns if segments are short - # we can hide the gaps by setting the line cap to round - Cairo.set_line_cap(ctx, Cairo.CAIRO_LINE_CAP_ROUND) + # Butted segments look the best for varying colors, at least when connection angles are small. + # While round style has nicer sharp joins, it looks bad with alpha colors (double paint) and + # also messes with dash patterns (they are too long because of the caps) + Cairo.set_line_cap(ctx, Cairo.CAIRO_LINE_CAP_BUTT) draw_multi( primitive, ctx, projected_positions, @@ -158,30 +160,22 @@ function draw_multi(primitive, ctx, positions, color, linewidths::AbstractArray, 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) - if primitive isa LineSegments - @assert iseven(length(positions)) - end +function draw_multi(primitive::LineSegments, ctx, positions, colors::AbstractArray, linewidths::AbstractArray, dash) + @assert iseven(length(positions)) @assert length(positions) == length(colors) @assert length(linewidths) == length(colors) - iterator = if primitive isa Lines - 1:length(positions)-1 - elseif primitive isa LineSegments - 1:2:length(positions) - end - - for i in iterator + for i in 1:2:length(positions) 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.") end + Cairo.move_to(ctx, positions[i]...) + Cairo.line_to(ctx, positions[i+1]...) Cairo.set_line_width(ctx, linewidths[i]) + !isnothing(dash) && Cairo.set_dash(ctx, dash .* linewidths[i]) c1 = colors[i] c2 = colors[i+1] @@ -199,8 +193,99 @@ function draw_multi(primitive::Union{Lines, LineSegments}, ctx, positions, color Cairo.destroy(pat) end end - # force clearing of path in case of skipped NaN - Cairo.new_path(ctx) +end + +function draw_multi(primitive::Lines, ctx, positions, colors::AbstractArray, linewidths::AbstractArray, dash) + @assert length(positions) == length(colors) + @assert length(linewidths) == length(colors) + + prev_color = colors[begin] + prev_linewidth = linewidths[begin] + prev_position = positions[begin] + prev_nan = isnan(prev_position) + prev_continued = false + + if !prev_nan + # first is not nan, move_to + Cairo.move_to(ctx, positions[begin]...) + else + # first is nan, do nothing + end + + for i in eachindex(positions)[2:end] + this_position = positions[i] + this_color = colors[i] + this_nan = isnan(this_position) + this_linewidth = linewidths[i] + if this_nan + # this is nan + if prev_continued + # and this is prev_continued, so set source and stroke to finish previous line + Cairo.set_line_width(ctx, this_linewidth) + !isnothing(dash) && Cairo.set_dash(ctx, dash .* this_linewidth) + Cairo.set_source_rgba(ctx, red(prev_color), green(prev_color), blue(prev_color), alpha(prev_color)) + Cairo.stroke(ctx) + else + # but this is not prev_continued, so do nothing + end + end + if prev_nan + # previous was nan + if !this_nan + # but this is not nan, so move to this position + Cairo.move_to(ctx, this_position...) + else + # and this is also nan, do nothing + end + else + if this_color == prev_color + # this color is like the previous + if !this_nan + # and this is not nan, so line_to and set prev_continued + this_linewidth != prev_linewidth && error("Encountered two different linewidth values $prev_linewidth and $this_linewidth in `lines` at index $(i-1). Different linewidths in one line are only permitted in CairoMakie when separated by a NaN point.") + Cairo.line_to(ctx, this_position...) + prev_continued = true + + if i == lastindex(positions) + # this is the last element so stroke this + Cairo.set_line_width(ctx, this_linewidth) + !isnothing(dash) && Cairo.set_dash(ctx, dash .* this_linewidth) + Cairo.set_source_rgba(ctx, red(this_color), green(this_color), blue(this_color), alpha(this_color)) + Cairo.stroke(ctx) + end + else + # but this is nan, so do nothing + end + else + prev_continued = false + if !this_nan + this_linewidth != prev_linewidth && error("Encountered two different linewidth values $prev_linewidth and $this_linewidth in `lines` at index $(i-1). Different linewidths in one line are only permitted in CairoMakie when separated by a NaN point.") + # this is not nan + # and this color is different than the previous, so move_to prev and line_to this + # create gradient pattern and stroke + Cairo.move_to(ctx, prev_position...) + Cairo.line_to(ctx, this_position...) + !isnothing(dash) && Cairo.set_dash(ctx, dash .* this_linewidth) + Cairo.set_line_width(ctx, this_linewidth) + + pat = Cairo.pattern_create_linear(prev_position..., this_position...) + Cairo.pattern_add_color_stop_rgba(pat, 0, red(prev_color), green(prev_color), blue(prev_color), alpha(prev_color)) + Cairo.pattern_add_color_stop_rgba(pat, 1, red(this_color), green(this_color), blue(this_color), alpha(this_color)) + Cairo.set_source(ctx, pat) + Cairo.stroke(ctx) + Cairo.destroy(pat) + + Cairo.move_to(ctx, this_position...) + else + # this is nan, do nothing + end + end + end + prev_nan = this_nan + prev_color = this_color + prev_linewidth = linewidths[i] + prev_position = this_position + end end ################################################################################ diff --git a/GLMakie/Project.toml b/GLMakie/Project.toml index 52af9bc22e1..06f998ca642 100644 --- a/GLMakie/Project.toml +++ b/GLMakie/Project.toml @@ -1,6 +1,6 @@ name = "GLMakie" uuid = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" -version = "0.8.7" +version = "0.8.8" [deps] ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" @@ -29,7 +29,7 @@ FixedPointNumbers = "0.7, 0.8" FreeTypeAbstraction = "0.10" GLFW = "3" GeometryBasics = "0.4.1" -Makie = "=0.19.7" +Makie = "=0.19.8" MeshIO = "0.4" ModernGL = "1" Observables = "0.5.1" diff --git a/MakieCore/Project.toml b/MakieCore/Project.toml index 8f276dee845..1db14f9ab24 100644 --- a/MakieCore/Project.toml +++ b/MakieCore/Project.toml @@ -1,7 +1,7 @@ authors = ["Simon Danisch"] name = "MakieCore" uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b" -version = "0.6.4" +version = "0.6.5" [deps] Observables = "510215fc-4207-5dde-b226-833fc4488ee2" diff --git a/MakieCore/src/basic_plots.jl b/MakieCore/src/basic_plots.jl index 897216bdd31..f186f92cb8c 100644 --- a/MakieCore/src/basic_plots.jl +++ b/MakieCore/src/basic_plots.jl @@ -521,6 +521,7 @@ Plots polygons, which are defined by Vector or Matrices of numbers can be used as well, which will use the colormap arguments to map the numbers to colors. One can also use `Makie.LinePattern`, to cover the poly with a regular stroke pattern. - `strokecolor::Union{Symbol, <:Colorant} = :black` sets the color of the outline around a marker. +- `strokecolormap`::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. - `strokewidth::Real = 0` sets the width of the outline around a marker. - `linestyle::Union{Nothing, Symbol, Vector} = nothing` sets the pattern of the line (e.g. `:solid`, `:dot`, `:dashdot`) @@ -533,6 +534,7 @@ $(Base.Docs.doc(MakieCore.generic_plot_attributes!)) color = theme(scene, :patchcolor), strokecolor = theme(scene, :patchstrokecolor), + strokecolormap = theme(scene, :colormap), strokewidth = theme(scene, :patchstrokewidth), linestyle = nothing, diff --git a/NEWS.md b/NEWS.md index 60d47c47e24..4f763ea11b9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,12 @@ ## master -- Allow arbitrary reversible scale functions through `Makie.ReversibleScale`. +- Allow arbitrary reversible scale functions through `Makie.ReversibleScale` [#3095](https://github.com/MakieOrg/Makie.jl/pull/3095). + +## v0.19.8 + +- Improved CairoMakie rendering of `lines` with repeating colors in an array [#3141](https://github.com/MakieOrg/Makie.jl/pull/3141). +- Added `strokecolormap` to poly. [#3145](https://github.com/MakieOrg/Makie.jl/pull/3145) - Added `xreversed`, `yreversed` and `zreversed` attributes to `Axis3` [#3138](https://github.com/MakieOrg/Makie.jl/pull/3138). - Fixed incorrect placement of contourlabels with transform functions [#3083](https://github.com/MakieOrg/Makie.jl/pull/3083) - Fixed automatic normal generation for meshes with shading and no normals [#3041](https://github.com/MakieOrg/Makie.jl/pull/3041). diff --git a/Project.toml b/Project.toml index 95b654d9bf1..0a842086115 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Makie" uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" authors = ["Simon Danisch", "Julius Krumbiegel"] -version = "0.19.7" +version = "0.19.8" [deps] Animations = "27a7e980-b3e6-11e9-2bcd-0b925532e340" @@ -82,7 +82,7 @@ Isoband = "0.1" KernelDensity = "0.5, 0.6" LaTeXStrings = "1.2" MacroTools = "0.5" -MakieCore = "=0.6.4" +MakieCore = "=0.6.5" Match = "1.1" MathTeXEngine = "0.5" Observables = "0.5.3" diff --git a/README.md b/README.md index c7c8d2eb2e4..49c5a3ccaa1 100644 --- a/README.md +++ b/README.md @@ -3,41 +3,52 @@ Makie.jl logo + src="/assets/makie_logo_canvas.svg" width="350">
-[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/MakieOrg/Makie.jl/blob/main/LICENSE) -[![][docs-stable-img]][docs-stable-url] [![][docs-master-img]][docs-master-url][![JOSS][joss-img]][joss-url] +[![][docs-stable-img]][docs-stable-url] +[![][docs-master-img]][docs-master-url] + [![Build Status](https://github.com/MakieOrg/Makie.jl/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/MakieOrg/Makie.jl/actions/workflows/ci.yml?query=branch%3Amaster) -[![](https://img.shields.io/twitter/url/https/twitter.com/cloudposse.svg?style=social&label=Follow%20%40MakiePlots)](https://twitter.com/MakiePlots) -[![chat][discord-img]][discord-url] +[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/MakieOrg/Makie.jl/blob/main/LICENSE) [![Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/Makie&label=Downloads)](https://pkgs.genieframework.com?packages=Makie) +[![JOSS][joss-img]][joss-url] +[![Citation Badge](https://api.juleskreuer.eu/citation-badge.php?doi=10.21105/joss.03349)](https://juleskreuer.eu/projekte/citation-badge) + +[![](https://img.shields.io/badge/Twitter-@MakiePlots-1DA1F2?&logo=twitter&logoColor=white)](https://twitter.com/MakiePlots) +[![chat][discord-img]][discord-url] +
-From the japanese word [_Maki-e_](https://en.wikipedia.org/wiki/Maki-e), which is a technique to sprinkle lacquer with gold and silver powder. +Makie is an interactive data visualization and plotting ecosystem for the [Julia programming language](https://julialang.org/), available on Windows, Linux and Mac. +The backend packages **GLMakie**, **WGLMakie**, **CairoMakie** and **RPRMakie** add different functionalities: +You can use Makie to interactively explore your data and create simple GUIs +in native windows or web browsers, export high-quality vector graphics or even raytrace with physically accurate lighting. + +The name Makie (we pronounce it Mah-kee) is derived from the japanese word [_Maki-e_](https://en.wikipedia.org/wiki/Maki-e), which is a technique to sprinkle lacquer with gold and silver powder. Data is the gold and silver of our age, so let's spread it out beautifully on the screen! -[Check out the documentation here!](http://docs.makie.org/stable/) +To learn more, we invite you to visit the documentation at [docs.makie.org](http://docs.makie.org/stable/). [gitlab-img]: https://gitlab.com/JuliaGPU/Makie.jl/badges/master/pipeline.svg [gitlab-url]: https://gitlab.com/JuliaGPU/Makie.jl/pipelines -[docs-stable-img]: https://img.shields.io/badge/docs-stable-lightgrey.svg +[docs-stable-img]: https://img.shields.io/badge/Docs-Stable-lightgrey.svg [docs-stable-url]: http://docs.makie.org/stable/ -[docs-master-img]: https://img.shields.io/badge/docs-master-blue.svg +[docs-master-img]: https://img.shields.io/badge/Docs-Dev-blue.svg [docs-master-url]: http://docs.makie.org/dev/ [joss-url]: https://doi.org/10.21105/joss.03349 [joss-img]: http://joss.theoj.org/papers/10.21105/joss.03349/status.svg [discord-url]: https://discord.com/invite/2FBjYAT3cY -[discord-img]: https://img.shields.io/discord/996787732149981214.svg?logo=discord&colorB=7289DA&style=flat-square +[discord-img]: https://img.shields.io/discord/996787732149981214.svg?logo=discord&colorB=7289DA&label=Discord ## Citing Makie -If you use Makie for a scientific publication, please cite [our JOSS paper](https://joss.theoj.org/papers/10.21105/joss.03349) the following way: +If you use Makie for a scientific publication, please acknowledge and support our work by citing [our JOSS paper](https://joss.theoj.org/papers/10.21105/joss.03349) the following way: ``` Danisch & Krumbiegel, (2021). Makie.jl: Flexible high-performance data visualization for Julia. @@ -72,15 +83,17 @@ We are on [Discord](https://discord.com/invite/2FBjYAT3cY) and [Discourse](https ## Installation -Please consider using the backends directly. As explained in the documentation, they re-export all of Makie's functionality. -So, instead of installing Makie, just install e.g. GLMakie directly: +Choose one or more backend packages: **GLMakie** (interactive OpenGL in native OS windows), **WGLMakie** (interactive WebGL in browsers, IDEs, notebooks), **CairoMakie** (static 2D vector graphics and images) and **RPRMakie** (raytracing). +Each backend re-exports all of Makie.jl so you don't have to install or load it explicitly. + +Install: ```julia julia>] pkg> add GLMakie ``` -You may check the installed version with: +Check the installed version: ```julia ]st GLMakie @@ -129,7 +142,7 @@ save("./assets/parabola.png", fig) fig ``` - + ### A more complex plot with unicode characters and LaTeX strings: [Similar to the one on this link]() @@ -141,26 +154,27 @@ fig x = -2pi:0.1:2pi approx = fill(0.0, length(x)) cmap = [:gold, :deepskyblue3, :orangered, "#e82051"] -set_theme!(palette = (; patchcolor = cgrad(cmap, alpha=0.45))) -fig, axis, lineplot = lines(x, sin.(x); label = L"sin(x)", linewidth = 3, color = :black, - axis = (; title = "Polynomial approximation of sin(x)", - xgridstyle = :dash, ygridstyle = :dash, - xticksize = 10, yticksize = 10, xtickalign = 1, ytickalign = 1, - xticks = (-π:π/2:π, ["π", "-π/2", "0", "π/2", "π"]) - )) -translate!(lineplot, 0, 0, 2) # move line to foreground -band!(x, sin.(x), approx .+= x; label = L"n = 0") -band!(x, sin.(x), approx .+= -x .^ 3 / 6; label = L"n = 1") -band!(x, sin.(x), approx .+= x .^ 5 / 120; label = L"n = 2") -band!(x, sin.(x), approx .+= -x .^ 7 / 5040; label = L"n = 3") -limits!(-3.8, 3.8, -1.5, 1.5) -axislegend(; position = :ct, bgcolor = (:white, 0.75), framecolor = :orange) -save("./assets/approxsin.png", fig, resolution = (800, 600)) -fig +with_theme(palette = (; patchcolor = cgrad(cmap, alpha=0.45))) do + fig, axis, lineplot = lines(x, sin.(x); label = L"sin(x)", linewidth = 3, color = :black, + axis = (; title = "Polynomial approximation of sin(x)", + xgridstyle = :dash, ygridstyle = :dash, + xticksize = 10, yticksize = 10, xtickalign = 1, ytickalign = 1, + xticks = (-π:π/2:π, ["π", "-π/2", "0", "π/2", "π"]) + )) + translate!(lineplot, 0, 0, 2) # move line to foreground + band!(x, sin.(x), approx .+= x; label = L"n = 0") + band!(x, sin.(x), approx .+= -x .^ 3 / 6; label = L"n = 1") + band!(x, sin.(x), approx .+= x .^ 5 / 120; label = L"n = 2") + band!(x, sin.(x), approx .+= -x .^ 7 / 5040; label = L"n = 3") + limits!(-3.8, 3.8, -1.5, 1.5) + axislegend(; position = :ct, bgcolor = (:white, 0.75), framecolor = :orange) + save("./assets/approxsin.png", fig, resolution = (800, 600)) + fig +end ``` - + ### Simple layout: Heatmap, contour and 3D surface plot @@ -171,28 +185,27 @@ fig x = y = -5:0.5:5 z = x .^ 2 .+ y' .^ 2 cmap = :plasma -set_theme!(colormap = cmap) -fig = Figure(fontsize = 22) -ax3d = Axis3(fig[1, 1]; aspect = (1, 1, 1), - perspectiveness = 0.5, azimuth = 2.19, elevation = 0.57) -ax2d = Axis(fig[1, 2]; aspect = 1, xlabel = "x", ylabel="y") -pltobj = surface!(ax3d, x, y, z; transparency = true) -heatmap!(ax2d, x, y, z; colormap = (cmap, 0.65)) -contour!(ax2d, x, y, z; linewidth = 2, levels = 12, color = :black) -contour3d!(ax3d, x, y, z; linewidth = 4, levels = 12, - transparency = true) -Colorbar(fig[1, 3], pltobj; label="z", labelrotation=pi) -colsize!(fig.layout, 1, Aspect(1, 1.0)) -colsize!(fig.layout, 2, Aspect(1, 1.0)) -resize_to_layout!(fig) -save("./assets/simpleLayout.png", fig) -fig +with_theme(colormap = cmap) do + fig = Figure(fontsize = 22) + ax3d = Axis3(fig[1, 1]; aspect = (1, 1, 1), + perspectiveness = 0.5, azimuth = 2.19, elevation = 0.57) + ax2d = Axis(fig[1, 2]; aspect = 1, xlabel = "x", ylabel="y") + pltobj = surface!(ax3d, x, y, z; transparency = true) + heatmap!(ax2d, x, y, z; colormap = (cmap, 0.65)) + contour!(ax2d, x, y, z; linewidth = 2, levels = 12, color = :black) + contour3d!(ax3d, x, y, z; linewidth = 4, levels = 12, + transparency = true) + Colorbar(fig[1, 3], pltobj; label="z", labelrotation=pi) + colsize!(fig.layout, 1, Aspect(1, 1.0)) + colsize!(fig.layout, 2, Aspect(1, 1.0)) + resize_to_layout!(fig) + save("./assets/simpleLayout.png", fig) + fig +end ``` - - -⚠️WARNING⚠️. Don't forget to reset to the default Makie settings by doing `set_theme!()`. + Interactive example by [AlexisRenchon](https://github.com/AlexisRenchon): diff --git a/RPRMakie/Project.toml b/RPRMakie/Project.toml index 564a226a6f8..af1b0811261 100644 --- a/RPRMakie/Project.toml +++ b/RPRMakie/Project.toml @@ -1,7 +1,7 @@ name = "RPRMakie" uuid = "22d9f318-5e34-4b44-b769-6e3734a732a6" authors = ["Simon Danisch"] -version = "0.5.7" +version = "0.5.8" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" @@ -17,7 +17,7 @@ julia = "1.3" Colors = "0.9, 0.10, 0.11, 0.12" FileIO = "1.6" GeometryBasics = "0.4.1" -Makie = "=0.19.7" +Makie = "=0.19.8" RadeonProRender = "0.3.0" [extras] diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index 4404c707f14..55e5308fe84 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -1128,3 +1128,41 @@ end # Display fig end + +@reference_test "Plotting empty polygons" begin + p = Makie.Polygon(Point2f[]) + q = Makie.Polygon(Point2f[(-1.0, 0.0), (1.0, 0.0), (0.0, 1.0)]) + fig, ax, sc = poly([p, q]) + poly!(Axis(fig[1,2]), p, color = :black) + poly!(Axis(fig[2,1]), [p, q], color = [:red, :blue]) + poly!(Axis(fig[2,2]), [p, q], color = :red) + poly!(Axis(fig[3,1]), Makie.MultiPolygon([p]), color = :green) + poly!(Axis(fig[3,2]), Makie.MultiPolygon([p, q]), color = [:black, :red]) + fig +end + +@reference_test "lines (some with NaNs) with array colors" begin + f = Figure() + ax = Axis(f[1, 1]) + hidedecorations!(ax) + hidespines!(ax) + lines!(ax, 1:10, 1:10, color = fill(RGBAf(1, 0, 0, 0.5), 10), linewidth = 5) + lines!(ax, 1:10, 2:11, color = [fill(RGBAf(1, 0, 0, 0.5), 5); fill(RGBAf(0, 0, 1, 0.5), 5)], linewidth = 5) + lines!(ax, 1:10, [3, 4, NaN, 6, 7, NaN, 9, 10, 11, NaN], color = [fill(RGBAf(1, 0, 0, 0.5), 5); fill(RGBAf(0, 0, 1, 0.5), 5)], linewidth = 5) + lines!(ax, 1:10, 4:13, color = repeat([RGBAf(1, 0, 0, 0.5), RGBAf(0, 0, 1, 0.5)], 5), linewidth = 5) + lines!(ax, 1:10, fill(NaN, 10), color = repeat([RGBAf(1, 0, 0, 0.5), RGBAf(0, 0, 1, 0.5)], 5), linewidth = 5) + lines!(ax, 1:10, [6, 7, 8, NaN, 10, 11, 12, 13, 14, 15], color = [:red, :blue, fill(:red, 8)...], linewidth = 5) + lines!(ax, 1:3, [7, 8, 9], color = [:red, :red, :blue], linewidth = 5) + lines!(ax, 1:3, [8, 9, NaN], color = [:red, :red, :blue], linewidth = 5) + lines!(ax, 1:3, [NaN, 10, 11], color = [:red, :red, :blue], linewidth = 5) + lines!(ax, 1:5, [10, 11, NaN, 13, 14], color = [:red, :red, :blue, :blue, :blue], linewidth = [5, 5, 5, 10, 10]) + lines!(ax, 1:10, 11:20, color = [fill(RGBAf(1, 0, 0, 0.5), 5); fill(RGBAf(0, 0, 1, 0.5), 5)], linewidth = 5, linestyle = :dot) + lines!(ax, 1:10, 12:21, color = fill(RGBAf(1, 0, 0, 0.5), 10), linewidth = 5, linestyle = :dot) + f +end + +@reference_test "contour with single alpha color" begin + x = range(-π, π; length=50) + z = @. sin(x) * cos(x') + fig, ax = contour(x, x, z, color=RGBAf(1,0,0,0.4), linewidth=6) +end diff --git a/WGLMakie/Project.toml b/WGLMakie/Project.toml index 598a901393a..e4c1ea1c489 100644 --- a/WGLMakie/Project.toml +++ b/WGLMakie/Project.toml @@ -1,7 +1,7 @@ name = "WGLMakie" uuid = "276b4fcb-3e11-5398-bf8b-a0c2d153d008" authors = ["SimonDanisch "] -version = "0.8.11" +version = "0.8.12" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" @@ -26,7 +26,7 @@ FreeTypeAbstraction = "0.10" GeometryBasics = "0.4.1" Hyperscript = "0.0.3, 0.0.4" JSServe = "2.2" -Makie = "=0.19.7" +Makie = "=0.19.8" Observables = "0.5.1" RelocatableFolders = "0.1, 0.2, 0.3, 1.0" ShaderAbstractions = "0.3" diff --git a/docs/examples/plotting_functions/poly.md b/docs/examples/plotting_functions/poly.md index 2f946fcd1a3..b15bfda6397 100644 --- a/docs/examples/plotting_functions/poly.md +++ b/docs/examples/plotting_functions/poly.md @@ -99,3 +99,26 @@ poly!(ps, color = rand(RGBf, length(ps))) f ``` \end{examplefigure} + +\begin{examplefigure}{} +```julia +using CairoMakie +CairoMakie.activate!() # hide +using Makie.GeometryBasics + + +f = Figure() +Axis(f[1, 1]) + +# vector of shapes +poly!( + [Rect(i, j, 0.75, 0.5) for i in 1:5 for j in 1:3], + color = :white, + strokewidth = 2, + strokecolor = 1:15, + strokecolormap=:plasma, +) + +f +``` +\end{examplefigure} \ No newline at end of file diff --git a/src/basic_recipes/poly.jl b/src/basic_recipes/poly.jl index fcf9c857776..038f9be82a1 100644 --- a/src/basic_recipes/poly.jl +++ b/src/basic_recipes/poly.jl @@ -30,7 +30,8 @@ function plot!(plot::Poly{<: Tuple{Union{GeometryBasics.Mesh, GeometryPrimitive} 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] + inspectable = plot[:inspectable], transparency = plot[:transparency], + colormap = plot[:strokecolormap] ) end @@ -40,7 +41,11 @@ function poly_convert(geometries) return triangle_mesh.(geometries) end poly_convert(meshes::AbstractVector{<:AbstractMesh}) = meshes -poly_convert(polys::AbstractVector{<:Polygon}) = triangle_mesh.(polys) +function poly_convert(polys::AbstractVector{<:Polygon}) + # GLPlainMesh2D is not concrete? + T = GeometryBasics.Mesh{2, Float32, GeometryBasics.Ngon{2, Float32, 3, Point2f}, SimpleFaceView{2, Float32, 3, GLIndex, Point2f, GLTriangleFace}} + return isempty(polys) ? T[] : triangle_mesh.(polys) +end function poly_convert(multipolygons::AbstractVector{<:MultiPolygon}) return [merge(triangle_mesh.(multipoly.polygons)) for multipoly in multipolygons] end @@ -81,7 +86,7 @@ end function to_lines(polygon::AbstractVector{<: VecTypes}) result = Point2f.(polygon) - push!(result, polygon[1]) + isempty(result) || push!(result, polygon[1]) return result end @@ -124,6 +129,7 @@ function plot!(plot::Poly{<: Tuple{<: Union{Polygon, AbstractVector{<: PolyEleme lines!( plot, outline, visible = plot.visible, color = stroke, linestyle = plot.linestyle, alpha = plot.alpha, + colormap = plot.strokecolormap, linewidth = plot.strokewidth, space = plot.space, overdraw = plot.overdraw, transparency = plot.transparency, inspectable = plot.inspectable, depth_shift = -1f-5 diff --git a/src/interaction/iodevices.jl b/src/interaction/iodevices.jl index 416f8580f69..4d6d2855d1d 100644 --- a/src/interaction/iodevices.jl +++ b/src/interaction/iodevices.jl @@ -170,6 +170,11 @@ module Mouse middle = 2 right = 1 # Conform to GLFW none = -1 # for convenience + button_4 = 3 + button_5 = 4 + button_6 = 5 + button_7 = 6 + button_8 = 7 end """ diff --git a/src/makielayout/blocks/polaraxis.jl b/src/makielayout/blocks/polaraxis.jl index 27997c40748..f536dfdbe53 100644 --- a/src/makielayout/blocks/polaraxis.jl +++ b/src/makielayout/blocks/polaraxis.jl @@ -107,13 +107,19 @@ function draw_axis!(po::PolarAxis, axis_radius) onany( po.blockscene, - po.rticks, po.rminorticks, po.rtickformat, + po.rticks, po.rminorticks, po.rtickformat, po.rticklabelpad, po.rtickangle, po.target_radius, axis_radius, po.sample_density, - ) do rticks, rminorticks, rtickformat, rtickangle, data_radius, axis_radius, sample_density + po.overlay.px_area + ) do rticks, rminorticks, rtickformat, px_pad, rtickangle, data_radius, axis_radius, sample_density, pixelarea _rtickvalues, _rticklabels = Makie.get_ticks(rticks, identity, rtickformat, 0, data_radius) _rtickpos = _rtickvalues .* (axis_radius / data_radius) # we still need the values - rtick_pos_lbl[] = tuple.(_rticklabels, Point2f.(_rtickpos, rtickangle)) + pad = let + w2, h2 = (0.5 .* widths(pixelarea)).^2 + s, c = sincos(rtickangle) + axis_radius * px_pad / sqrt(w2 * c * c + h2 * s * s) + end + rtick_pos_lbl[] = tuple.(_rticklabels, Point2f.(_rtickpos .+ pad, rtickangle)) thetas = LinRange(thetalims..., sample_density) rgridpoints[] = Makie.GeometryBasics.LineString.([Point2f.(r, thetas) for r in _rtickpos]) @@ -133,8 +139,8 @@ function draw_axis!(po::PolarAxis, axis_radius) onany( po.blockscene, po.thetaticks, po.thetaminorticks, po.thetatickformat, po.thetaticklabelpad, - po.theta_0, axis_radius, po.overlay.px_area - ) do thetaticks, thetaminorticks, thetatickformat, px_pad, theta_0, axis_radius, pixelarea + po.direction, po.theta_0, axis_radius, po.overlay.px_area + ) do thetaticks, thetaminorticks, thetatickformat, px_pad, dir, theta_0, axis_radius, pixelarea _thetatickvalues, _thetaticklabels = Makie.get_ticks(thetaticks, identity, thetatickformat, 0, 2pi) @@ -147,7 +153,7 @@ function draw_axis!(po::PolarAxis, axis_radius) end thetatick_align[] = map(_thetatickvalues) do angle - s, c = sincos(angle + theta_0) + s, c = sincos(dir * (angle + theta_0)) scale = 1 / max(abs(s), abs(c)) # point on ellipse -> point on bbox Point2f(0.5 - 0.5scale * c, 0.5 - 0.5scale * s) end @@ -249,7 +255,11 @@ function draw_axis!(po::PolarAxis, axis_radius) color = po.rticklabelcolor, strokewidth = po.rticklabelstrokewidth, strokecolor = rstrokecolor, - align = (:left, :bottom), + align = map(po.direction, po.theta_0, po.rtickangle) do dir, theta_0, angle + s, c = sincos(dir * (angle + theta_0)) + scale = 1 / max(abs(s), abs(c)) # point on ellipse -> point on bbox + Point2f(0.5 - 0.5scale * c, 0.5 - 0.5scale * s) + end ) thetastrokecolor = map(po.blockscene, clipcolor, po.thetaticklabelstrokecolor) do bg, sc diff --git a/src/makielayout/mousestatemachine.jl b/src/makielayout/mousestatemachine.jl index 0fdd41e3bfe..472db916485 100644 --- a/src/makielayout/mousestatemachine.jl +++ b/src/makielayout/mousestatemachine.jl @@ -122,6 +122,9 @@ function addmouseevents!(scene, bbox::Observables.AbstractObservable{<: Rect2}; end +# don't react to buttons beyond the first three +_isstandardmousebutton(b) = (b == Mouse.left || b == Mouse.middle || b == Mouse.right) + function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) Mouse = Makie.Mouse dblclick_max_interval = 0.2 @@ -156,7 +159,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) # this can mean a new drag started, or a drag continues if it is ongoing. # 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 last_mouseevent[] == Mouse.press && _isstandardmousebutton(mouse_downed_button[]) if drag_ongoing[] # continue the drag @@ -241,7 +244,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) # mouse went down, this can either happen inside or outside the objects of interest # we also only react if one button is pressed, because otherwise things go crazy (pressed left button plus clicks from other buttons in between are not allowed, e.g.) - if event.action == Mouse.press + if event.action == Mouse.press && _isstandardmousebutton(first(pressed_buttons)) if length(pressed_buttons) == 1 button = first(pressed_buttons) mouse_downed_button[] = button @@ -267,7 +270,7 @@ function _addmouseevents!(scene, is_mouse_over_relevant_area, priority) end end last_mouseevent[] = Mouse.press - elseif event.action == Mouse.release + elseif event.action == Mouse.release && _isstandardmousebutton(mouse_downed_button[]) # only register up events and clicks if the upped button matches # the recorded downed one # and it can't be nothing (if the first up event comes from outside) diff --git a/src/makielayout/types.jl b/src/makielayout/types.jl index 47228158bed..3a4527d50c0 100644 --- a/src/makielayout/types.jl +++ b/src/makielayout/types.jl @@ -1679,6 +1679,8 @@ end rticklabelstrokewidth = 0.0 "The color of the outline of `r` ticks. By default this uses the background color." rticklabelstrokecolor = automatic + "Padding of the `r` ticks label." + rticklabelpad = 4f0 "Controls if the `r` ticks are visible." rticklabelsvisible = inherit(scene, (:Axis, :xticklabelsvisible), true) "The angle in radians along which the `r` ticks are printed." diff --git a/test/conversions.jl b/test/conversions.jl index 881062c02c3..56cd2e809a8 100644 --- a/test/conversions.jl +++ b/test/conversions.jl @@ -278,12 +278,27 @@ end @testset "empty poly" begin + # Geometry Primitive 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}[]) + # Empty Polygon + f, ax, pl = poly(Polygon(Point2f[])); + pl[1] = Polygon(Point2f[(1,0), (1,1), (0,1)]); + @test pl.plots[1][1][] == GeometryBasics.triangle_mesh(pl[1][]) + + f, ax, pl = poly(Polygon[]); + pl[1] = [Polygon(Point2f[(1,0), (1,1), (0,1)])]; + @test pl.plots[1][1][] == GeometryBasics.triangle_mesh.(pl[1][]) + + # PointBased inputs + f, ax, pl = poly(Point2f[]) points = decompose(Point2f, Circle(Point2f(0),1)) + pl[1] = points + @test pl.plots[1][1][] == Makie.poly_convert(points) + + f, ax, pl = poly(Vector{Point2f}[]) pl[1] = [points] @test pl.plots[1][1][] == Makie.poly_convert(points) end