hvplot
hvplot copied to clipboard
`robust` or `clim_percentile` option to get the 2nd / 98th percentile
from pystac_client import Client
from odc.stac import load
import numpy as np
client = Client.open("https://earth-search.aws.element84.com/v1")
collection = "sentinel-2-l2a"
tas_bbox = [146.5, -43.6, 146.7, -43.4]
search = client.search(collections=[collection], bbox=tas_bbox, datetime="2023-12")
ds = load(search.items(), bbox=tas_bbox, groupby="solar_day", chunks={})
da = ds[["red", "green", "blue"]].isel(time=2).load().to_array()
da.plot.imshow(robust=True)
Without robust:
Which is what hvplot yields.
When I try to manually calculate it and pass a custom clim
, there's no effect
https://github.com/pydata/xarray/blob/492aa076bd1812af71d68dc221312fb9a199d2d3/xarray/plot/utils.py#L215-L225
HoloViews has the clim_percentile
plot option but that only applies to plot types that inherit from ColorbarPlot
, while RGBPlot
inherits from LegendPlot
. @ahuang11 I'd say we should first add this plot option to HoloViews? To eventually expose it in hvPlot, where I'd say robust
would be a good choice given that robust=True
would be already familiar to Xarray users.
I was looking at https://github.com/holoviz/holoviews/blob/6aa6c9ddb7c9308531753efae41cbd0873c975a3/holoviews/plotting/bokeh/raster.py#L134 and I'm not sure there's a way to add clim_percentile to RGBPlot without updating Bokeh too.
I tried doing:
if self.clim_percentile:
low, high = 0, 1
style["color_mapper"] = LinearColorMapper(low=low, high=high)
AttributeError [Call holoviews.ipython.show_traceback() for details]
unexpected attribute 'color_mapper' to ImageRGBA, possible attributes are anchor, decorations, dh, dh_units, dilate, dw, dw_units, global_alpha, image, js_event_callbacks, js_property_callbacks, name, origin, subscribed_events, syncable, tags, x or y
I also tried doing:
if self.clim_percentile:
low, high = np.nanpercentile(img, (2, 98))
img[img < low] = low
img[img > high] = high
But it doesn't seem to work
Thoughts about having this in hvPlot? https://github.com/holoviz/holoviews/pull/6137
I don't have a strong preference, but I do want to have a way forward.
I also don't have strong preference :)
I also don't have strong preference :upside_down_face:
I'm -1 on adding this anywhere. Taking percentiles of RGB values just does not make sense to me.
If that's the case, how should users address this?
The initial goal was that I wanted to write a demo of how you can explore satellite imagery with hvplot easily, but then I encountered the issue that robust/clim_percentile was not exposed.
If robust/clim_percentile isn't implemented, its a tad tedious for the user to have to manually implement it for satellite imagery vs typing robust=True
.
Would you prefer it be an operation? E.g. Clip
?
Will have to look at it.
Yeah, looking at this dataset the values are not R G B values they are raw reflectance values for different spectra from a satellite. Visualizing them using an RGB element without first processing these values is simply incorrect. So the only thing I can imagine doing is providing some operation in geoviews.
https://ecampusontario.pressbooks.pub/remotesensing/chapter/chapter-5-visualization-and-manipulation-of-satellite-images/
Based on my reading of that the transformation is quite simple, you divide the red green blue values 2**8 and then cast to uint8.
Alternatively you can also apply histogram equalization.
Hmm, the division thing doesn't work.
from datashader.transfer_functions import eq_hist
hv.RGB(eq_hist(da.data)[0].transpose([1, 2, 0])).opts(width=600)
hv.RGB((da / (2**2)).clip(0, 255).astype(np.uint8).data.transpose([1, 2, 0])).opts(width=600)
Okay, I've come around I'd be okay with a two-pronged approach, we implement the robust semantics in hvPlot and then HoloViews appropriately clips the data.
Philipp found the actual _rescale_imshow_rgb
robust usage in xarray here