holoviz / hvplot

A high-level plotting API for pandas, dask, xarray, and networkx built on HoloViews
https://hvplot.holoviz.org
BSD 3-Clause "New" or "Revised" License
1.13k stars 108 forks source link

Data not mapping properly to Polygons when `rasterize=False` & Matplotlib Extension #1099

Open philipc2 opened 1 year ago

philipc2 commented 1 year ago

Overview

I am attempting to visualize data that resides on unstructured grids. To achieve this, I am developing a to_gdf method that converts our unstructured grid representation into geometries (Polygons) that can be visualized.

I have been able to compute the geometries of the grid and collect them in a spatialpandas.GeoDataFrame, however when mapping data variables to the polygons, visualizing them with rasterize=False produces seemingly random results when compared to using rasterize=True when using the matplotlib backend.

Using the bokeh backend correctly maps the data with or without rasterization.

Here is the code for how we construct our geometries

    def to_gdf(self, override=False, cache=True):

        # return cached gdf
        if self._gdf is not None and not override:
            return self._gdf

        # obtain polygon shells for shapely polygon construction
        polygon_shells = self.polygon_shells

        # list of shapely Polygons representing each Face in our grid
        polygons = [Polygon(shell) for shell in polygon_shells]

        # List of Polygons (non-split) and MultiPolygons (split across antimeridian)
        corrected_polygons = [antimeridian.fix_polygon(P) for P in polygons]

        # prepare geometry for GeoDataFrame
        geometry = MultiPolygonArray(corrected_polygons)

        # construct our GeoDataFrame with corrected polygons
        gdf = GeoDataFrame({"geometry": geometry})

        # cache instance of gdf
        if cache:
            self._gdf = gdf

        return gdf

Software Version Info

uxarray on branch "philipc2/wrapped-polygons" for development spatialpandas 0.4.8 shapely 2.0.1 geoviews 1.9.6 hvplot 0.8.4 holoviews 1.16.2 xarray 2023.5.0

MCVE


# on branch "philipc2/wrapped-polygons" for development 
import uxarray as ux
import xarray as xr
import hvplot.pandas
import geoviews.feature as gf

hvplot.extension('matplotlib')

# load grid and data files
mpas_root_filepath = "../../test/meshfiles/mpas/other/"
mpas_dataset_filepath = mpas_root_filepath + "ocean.QU.480km.scrip.151209.nc"
data_path = mpas_root_filepath + "ocean.QU.480km.151209.nc"
uxgrid = ux.open_grid(mpas_dataset_filepath, use_dual=False)

# faces mapped to polygons with corrected antimeridian crossing, stored as a sp.GeoDataFrame
gdf = uxgrid.to_gdf()

# obtain a 1D slide of temperature that maps to each face
d_var = xrds['temperature'].values[0, :, 0]
gdf['d_var'] = d_var

# plot
gdf.hvplot.polygons(rasterize=False, geo=True, hover_cols='all', c="d_var", height=1000, width=2000, cmap='inferno') * gf.coastline

Plots Showcasing Described Issue

Sea Surface Temperature

Raster Plot (MPL)

gdf.hvplot.polygons(rasterize=True, geo=True, hover_cols='all', c="d_var", height=1000, width=2000, cmap='inferno') * gf.coastline

image

Non-Raster Plot (MPL)

gdf.hvplot.polygons(rasterize=False, geo=True, hover_cols='all', c="d_var", height=1000, width=2000, cmap='inferno') * gf.coastline

image

Raster Plot (Bokeh)

image

Non-Raster Plot (Bokeh)

image

Ocean Depth

Raster Plot

image

Non-Raster Plot

image

philippjfr commented 1 year ago

Thanks for the detailed issue, there's likely something off with colormapping in the HoloViews PolygonPlot implementation.