-
Notifications
You must be signed in to change notification settings - Fork 94
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
Pyresample 1.25.1 create_area_def return wrong lons with the .get_lonlats() #457
Comments
It depends what we consider "wrong", but obviously if resampling is no longer working that's a problem. In #447 I actually made an attempt at fixing some assumptions and shortcuts that pyresample has had for a long time. These fixes generally mean more logic is given to the pyproj python library and PROJ C library that pyproj wraps. I think the main thing you are running into is the removal of a shortcut where pyproj transformations of geographic (lon/lat) datasets were not actually given to pyproj and we assumed that what went in (lon/lat degrees) should come out (lon/lat degrees). The problem with this is it is not accurate when the target projection has a prime meridian or longitude shift. So your case is the exact case I was trying to fix. Another way to look at that is that pyresample tries to use "standard" lon/lat degrees where 0 longitude is the prime meridian at Greenwich. Everything else is in the project units of the AreaDefinition being used. I can't promise this is consistent with SwathDefinitions since it is something we're trying to be more strict about lately. Do you have a more complete example of what resampling interfaces you are using? A complete but minimal example that I can use to test and verify things would be great. Especially if it doesn't depend on any data files (random data is fine). |
I should clarify, the Side note: Be careful defining projections as "latlong" with modern PROJ. PROJ is much more strict about axis ordering and since you put "lat" first it may return latitudes first when pyresample (and you) may expect the longitude value. Specifying |
Dear David Hoese Do you have a more complete example of what resampling interfaces you are using? # pyresample==1.25.1
In [1]: from pyresample import create_area_def
...: from pyresample import geometry
...: from pyresample.kd_tree import resample_nearest
...: import numpy as np
In [2]: a = create_area_def(area_id="nowpap",
...: projection={'datum': 'WGS84', 'lat_0': '36',
...: 'lon_0': '137', 'proj': 'latlong'},
...: shape=(1537, 2068),
...: area_extent=(120, 23, 154, 49))
...:
...: x = np.linspace(120.0, 154.0, 3000)
...: y = np.linspace(23, 49, 2000)
...: x, y = np.meshgrid(x, y)
...: src_geo = geometry.SwathDefinition(x, y)
...:
...: s = np.sin(np.linspace(0, 1, x.size)).reshape(x.shape)
...: out = resample_nearest(
...: source_geo_def=src_geo,
...: data=s,
...: target_geo_def=a,
...: fill_value=None,
...: radius_of_influence=30000
...: )
...: out[~out.mask]
Out[2]:
masked_array(data=[],
mask=[],
fill_value=1e+20,
dtype=float64) # pyresample==1.24.0
In [1]: from pyresample import create_area_def
...: from pyresample import geometry
...: from pyresample.kd_tree import resample_nearest
...: import numpy as np
In [2]: a = create_area_def(area_id="nowpap",
...: projection={'datum': 'WGS84', 'lat_0': '36',
...: 'lon_0': '137', 'proj': 'latlong'},
...: shape=(1537, 2068),
...: area_extent=(120, 23, 154, 49))
...:
...: x = np.linspace(120.0, 154.0, 3000)
...: y = np.linspace(23, 49, 2000)
...: x, y = np.meshgrid(x, y)
...: src_geo = geometry.SwathDefinition(x, y)
...:
...: s = np.sin(np.linspace(0, 1, x.size)).reshape(x.shape)
...: out = resample_nearest(
...: source_geo_def=src_geo,
...: data=s,
...: target_geo_def=a,
...: fill_value=None,
...: radius_of_influence=30000
...: )
In [3]: out[~out.mask]
Out[3]:
masked_array(
data=[[[8.4093046e-01, 8.4093052e-01, 8.4093070e-01, ...,
8.4120035e-01, 8.4120053e-01, 8.4120065e-01],
[8.4065974e-01, 8.4065986e-01, 8.4066004e-01, ...,
8.4092993e-01, 8.4093010e-01, 8.4093016e-01],
[8.4038889e-01, 8.4038895e-01, 8.4038913e-01, ...,
8.4065920e-01, 8.4065938e-01, 8.4065950e-01],
...,
[1.5001664e-03, 1.5003331e-03, 1.5006664e-03, ...,
1.9991656e-03, 1.9994990e-03, 1.9996658e-03],
[1.0001666e-03, 1.0003333e-03, 1.0006666e-03, ...,
1.4991664e-03, 1.4994997e-03, 1.4996664e-03],
[5.0016673e-04, 5.0033338e-04, 5.0066673e-04, ...,
9.9916663e-04, 9.9950004e-04, 9.9966663e-04]]],
mask=False,
fill_value=3.4028235e+38,
dtype=float32) Side note: Be careful defining projections as "latlong" with modern PROJ. PROJ is much more strict about axis ordering and since you put "lat" first it may return latitudes first when pyresample (and you) may expect the longitude value. Specifying longlat should work in more cases. Thanks for this side note. Maybe I should have said "inconsistent behaviour between different different pyresample versions"? |
Thanks for the example code, it really helps. There are some small mistakes here that I think I'm starting to understand. If I take your example I get the same results as is. If I change the projection to
then you get the same results as earlier pyresample versions. Note I changed your final statement to We can further analyze this by using pyproj in
So the CRSes are lon/lat (EPSG:4326), your desired CRS, and your desired CRS but with a different lat_0. In the first two calls we see that even though b and c are different in the definition the transform of (0, 0) EPSG:4326 to the desired projections yields the same result. In the next two calls we see that they are producing the same results still...but we changed the latitude input, right? We should have expected the "X" value to stay the same and the latitude/Y go up by 15. Well turns out EPSG:4326 is defined with axes (lat, lon). Apparently I was wrong with
By adding Bottom lineYour extents in your original AreaDefinition are incorrect. They should be in the projection space of your area. In your case that means the origin is at EPSG:4326 (137, 0). So if you want EPSG:4326 longitude 130 that would be -7 in your AreaDefinition. ...and remove What do you think? Did I make any sense here? |
Definitely it makes a lot of sense. However, by saying “Your extents in your original AreaDefinition are incorrect” we are back to your first saying of WHAT YOU CONSIDER INCORRECT. If I use projected coordinates, then pyresample 1.24.0 behaves likes 1.25.1, which means In the language of projections, definitely the latest version is right. But the issue I had was this change in When I first encountered it, I went to pyresample documentation page to try to understand it, but did not find any discussion about this behavior change. From your example, I understand that if I set But I think it would be nice to have somewhere in the docs page a discussion about the new behavior which is different from the past versions. Or if I missed it, I would appreciate it if you could direct me to that information. |
You make very good points. The pyresample is extremely lacking and in my opinion barely useful for modern pyresample. It is one of my goals once I eventually get some time to rewrite the documentation (see #434). The best I can give you is the CHANGELOG that is not linked to in the web site (but should be) that mentions "fixing" lon/lat conversion when prime meridian is not 0: https://github.com/pytroll/pyresample/blob/main/CHANGELOG.md. Agreed that this is not as public as it should be. Dealing with lon/lat transformations that don't have a 0 prime meridian is a pretty new concept to me...that's my best excuse for the lack of information on it. Sorry for all the confusion. |
Thanks a lot David I really appretiate the pyresample package. If there is anything I can contribute back, I would be happy to do it. |
Dear David, I think the longlat "projection" is quite problematic? I run into another issue. It might be covered somewhere. When I call
However, Min example: extent= (-10.578110399046421, 27.046055, 12.60629960095357, 46.45152)
proj= {'datum': 'WGS84', 'lat_0': 36.96185259015367, 'lon_0': 133.78974039904642, 'proj': 'latlong'}
AreaID= 'nowpap_region'
a = create_area_def(projection=proj,
area_extent=extent,
resolution=0.00225,
units='degrees',
area_id=AreaID)
The reason I am writing this is because I work with swath images and most of the time the resolution is reported in metric system. But if I want to create my area in degrees, then I have to estimate the resolution in degrees so that pyresample does not fail. Alternatively, I should suply the shape and all goes well. But the shape also depends on the resolution. I thought there should a better way. Appreciate your advice on this. |
What errors/failures?
Most other projections are in metered space/units. The The only way currently to express parameters in different units is to wrap them in an xarray DataArray object (I regret asking the contributor who added this function to do it this way, but here we are). So you could leave |
I think is no longer relevant to post it since you explain that if you have a latlong projection then it assumes your extents and resolution parameters are in degrees
extent= (-10.578110399046421, 27.046055, 12.60629960095357, 46.45152)
proj= {'datum': 'WGS84', 'lat_0': 36.96185259015367, 'lon_0': 133.78974039904642, 'proj': 'latlong'}
AreaID= 'nowpap_region'
a = create_area_def(projection=proj,
area_extent=extent,
resolution=xr.DataArray(250, attrs={"units": "meters"}),
units='degrees',
area_id=AreaID) ValueError Traceback (most recent call last) Cell In [17], line 4 2 proj= {'datum': 'WGS84', 'lat_0': 36.96185259015367, 'lon_0': 133.78974039904642, 'proj': 'latlong'} 3 AreaID= 'nowpap_region' ----> 4 a = create_area_def(projection=proj, 5 area_extent=extent, 6 resolution=xr.DataArray(250, attrs={"units": "meters"}), 7 units='degrees', 8 area_id=AreaID) |
Ugh sorry, it is possible to do the opposite (a metered projection using degree extents). The only way to map some meters to a value in degrees semi-accurately is to have some projection associated with it. We had decided not to "just pick one" for this operation in Basically if you did "250m" at the equator in a mercator projection you'd get one resolution, if you did it at latitude 55 you'd get another, if you did it at the equator of a polar-stereographic projection you'd get yet another result. Having pyresample be smart about this would be only an estimate and ugly/difficult to implement. Another thought, do you need a lon/lat projection or would an equirectangular projection ( |
Thank you! I think I will stick to using the shape of the target area. |
Code Sample, a minimal, complete, and verifiable piece of code
Problem description
The latest version of pyresample returns lons out of the area extent.
So, the resampling does not end successfully.
projection_x_coords, projection_y_coords return the correct information though.
a.projection_x_coords
Out[8]: array([120.008, 120.025, 120.041, ..., 153.959, 153.975, 153.992])
In [9]: a.projection_y_coords
Out[9]: array([48.992, 48.975, 48.958, ..., 23.042, 23.025, 23.008])
Expected Output
Actual Result, Traceback if applicable
Versions of Python, package at hand and relevant dependencies
pyresample 1.25.1
The text was updated successfully, but these errors were encountered: