-
Notifications
You must be signed in to change notification settings - Fork 235
Figure.savefig: Support generating GeoTIFF file (with extension '.tiff') #2698
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
Changes from 24 commits
41767a2
cd9918f
f2348cc
921912d
a83862f
51c8dbe
cf771cc
3303ba4
4fd2f50
9e77ef3
d5e6617
f1f41bf
252514b
c4d480e
2137682
d57d8e0
44bfcfe
e7c2b36
9127756
26837e8
d5ececc
05ef422
71611df
916b4a8
6a1caa3
da9ca29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,6 +92,60 @@ def test_figure_savefig_exists(): | |
| fname.unlink() | ||
|
|
||
|
|
||
| def test_figure_savefig_geotiff(): | ||
| """ | ||
| Make sure .tif generates a normal TIFF file and .tiff generates a GeoTIFF | ||
| file. | ||
| """ | ||
| fig = Figure() | ||
| fig.basemap(region=[0, 10, 0, 10], projection="M10c", frame=True) | ||
|
|
||
| # Save as GeoTIFF | ||
| geofname = Path("test_figure_savefig_geotiff.tiff") | ||
| fig.savefig(geofname) | ||
| assert geofname.exists() | ||
| # The .pgw should not exist | ||
| assert not geofname.with_suffix(".pgw").exists() | ||
|
|
||
| # Save as TIFF | ||
| fname = Path("test_figure_savefig_tiff.tif") | ||
| fig.savefig(fname) | ||
| assert fname.exists() | ||
|
|
||
| # Check if a TIFF is georeferenced or not | ||
| try: | ||
| # pylint: disable=import-outside-toplevel | ||
| import rioxarray | ||
| from rasterio.errors import NotGeoreferencedWarning | ||
|
|
||
| # GeoTIFF | ||
| with rioxarray.open_rasterio(geofname) as xds: | ||
| assert xds.rio.crs is not None | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The output CRS from this 10cm Mercator projection map is: I tried dragging and dropping the However, the blue gridlines (actual longitude/latitude lines from QGIS) don't match up with the GeoTIFF (from psconvert), see the top left corner around 10°N, where the black/white zebra grid markings don't line up with the blue lines. Not sure what the default projection is that is output from psconvert, but I think we should make sure there isn't a bug somewhere. Maybe we should try a few other projections besides @EJFielding, could you share with us the projection (
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh wait nevermind, I think I had a cached There's still a 900m gap between the 9°N blue longitude line and the black/white zebra grid border, but I think that's just because of the default dpi resolution being a bit coarse.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the frame make trouble here? The psconvert -W (https://docs.generic-mapping-tools.org/latest/psconvert.html) says:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assuming that the with pygmt.config(MAP_FRAME_TYPE="inside"):
fig.basemap(region=[0, 10, 0, 10], projection="M10c", frame="afg")And it does look a bit better on the latitude (y-axis) side on the top left corner. The blue line and black lines align well on the latitude grid. But on the longitude (x-axis) side on the bottom right, there still seems to be some offset (~900m) with the blue line not aligning with the black line (and actually, there's some offset from the 0deg latitude origin too): Given that the world file's georeferencing starts from the top-left corner (see https://en.wikipedia.org/wiki/World_file), it kinda makes sense that the top left corner is more aligned, and the offset/distortion is greater at the bottom right corner. Not sure if there's much we can do about this though.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please try to produce a figure using
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still having an offset without the frame: fig = Figure()
with pygmt.config(MAP_FRAME_TYPE="inside"):
fig.coast(shorelines=True, region=[0, 10, 0, 10], projection="M10c")
# Save as GeoTIFF
geofname = Path("test_figure_savefig_geotiff.tiff")
fig.savefig(geofname)Top-left corner Bottom-right corner I measured the size of one of the gray pixels and it was ~900+m, same as the offset. So it might be a case of gridline vs pixel registration (xref #487)? Though I'd think the offset would be half a pixel instead (~450m).
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But this is not a grid, so can't be the gridline/pixel registration issue. Anyway, if something doesn't make sense, then it must be an upstream bug. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found that the GeoTIFF images I was making with GMT classic looked better with the inside frame. I don't remember if having the frame outside made a difference in the geolocation. I am not sure what the conventions are for "world" files, but I know that GDAL has the reference location for the image as the top-left corner of the top-left pixel, unless you change the registration. This is the same as "pixel" registration in GMT. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The other thing to realize for checking image geolocation is that the coastline database used in GMT is something like 40 years old, and not very accurate. I would not rely on the GMT coastline to check the geolocations. In some places the GMT coastline is several hundred meters different from Google Maps or OpenStreetMap.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @weiji14 When you have time, it would be better to submit an upstream issue for more in-depth discussions about the possible misalignments. I believe we can do nothing on the PyGMT side.
seisman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| npt.assert_allclose( | ||
| actual=xds.rio.bounds(), | ||
| desired=( | ||
| -661136.0621116752, | ||
| -54631.82709660966, | ||
| 592385.4459661598, | ||
| 1129371.7360144067, | ||
| ), | ||
| ) | ||
| assert xds.rio.shape == (1257, 1331) | ||
seisman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # TIFF | ||
| with pytest.warns(expected_warning=NotGeoreferencedWarning) as record: | ||
| with rioxarray.open_rasterio(fname) as xds: | ||
| assert xds.rio.crs is None | ||
seisman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| npt.assert_allclose( | ||
| actual=xds.rio.bounds(), desired=(0.0, 0.0, 1331.0, 1257.0) | ||
| ) | ||
| assert xds.rio.shape == (1257, 1331) | ||
seisman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| assert len(record) == 1 | ||
| except ImportError: | ||
| pass | ||
| geofname.unlink() | ||
| fname.unlink() | ||
|
|
||
|
|
||
| def test_figure_savefig_directory_nonexists(): | ||
| """ | ||
| Make sure that Figure.savefig() raises a FileNotFoundError when the parent | ||
|
|
||







Uh oh!
There was an error while loading. Please reload this page.