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