11module PyramidSchemeMakieExt
22using Makie: Axis, Colorbar, DataAspect, Figure, FigureAxisPlot, Observable, Relative
3- using Makie: on, heatmap!, image!
4- import Makie: plot, plot!
3+ using Makie: on, heatmap!, map!
4+ using Makie. ComputePipeline: add_input!
5+ using Makie
6+
57using PyramidScheme: Pyramid, switchkeys, levels, selectlevel, xkey, ykey
68using DimensionalData: DimensionalData as DD
79using DimensionalData. Dimensions: XDim, YDim
810using Extents: Extent, extent, intersects
9- """
10- plot(pyramids)
11- Plot a Pyramid.
12- This will plot the coarsest resolution level at the beginning and will plot higher resolutions after zooming into the plot.
13- This is expected to be used with interactive Makie backends.
14- """
15- function plot(pyramid :: Pyramid ;colorbar = true , kwargs... )
16- # This should be converted into a proper recipe for Makie but this would depend on a pyramid type.
17- fig = Figure()
18- lon, lat = DD . dims(DD . parent(pyramid) )
19- ax = Axis(fig[ 1 , 1 ], limits = (extrema(lon), extrema(lat)), aspect = DataAspect() )
20- hmap = plot!(ax, pyramid;kwargs ... )
21- if colorbar
22- Colorbar(fig[ 1 , 2 ], hmap, height = Relative( 3.5 / 4 ) )
11+ miss2nan(x) = ismissing(x) ? NaN : x
12+
13+ # hacks to get around DD hacks that get around Makie issues
14+ for p in (Heatmap, Image, Contour, Contourf, Contour3d, Spy, Surface)
15+ f = Makie. plotkey(p)
16+ @eval begin
17+ function Makie. $ f(A :: Pyramid ; kwargs... )
18+ invoke( Makie. $ f, Tuple{AbstractMatrix{ <: Any }}, A; kwargs ... )
19+ end
20+ function Makie. $ f(A :: Observable{<: Pyramid} ; kwargs ... )
21+ invoke(Makie. $ f, Tuple{ <: Union{<:AbstractMatrix{<: Any}, <:Observable{<: AbstractMatrix{<:Any}}} }, A; kwargs ... )
22+ end
23+ Makie . expand_dimensions( :: Type{$p} , p :: Pyramid ) = (p,)
24+ Makie . convert_arguments( :: Type{$p} , p :: Pyramid ) = (p, )
2325 end
24- ax. autolimitaspect = 1
25- FigureAxisPlot(fig, ax, hmap)
2626end
2727
28- function plot!(ax, pyramid:: Pyramid ;interp= false , kwargs... )# ; rastercrs=crs(parent(pyramid)),plotcrs=EPSG(3857), kwargs...)
29- tip = levels(pyramid)[end - 2 ][:,:]
30- # @show typeof(tip)
31- data = Observable{DD. AbstractDimMatrix}(tip)
32- xval = only(values(extent(pyramid, XDim)))
33- yval = only(values(extent(pyramid, YDim)))
34- rasdataext = Extent(X= xval, Y= yval)
35- rasext = extent(pyramid)
36- xk = xkey(rasext)
37- yk = ykey(rasext)
38- on(ax. scene. viewport) do viewport
39- limext = extent(ax. finallimits[])
40-
41- datalimit = switchkeys(limext, rasext)
42-
43- data. val = selectlevel(pyramid, datalimit, target_imsize= viewport. widths)
44- notify(data)
45- end
46- on(ax. finallimits) do limits
47- limext = extent(limits)
48- # Compute limit in raster projection
49- # trans = Proj.Transformation(plotcrs, rastercrs, always_xy=true)
50- # datalimit = trans_bounds(trans, limext)
51- datalimit = switchkeys(limext, rasext)
52- if intersects(rasdataext, limext)
53- rasdata = selectlevel(pyramid, datalimit, target_imsize= ax. scene. viewport[]. widths)
54- # Project selected data to plotcrs
55- # data.val = Rasters.resample(rasdata, crs=plotcrs, method=:bilinear )
56- data. val = rasdata
28+ struct PyramidConversion <: Makie.ConversionTrait end
29+
30+ function Makie. conversion_trait(:: Type{<:Heatmap} , :: Pyramid )
31+ return PyramidConversion()
32+ end
33+
34+ function Makie. types_for_plot_arguments(:: Type{<:Heatmap} , :: PyramidConversion )
35+ return Tuple{<: Pyramid }
36+ end
37+
38+ Makie. expand_dimensions(:: PyramidConversion , p:: Pyramid ) = (p,)
39+ Makie. convert_arguments(:: PyramidConversion , p:: Pyramid ) = (p,)
40+
41+
42+
43+ Makie. plottype(:: Pyramid ) = Makie. Heatmap
44+
45+ function Makie. plot!(plot:: Heatmap{<: Tuple{<: Pyramid}} )
46+ #=
47+ Go from a relative space rectangle
48+ to the rectangle in data space and pixel space,
49+ thus getting `ax.finallimits` and `ax.viewport`
50+ respectively.
51+
52+ This is a bit arcane but probably the simplest thing in the long run.
53+ =#
54+ inputpositions = [Point2f(0 , 0 ), Point2f(1 , 1 )]
55+ add_input!(plot. attributes, :__pyramid_input_positions, inputpositions)
56+ Makie. register_positions_projected!(
57+ plot; input_space = :relative, output_space = :space,
58+ input_name = :__pyramid_input_positions,
59+ output_name = :__pyramid_dataspace_positions,
60+ )
61+ Makie. register_positions_projected!(
62+ plot; input_space = :relative, output_space = :pixel,
63+ input_name = :__pyramid_input_positions,
64+ output_name = :__pyramid_pixelspace_positions,
65+ )
66+
67+ data = Observable{DD. AbstractDimMatrix}(levels(plot. arg1[])[end - 2 ][:, :])
68+ onany(plot, plot. arg1, plot. __pyramid_dataspace_positions, plot. __pyramid_pixelspace_positions) do pyramid, datapos, pixelpos
69+ xyext = values.(extent(pyramid, (XDim, YDim)))
70+ xval, yval = first(xyext), last(xyext)
71+ pyramid_data_ext = Extent(X= xval, Y= yval)
72+ pyramid_ext = extent(pyramid)
73+
74+ data_limits_ext = Extent(X = extrema(first, datapos), Y = extrema(x -> x[2 ], datapos))
75+ pixel_widths = Point2f(abs.(pixelpos[2 ] .- pixelpos[1 ]))
76+
77+ datalimit = switchkeys(data_limits_ext, pyramid_ext)
78+
79+ if intersects(pyramid_data_ext, data_limits_ext)
80+ data[] = miss2nan.(
81+ selectlevel(pyramid, datalimit, target_imsize = pixel_widths)
82+ )
5783 end
58- notify(data)
84+ nothing
5985 end
60- # @show typeof(data)
61- hmap = heatmap!(ax, data; interpolate = interp, kwargs ... )
86+
87+ heatmap!(plot, plot . attributes, data )
6288end
89+
90+ function Makie. data_limits(p:: Heatmap{<: Tuple{<: Pyramid}} )
91+ extX, extY = extent(p. arg1[], (XDim, YDim))
92+ rect = Rect3f((extX[1 ], extY[1 ],0 ), (extX[2 ] - extX[1 ], extY[2 ] - extY[1 ], 0 ))
93+ return rect
94+ end
95+ Makie. boundingbox(p:: Heatmap{<: Tuple{<: Pyramid}} , space:: Symbol = :data) = Makie. apply_transform_and_model(p, Makie. data_limits(p))
96+
97+
98+ # """
99+ # plot(pyramids)
100+ # Plot a Pyramid.
101+ # This will plot the coarsest resolution level at the beginning and will plot higher resolutions after zooming into the plot.
102+ # This is expected to be used with interactive Makie backends.
103+ # """
104+ # function plot(pyramid::Pyramid;colorbar=true, size=(1155, 1043), kwargs...)
105+ # #This should be converted into a proper recipe for Makie but this would depend on a pyramid type.
106+ # fig = Figure(;size)
107+ # lon, lat = DD.dims(DD.parent(pyramid))
108+ # ax = Axis(fig[1,1], limits=(extrema(lon), extrema(lat)), aspect=DataAspect())
109+ # hmap = plot!(ax, pyramid;kwargs...)
110+ # if colorbar
111+ # Colorbar(fig[1,2], hmap, height = Relative(3.5 / 4))
112+ # end
113+ # ax.autolimitaspect = 1
114+ # FigureAxisPlot(fig, ax, hmap)
115+ # end
116+
117+ # function plot!(ax, pyramid::Pyramid;interp=false, kwargs...)#; rastercrs=crs(parent(pyramid)),plotcrs=EPSG(3857), kwargs...)
118+ # tip = levels(pyramid)[end-2][:,:]
119+ # #@show typeof(tip)
120+ # subtypes = Union{typeof.(pyramid.levels)..., typeof(parent(pyramid))}
121+ # data = Observable{DD.AbstractDimMatrix}(tip)
122+ # xyext = values.(extent(pyramid, (XDim, YDim)))
123+ # xval = first(xyext)
124+ # yval = last(xyext)
125+ # rasdataext = Extent(X=xval, Y=yval)
126+ # rasext = extent(pyramid)
127+ # on(ax.scene.viewport) do viewport
128+ # limext = extent(ax.finallimits[])
129+
130+ # datalimit = switchkeys(limext, rasext)
131+ # data[] = miss2nan.(selectlevel(pyramid, datalimit, target_imsize=viewport.widths))
132+ # end
133+ # on(ax.finallimits) do limits
134+ # limext = extent(limits)
135+ # # Compute limit in raster projection
136+ # #trans = Proj.Transformation(plotcrs, rastercrs, always_xy=true)
137+ # #datalimit = trans_bounds(trans, limext)
138+ # datalimit = switchkeys(limext, rasext)
139+ # if intersects(rasdataext, limext)
140+ # rasdata = selectlevel(pyramid, datalimit, target_imsize=ax.scene.viewport[].widths)
141+ # # Project selected data to plotcrs
142+ # #data.val = Rasters.resample(rasdata, crs=plotcrs, method=:bilinear )
143+ # data.val = miss2nan.(rasdata)
144+ # end
145+ # notify(data)
146+ # end
147+ # #@show typeof(data)
148+ # hmap = heatmap!(ax, data; interpolate=interp, kwargs...)
149+ # end
63150end
0 commit comments