Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better error message and exception for out-of-bound data #581

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions geoviews/tests/test_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import cartopy.crs as ccrs
import pytest

from geoviews.util import project_extents



def test_outside_extents():
# extents outside bounds of map 32635, see https://epsg.io/32635
extents = (-2036817.4174174175, 577054.6546546547, -1801982.5825825825, 867745.3453453453)
dest_proj = ccrs.Mercator()
src_proj = ccrs.epsg(32635)

msg = (
"Could not project data from '.+?' projection to '.+?' projection\. "
"Ensure some data is inside the bounds \+\/\- the threshold of the CRS\. "
"For '.+?' this is \(xmin, xmax, ymin, ymax\) = \(.+?\)\."
)
with pytest.raises(ValueError, match=msg):
project_extents(extents, src_proj, dest_proj)
34 changes: 27 additions & 7 deletions geoviews/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,33 @@ def project_extents(extents, src_proj, dest_proj, tol=1e-6):
try:
geom_in_crs = dest_proj.project_geometry(geom_in_src_proj, src_proj)
except ValueError:
src_name =type(src_proj).__name__
dest_name =type(dest_proj).__name__
raise ValueError('Could not project data from %s projection '
'to %s projection. Ensure the coordinate '
'reference system (crs) matches your data '
'and the kdims.' %
(src_name, dest_name))
src_name = type(src_proj).__name__
dest_name = type(dest_proj).__name__
raise ValueError(
f'Could not project data from {src_name} projection '
f'to {dest_name} projection. Ensure the coordinate '
'reference system (CRS) matches your data and the kdims.'
) from None
except IndexError:
# 'unknown' is returned when crs has no name.
src_type_name = type(src_proj).__name__
src_name = getattr(src_proj, "name", src_type_name)
src_name = src_type_name if src_name == "unknown" else src_name

dest_type_name = type(dest_proj).__name__
dest_name = getattr(dest_proj, "name", dest_type_name)
dest_name = dest_type_name if dest_name == "unknown" else dest_name

# Calculate the limit of the src_proj
b = np.array(src_proj.bounds)
t = src_proj.threshold * np.array([1, -1, 1, -1])
limit = np.round(b + t).astype(int)
raise ValueError(
f"Could not project data from '{src_name}' projection "
f"to '{dest_name}' projection. Ensure some data "
f"is inside the bounds +/- the threshold of the CRS. "
f"For '{src_name}' this is (xmin, xmax, ymin, ymax) = {tuple(limit)}."
) from None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this is a viz tool designed to support data exploration, isn't there an argument for simply warning about data that can't be projected into these coordinates, while projecting the remainder of the data? E.g. if people have data extending to the poles and use a projection not defined for the full extent, seems like they should be able to see the rest of the data anyway. Otherwise they'll have to figure out the extent of this projection and figure out how to clip out that data, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually what it already does. The IndexError is happening because there is no data after the conversion. I wanted to show a small example of it happening, but I could not get it to work without changing the code. See comment below.

else:
geom_in_crs = boundary_poly.intersection(domain_in_src_proj)
return geom_in_crs.bounds
Expand Down