Skip to content

Commit

Permalink
Merge pull request #2106 from bornagain1981/main
Browse files Browse the repository at this point in the history
  • Loading branch information
mraspaud authored Dec 15, 2023
2 parents 9f74871 + 9b0bcae commit 7d1810b
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 3 deletions.
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ The following people have made contributions to this project:
- [Lu Liu (yukaribbba)](https://github.com/yukaribbba)
- [Andrea Meraner (ameraner)](https://github.com/ameraner)
- [Aronne Merrelli (aronnem)](https://github.com/aronnem)
- [Luca Merucci (lmeru)](https://github.com/lmeru)
- [Lucas Meyer (LTMeyer)](https://github.com/LTMeyer)
- [Zifeng Mo (Isotr0py)](https://github.com/Isotr0py)
- [Ondrej Nedelcev (nedelceo)](https://github.com/nedelceo)
Expand Down
3 changes: 2 additions & 1 deletion continuous_integration/environment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ dependencies:
- mock
- libtiff
- geoviews
- holoviews
- hvplot
- zarr
- python-eccodes
# 2.19.1 seems to cause library linking issues
- eccodes>=2.20
- geoviews
- pytest
- pytest-cov
- pytest-lazy-fixture
Expand Down
2 changes: 1 addition & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def __getattr__(cls, name):
for mod_name in MOCK_MODULES:
sys.modules[mod_name] = Mock() # type: ignore

autodoc_mock_imports = ["cf", "glymur", "h5netcdf", "imageio", "mipp", "netCDF4",
autodoc_mock_imports = ["cf", "glymur", "h5netcdf", "holoviews", "imageio", "mipp", "netCDF4",
"pygac", "pygrib", "pyhdf", "pyninjotiff",
"pyorbital", "pyspectral", "rasterio", "trollimage",
"zarr"]
Expand Down
76 changes: 75 additions & 1 deletion satpy/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from pyresample.geometry import AreaDefinition, BaseDefinition, SwathDefinition
from xarray import DataArray

from satpy.composites import IncompatibleAreas
from satpy.composites import IncompatibleAreas, enhance2dataset
from satpy.composites.config_loader import load_compositor_configs_for_sensors
from satpy.dataset import DataID, DataQuery, DatasetDict, combine_metadata, dataset_walker, replace_anc
from satpy.dependency_tree import DependencyTree
Expand Down Expand Up @@ -1066,6 +1066,80 @@ def to_geoviews(self, gvtype=None, datasets=None, kdims=None, vdims=None, dynami

return gview

def to_hvplot(self, datasets=None, *args, **kwargs):
"""Convert satpy Scene to Hvplot. The method could not be used with composites of swath data.
Args:
datasets (list): Limit included products to these datasets.
args: Arguments coming from hvplot
kwargs: hvplot options dictionary.
Returns: hvplot object that contains within it the plots of datasets list.
As default it contains all Scene datasets plots and a plot title is shown.
Example usage::
scene_list = ['ash','IR_108']
scn = Scene()
scn.load(scene_list)
scn = scn.resample('eurol')
plot = scn.to_hvplot(datasets=scene_list)
plot.ash+plot.IR_108
"""

def _get_crs(xarray_ds):
return xarray_ds.area.to_cartopy_crs()

def _get_timestamp(xarray_ds):
time = xarray_ds.attrs["start_time"]
return time.strftime("%Y %m %d -- %H:%M UTC")

def _get_units(xarray_ds, variable):
return xarray_ds[variable].attrs["units"]

def _plot_rgb(xarray_ds, variable, **defaults):
img = enhance2dataset(xarray_ds[variable])
return img.hvplot.rgb(bands="bands", title=title,
clabel="", **defaults)

def _plot_quadmesh(xarray_ds, variable, **defaults):
return xarray_ds[variable].hvplot.quadmesh(
clabel=f"[{_get_units(xarray_ds,variable)}]", title=title,
**defaults)

import hvplot.xarray as hvplot_xarray # noqa
from holoviews import Overlay

plot = Overlay()
xarray_ds = self.to_xarray_dataset(datasets)

if hasattr(xarray_ds, "area") and hasattr(xarray_ds.area, "to_cartopy_crs"):
ccrs = _get_crs(xarray_ds)
defaults={"x":"x","y":"y"}
else:
ccrs = None
defaults={"x":"longitude","y":"latitude"}

if datasets is None:
datasets = list(xarray_ds.keys())

defaults.update(data_aspect=1, project=True, geo=True,
crs=ccrs, projection=ccrs, rasterize=True, coastline="110m",
cmap="Plasma", responsive=True, dynamic=False, framewise=True,
colorbar=False, global_extent=False, xlabel="Longitude",
ylabel="Latitude")

defaults.update(kwargs)

for element in datasets:
title = f"{element} @ {_get_timestamp(xarray_ds)}"
if xarray_ds[element].shape[0] == 3:
plot[element] = _plot_rgb(xarray_ds, element, **defaults)
else:
plot[element] = _plot_quadmesh(xarray_ds, element, **defaults)

return plot

def to_xarray_dataset(self, datasets=None):
"""Merge all xr.DataArrays of a scene to a xr.DataSet.
Expand Down
47 changes: 47 additions & 0 deletions satpy/tests/scene_tests/test_conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,53 @@ def test_geoviews_basic_with_swath(self):
# we assume that if we got something back, geoviews can use it
assert gv_obj is not None

def test_hvplot_basic_with_area(self):
"""Test converting a Scene to hvplot with a AreaDefinition."""
from pyresample.geometry import AreaDefinition
scn = Scene()
area = AreaDefinition("test", "test", "test",
{"proj": "geos", "lon_0": -95.5, "h": 35786023.0},
2, 2, [-200, -200, 200, 200])
scn["ds1"] = xr.DataArray(da.zeros((2, 2), chunks=-1), dims=("y", "x"),
attrs={"start_time": datetime(2018, 1, 1),
"area": area, "units": "m"})
hv_obj = scn.to_hvplot()
# we assume that if we got something back, hvplot can use it
assert hv_obj is not None

def test_hvplot_rgb_with_area(self):
"""Test converting a Scene to hvplot with a AreaDefinition."""
from pyresample.geometry import AreaDefinition
scn = Scene()
area = AreaDefinition("test", "test", "test",
{"proj": "geos", "lon_0": -95.5, "h": 35786023.0},
2, 2, [-200, -200, 200, 200])
scn["ds1"] = xr.DataArray(da.zeros((2, 2), chunks=-1), dims=("y", "x"),
attrs={"start_time": datetime(2018, 1, 1),
"area": area, "units": "m"})
scn["ds2"] = xr.DataArray(da.zeros((2, 2), chunks=-1), dims=("y", "x"),
attrs={"start_time": datetime(2018, 1, 1),
"area": area, "units": "m"})
scn["ds3"] = xr.DataArray(da.zeros((2, 2), chunks=-1), dims=("y", "x"),
attrs={"start_time": datetime(2018, 1, 1),
"area": area, "units": "m"})
hv_obj = scn.to_hvplot()
# we assume that if we got something back, hvplot can use it
assert hv_obj is not None

def test_hvplot_basic_with_swath(self):
"""Test converting a Scene to hvplot with a SwathDefinition."""
from pyresample.geometry import SwathDefinition
scn = Scene()
longitude = xr.DataArray(da.zeros((2, 2)))
latitude = xr.DataArray(da.zeros((2, 2)))
area = SwathDefinition(longitude, latitude)
scn["ds1"] = xr.DataArray(da.zeros((2, 2), chunks=-1), dims=("y", "x"),
attrs={"start_time": datetime(2018, 1, 1),
"area": area, "units": "m"})
hv_obj = scn.to_hvplot()
# we assume that if we got something back, hvplot can use it
assert hv_obj is not None

class TestToXarrayConversion:
"""Test Scene.to_xarray() conversion."""
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
"doc": ["sphinx", "sphinx_rtd_theme", "sphinxcontrib-apidoc"],
# Other
"geoviews": ["geoviews"],
"holoviews": ["holoviews"],
"hvplot": ["hvplot", "geoviews", "cartopy", "holoviews"],
"overlays": ["pycoast", "pydecorate"],
"satpos_from_tle": ["skyfield", "astropy"],
"tests": test_requires,
Expand Down

0 comments on commit 7d1810b

Please sign in to comment.