193193 end
194194end
195195
196+ # plot multispectral images as rgb
197+ @userplot RGBPlot
198+
199+ @recipe function f (p:: RGBPlot ; bands= 1 : 3 , low= 0.02 , high= 0.98 )
200+ r = first (p. args)
201+ if ! (typeof (r) <: AbstractRaster )
202+ error (" Plotting RGB images is only implemented for AbstractRasters." )
203+ end
204+ if ! hasdim (r, Band)
205+ error (" Raster must have a band dimension." )
206+ end
207+ if ! (0 <= low <= 1 ) || ! (0 <= high <= 1 )
208+ error (" 'low' and 'high' have to be between 0 and 1 (inclusive)." )
209+ end
210+ img = Float32 .(copy (r[Band ([bands... ])]))
211+ normalize! (img, low, high)
212+ img = permutedims (img, (Band, X, Y))
213+ img = DD. reorder (img, X=> DD. ForwardOrdered, Y=> DD. ForwardOrdered)
214+ plot_image = ImageCore. colorview (RGB, img)
215+
216+ yguide, xguide = DD. label (dims (img, (Y,X)))
217+
218+ y, x = map (Rasters. _prepare, dims (img, (Y,X)))
219+
220+ rdt = DD. refdims_title (img; issingle= true )
221+ :title --> (rdt === " " ? Rasters. _maybename (img) : Rasters. _maybename (img) * " \n " * rdt)
222+ :xguide --> xguide
223+ :xrotation --> 45
224+ :yguide --> yguide
225+ :tick_direction --> :out
226+ :framestyle --> :box
227+
228+ if all (d -> lookup (d) isa Mapped, (x, y))
229+ :xlims --> mappedbounds (x)
230+ :ylims --> mappedbounds (y)
231+ :aspect_ratio --> :equal
232+ else
233+ :xlims --> bounds (img, x)
234+ :ylims --> bounds (img, y)
235+ bnds = bounds (img, (X, Y))
236+ # # TODO : Rethink this....
237+ s1, s2 = map (((l, u),) -> (u - l), bnds) ./ (size (img, X), size (img, Y))
238+ square_pixels = s2 / s1
239+ :aspect_ratio --> square_pixels
240+ end
241+
242+ :seriestype --> :image
243+ :yflip --> false
244+ DD. index (x), DD. index (y), plot_image'
245+ end
246+
247+
196248# Plots.jl heatmaps pixels are centered.
197249# So we should center the index, and use the projected value.
198250_prepare (d:: Dimension ) = d |> _maybe_shift |> _maybe_mapped
@@ -248,3 +300,26 @@ function DD.refdims_title(refdim::Band; issingle=false)
248300 end
249301end
250302
303+ function eachband_view (r:: Raster )
304+ nbands = size (r, Band)
305+ return (view (r, Band (n)) for n in 1 : nbands)
306+ end
307+
308+ function normalize! (raster, low= 0.1 , high= 0.9 )
309+ if ! hasdim (raster, Band)
310+ l = quantile (skipmissing (raster), low)
311+ h = quantile (skipmissing (raster), high)
312+ raster .- = l
313+ raster ./= h - l + eps (float (eltype (raster)))
314+ raster .= clamp .(raster, zero (eltype (raster)), one (eltype (raster)))
315+ else
316+ for band in eachband_view (raster)
317+ l = quantile (skipmissing (band), low)
318+ h = quantile (skipmissing (band), high)
319+ band .- = l
320+ band ./= h - l + eps (float (eltype (raster)))
321+ band .= clamp .(band, zero (eltype (raster)), one (eltype (raster)))
322+ end
323+ end
324+ return raster
325+ end
0 commit comments