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
911miss2nan (x) = ismissing (x) ? NaN : x
10- """
11- plot(pyramids)
12- Plot a Pyramid.
13- This will plot the coarsest resolution level at the beginning and will plot higher resolutions after zooming into the plot.
14- This is expected to be used with interactive Makie backends.
15- """
16- function plot (pyramid:: Pyramid ;colorbar= true , size= (1155 , 1043 ), kwargs... )
17- # This should be converted into a proper recipe for Makie but this would depend on a pyramid type.
18- fig = Figure (;size)
19- lon, lat = DD. dims (DD. parent (pyramid))
20- ax = Axis (fig[1 ,1 ], limits= (extrema (lon), extrema (lat)), aspect= DataAspect ())
21- hmap = plot! (ax, pyramid;kwargs... )
22- if colorbar
23- Colorbar (fig[1 ,2 ], hmap, height = Relative (3.5 / 4 ))
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,)
2425 end
25- ax. autolimitaspect = 1
26- FigureAxisPlot (fig, ax, hmap)
2726end
2827
29- function plot! (ax, pyramid:: Pyramid ;interp= false , kwargs... )# ; rastercrs=crs(parent(pyramid)),plotcrs=EPSG(3857), kwargs...)
30- tip = levels (pyramid)[end - 2 ][:,:]
31- # @show typeof(tip)
32- subtypes = Union{typeof .(pyramid. levels)... , typeof (parent (pyramid))}
33- data = Observable {DD.AbstractDimMatrix} (tip)
34- xval = only (values (extent (pyramid, XDim)))
35- yval = only (values (extent (pyramid, YDim)))
36- rasdataext = Extent (X= xval, Y= yval)
37- rasext = extent (pyramid)
38- on (ax. scene. viewport) do viewport
39- limext = extent (ax. finallimits[])
40-
41- datalimit = switchkeys (limext, rasext)
42- data. val = miss2nan .(selectlevel (pyramid, datalimit, target_imsize= viewport. widths))
43- notify (data)
44- end
45- on (ax. finallimits) do limits
46- limext = extent (limits)
47- # Compute limit in raster projection
48- # trans = Proj.Transformation(plotcrs, rastercrs, always_xy=true)
49- # datalimit = trans_bounds(trans, limext)
50- datalimit = switchkeys (limext, rasext)
51- if intersects (rasdataext, limext)
52- rasdata = selectlevel (pyramid, datalimit, target_imsize= ax. scene. viewport[]. widths)
53- # Project selected data to plotcrs
54- # data.val = Rasters.resample(rasdata, crs=plotcrs, method=:bilinear )
55- data. val = miss2nan .(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+ )
5683 end
57- notify (data)
84+ nothing
5885 end
59- # @show typeof(data)
60- hmap = heatmap! (ax, data; interpolate = interp, kwargs ... )
86+
87+ heatmap! (plot, plot . attributes, data )
6188end
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
62150end
0 commit comments