Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
73768eb
initial attempt of tricontourf
jkrumbiegel Aug 17, 2022
3746435
use miniqhull instead
jkrumbiegel Aug 18, 2022
7d8ffb0
use modified implementation of getting contours
jkrumbiegel Aug 18, 2022
daa0c07
add docs page
jkrumbiegel Aug 18, 2022
ff74772
colormap example
jkrumbiegel Aug 18, 2022
79882c6
add colorbar to docs
jkrumbiegel Aug 21, 2022
91e8a0c
add visual tests
jkrumbiegel Aug 21, 2022
3c64c80
add compat bounds
jkrumbiegel Aug 21, 2022
a1e06bb
use static rng
jkrumbiegel Aug 21, 2022
d6f3f1d
add option to pass matrix of triangles instead
jkrumbiegel Aug 21, 2022
3e4ce8e
shift to separate file
jkrumbiegel Aug 23, 2022
e65ad43
add triangulation example
jkrumbiegel Aug 23, 2022
2e9787d
add same example to tests
jkrumbiegel Aug 23, 2022
575c057
add news
jkrumbiegel Aug 23, 2022
faf8fa6
Merge branch 'master' into jk/tricontourf
SimonDanisch Aug 24, 2022
6fa497e
Merge branch 'master' into jk/tricontourf
SimonDanisch Aug 24, 2022
df4e006
fix missing contours
jkrumbiegel Aug 25, 2022
bcb8f17
Merge branch 'master' into jk/tricontourf
jkrumbiegel Sep 17, 2022
32c48a3
type plot function correctly for method errors
jkrumbiegel Sep 19, 2022
e1b819f
add CairoMakie tricontourf override
jkrumbiegel Sep 19, 2022
fbe6ecb
map(Point2f
jkrumbiegel Sep 19, 2022
6d9102a
factor out shared code between contourf and tricontourf
jkrumbiegel Sep 19, 2022
d990217
Merge branch 'master' into jk/tricontourf
SimonDanisch Sep 22, 2022
32c878b
Merge branch 'master' into jk/tricontourf
jkrumbiegel Sep 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions CairoMakie/src/overrides.jl
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,38 @@ function draw_plot(scene::Scene, screen::CairoScreen,

nothing
end

#################################################################################
# Tricontourf #
# Tricontourf creates many disjoint polygons that are adjacent and form contour #
# bands, however, at the gaps we see white antialiasing artifacts. Therefore #
# we override behavior and draw each band in one go #
#################################################################################

function draw_plot(scene::Scene, screen::CairoScreen, tric::Tricontourf)

pol = only(tric.plots)::Poly
colornumbers = pol.color[]
colors = numbers_to_colors(colornumbers, pol)

polygons = pol[1][]

model = pol.model[]
space = to_value(get(pol, :space, :data))
projected_polys = project_polygon.(Ref(scene), space, polygons, Ref(model))

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]
Cairo.set_source_rgba(screen.context, rgbatuple(col)...)
Cairo.fill(screen.context)
end
end
return
end

draw_tripolys(projected_polys, colornumbers, colors)

return
end
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## master

- Added the `tricontourf` plotting function [#2226](https://github.com/JuliaPlots/Makie.jl/pull/2226).
- Fix per character attributes in text [#2244](https://github.com/JuliaPlots/Makie.jl/pull/2244)
- `Axis` does now accept both a `Bool` and a `Tuple{Bool, Bool}` as values for `xtrimspine` and `ytrimspine` to trim only one end of the spine [#2171](https://github.com/JuliaPlots/Makie.jl/pull/2171).
- Added `BezierPath` which can be constructed from SVG like command list, SVG string or from a `Polygon`.
Expand Down
4 changes: 4 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
Match = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf"
MathTeXEngine = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53"
MiniQhull = "978d7f02-9e05-4691-894f-ae31a51d76ca"
Observables = "510215fc-4207-5dde-b226-833fc4488ee2"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
Packing = "19eb6ba3-879d-56ad-ad62-d5c202156566"
Expand All @@ -49,6 +50,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
TriplotBase = "981d1d27-644d-49a2-9326-4793e63143c3"
UnicodeFun = "1cfade01-22cf-5700-b092-accc4b62d6e1"

[compat]
Expand All @@ -75,6 +77,7 @@ KernelDensity = "0.5, 0.6"
LaTeXStrings = "1.2"
MakieCore = "=0.4.0"
Match = "1.1"
MiniQhull = "0.3"
MathTeXEngine = "0.5"
Observables = "0.5.1"
OffsetArrays = "1"
Expand All @@ -88,5 +91,6 @@ SnoopPrecompile = "1.0"
StatsBase = "0.31, 0.32, 0.33"
StatsFuns = "0.9, 1.0"
StructArrays = "0.3, 0.4, 0.5, 0.6"
TriplotBase = "=0.1.0"
UnicodeFun = "0.4"
julia = "1.3"
57 changes: 56 additions & 1 deletion ReferenceTests/src/tests/examples2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,61 @@ end
f
end

@reference_test "tricontourf" begin
x = RNG.randn(50)
y = RNG.randn(50)
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)
Colorbar(f[1, 2], tr)
f
end

@reference_test "tricontourf extendhigh extendlow" begin
x = RNG.randn(50)
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)
Colorbar(f[1, 2], tr)
f
end

@reference_test "tricontourf relative mode" begin
x = RNG.randn(50)
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)
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.()

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 = 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
end

@reference_test "marker offset in data space" begin
f = Figure()
ax = Axis(f[1, 1]; xticks=0:1, yticks=0:10)
Expand All @@ -571,4 +626,4 @@ end

f
end
end
end
100 changes: 100 additions & 0 deletions docs/examples/plotting_functions/tricontourf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# tricontourf

{{doc tricontourf}}

## Examples

\begin{examplefigure}{svg = true}
```julia
using CairoMakie
CairoMakie.activate!() # hide
Makie.inline!(true) # hide
using Random
Random.seed!(1234)

x = randn(50)
y = randn(50)
z = -sqrt.(x .^ 2 .+ y .^ 2) .+ 0.1 .* randn.()

f, ax, tr = tricontourf(x, y, z)
scatter!(x, y, color = z, strokewidth = 1, strokecolor = :black)
Colorbar(f[1, 2], tr)
f
```
\end{examplefigure}

\begin{examplefigure}{svg = true}
```julia
using CairoMakie
CairoMakie.activate!() # hide
Makie.inline!(true) # hide
using Random
Random.seed!(1234)

x = randn(200)
y = randn(200)
z = x .* y

f, ax, tr = tricontourf(x, y, z, colormap = :batlow)
scatter!(x, y, color = z, colormap = :batlow, strokewidth = 1, strokecolor = :black)
Colorbar(f[1, 2], tr)
f
```
\end{examplefigure}

#### Triangulation modes

\begin{examplefigure}{svg = true}
```julia
using CairoMakie
CairoMakie.activate!() # hide
Makie.inline!(true) # hide
using Random
Random.seed!(123)

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.*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 = 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
```
\end{examplefigure}

#### Relative mode

Sometimes it's beneficial to drop one part of the range of values, usually towards the outer boundary.
Rather than specifying the levels to include manually, you can set the `mode` attribute
to `:relative` and specify the levels from 0 to 1, relative to the current minimum and maximum value.

\begin{examplefigure}{svg = true}
```julia
using CairoMakie
CairoMakie.activate!() # hide
Makie.inline!(true) # hide
using Random
Random.seed!(1234)

x = randn(50)
y = randn(50)
z = -sqrt.(x .^ 2 .+ y .^ 2) .+ 0.1 .* randn.()

f, ax, tr = tricontourf(x, y, z, mode = :relative, levels = 0.2:0.1:1)
scatter!(x, y, color = z, strokewidth = 1, strokecolor = :black)
Colorbar(f[1, 2], tr)
f
```
\end{examplefigure}
3 changes: 3 additions & 0 deletions src/Makie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ import GridLayoutBase
import ImageIO
import FileIO
import SparseArrays
import TriplotBase
import MiniQhull

using IntervalSets: IntervalSets, (..), OpenInterval, ClosedInterval, AbstractInterval, Interval, endpoints
using FixedPointNumbers: N0f8
Expand Down Expand Up @@ -140,6 +142,7 @@ include("basic_recipes/stairs.jl")
include("basic_recipes/stem.jl")
include("basic_recipes/streamplot.jl")
include("basic_recipes/timeseries.jl")
include("basic_recipes/tricontourf.jl")
include("basic_recipes/volumeslices.jl")
include("basic_recipes/wireframe.jl")

Expand Down
50 changes: 6 additions & 44 deletions src/basic_recipes/contourf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,60 +72,26 @@ end
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))
end

colorrange = lift(c._computed_levels) do levels
minimum(levels), maximum(levels)
end
computed_colormap = lift(c._computed_levels, c.colormap, c.extendlow,
c.extendhigh) do levels, cmap, elow, ehigh
levels_scaled = (levels .- minimum(levels)) ./ (maximum(levels) - minimum(levels))
n = length(levels_scaled)

if elow == :auto && !(ehigh == :auto)
cm_base = cgrad(cmap, n + 1; categorical=true)[2:end]
cm = cgrad(cm_base, levels_scaled; categorical=true)
elseif ehigh == :auto && !(elow == :auto)
cm_base = cgrad(cmap, n + 1; categorical=true)[1:(end - 1)]
cm = cgrad(cm_base, levels_scaled; categorical=true)
elseif ehigh == :auto && elow == :auto
cm_base = cgrad(cmap, n + 2; categorical=true)[2:(end - 1)]
cm = cgrad(cm_base, levels_scaled; categorical=true)
else
cm = cgrad(cmap, levels_scaled; categorical=true)
end
return cm
end
computed_colormap = lift(compute_contourf_colormap, c._computed_levels, c.colormap, c.extendlow,
c.extendhigh)
c.attributes[:_computed_colormap] = computed_colormap

lowcolor = Observable{RGBAf}()
map!(lowcolor, c.extendlow, c.colormap) do el, cmap
if isnothing(el)
return RGBAf(0, 0, 0, 0)
elseif el === automatic || el == :auto
return RGBAf(to_colormap(cmap)[begin])
else
return to_color(el)::RGBAf
end
end
map!(compute_lowcolor, lowcolor, c.extendlow, c.colormap)
c.attributes[:_computed_extendlow] = lowcolor
is_extended_low = lift(x -> !isnothing(x), lowcolor)
is_extended_low = lift(!isnothing, lowcolor)

highcolor = Observable{RGBAf}()
map!(highcolor, c.extendhigh, c.colormap) do eh, cmap
if isnothing(eh)
return RGBAf(0, 0, 0, 0)
elseif eh === automatic || eh == :auto
return RGBAf(to_colormap(cmap)[end])
else
return to_color(eh)::RGBAf
end
end
map!(compute_highcolor, highcolor, c.extendhigh, c.colormap)
c.attributes[:_computed_extendhigh] = highcolor
is_extended_high = lift(x -> !isnothing(x), highcolor)
is_extended_high = lift(!isnothing, highcolor)

PolyType = typeof(Polygon(Point2f[], [Point2f[]]))

Expand All @@ -143,13 +109,9 @@ function Makie.plot!(c::Contourf{<:Tuple{<:AbstractVector{<:Real}, <:AbstractVec
lows = levels[1:end-1]
highs = levels[2:end]

nbands = length(lows)
# zs needs to be transposed to match rest of makie
isos = Isoband.isobands(xs, ys, zs', lows, highs)

allvertices = Point2f[]
allfaces = NgonFace{3,OffsetInteger{-1,UInt32}}[]
allids = Int[]
levelcenters = (highs .+ lows) ./ 2

for (i, (center, group)) in enumerate(zip(levelcenters, isos))
Expand Down
Loading