Deciding on default grid registration and grid type for PyGMT

PyGMT v0.1.1 assumes that input xarray.DataArray grids are gridline registered ( GMT_GRID_NODE_REG ), and of cartesian type ( GMT_GRID_IS_CARTESIAN ). Currrently we are working on allowing for either pixel/gridline registered and cartesian/geographic grids at #476, by changing the virtualfile_from_grid mechanism. But we’ll need to decide on a good default going forward (i.e. for v0.2.0).

GMT defaults to using gridline registration (aka data values represent top left corner of pixel), and PyGMT currently follows this convention. Should we change it to pixel registration which is what xarray follows? Place your vote below!

Registration type:

  • Gridline (left image)
  • Pixel (right image)
0 voters

Grid type:

  • Cartesian, i.e. GMT_GRID_IS_CARTESIAN
  • Geographic, i.e. GMT_GRID_IS_GEO
0 voters

Feel free to leave your comments below, or on Github at Deciding on default grid registration and grid type for PyGMT · Issue #487 · GenericMappingTools/pygmt · GitHub where there will be some more context.

GMT does not have a default for grid or pixel registration. It simply handles both of them. Some modules, like surface do have the gridline default but GMT in itself doesn’t. Can’t PyGMT do the same? If xarrays need to be pixel-registered just make sure they are and no resample is needed. Just do the same as grdedit -T does.

Just to clarify, this is a non-issue for users passing in a NetCDF filename directly into PyGMT, in that case, the gridline/pixel registration type will be handled like normal in GMT.

It is when we’re creating a virtualfile grid from an xarray object via the C API, and passing that onto GMT, that we have to explicitly state whether it is gridline or pixel registered. For some cases, where an xarray is created from a NetCDF file, we can detect whether an xarray is gridline/pixel registered (and we’ve almost got this automated method sorted).

The default then would really only affect users creating their grid from scratch in pure Python, as there won’t be a NetCDF ‘source’ we can run grdinfo on to detect the registration type. In this case, would it be better to assume that the user created a pixel registered or gridline registered grid?

In case you find it useful, that’s how I deal with it in Julia

1 Like

Thanks for linking to that! I was thinking of using a boolean flag as well last night (instead of the current implementation which parses a string like reg="g" or reg="p"). Will take a closer look later, what does HDR stand for?

HDR is an header vector (explained in the function)
HDR 1x9 [xmin xmax ymin ymax zmin zmax reg xinc yinc] header descriptor
We have this guy since the very early grdreader in Matlab tens of years ago.

Hi! I am having a weird new issue that I think is related to this discussion.

I have a text file that I converted to netCDF. It plots fine as the text file, but the netCDF gives me the following error: “grdimage [WARNING]: Guessing of registration in conflict between x and y, using gridline”

These are the commands I performed on my data.
pygmt.xyz2grd(data=‘data.txt’, spacing=.05, region=[-127.5, -65, 20, 50], outgrid=‘data.nc’)

fig = pygmt.Figure()
with pygmt.config(MAP_ANNOT_OFFSET_PRIMARY=‘0.1c’):
fig.basemap(frame=[‘af’], region=[-127.5, -65, 20, 50], projection=‘M6i’)
pygmt.makecpt(cmap=“vik”, reverse=True, series=[7.55,8.5])
fig.grdimage(grid=‘data.nc’, cmap=True,)
fig.show()

Please let me know if you have any ideas about which (likely missing) parameter is causing the registration error. Figure.grdimage does not have a registration option, so I’m not sure where to start. Thanks for your help!

xyz2grd (https://www.pygmt.org/v0.9.0/api/generated/pygmt.xyz2grd.html) has a registration parameter that defaults to g for gridline. Maybe try setting it to p for pixel to see if it helps?

Could you also post the output of gmt grdinfo data.nc or print(pygmt.grdinfo('data.nc')) to see if something is acting up?

@weiji14 Using the pixel registration gives the error “xyz2grd [WARNING]: 1157 values gave bad indices: Pixel vs Gridline registration confusion?” so I reverted to gridline registration.

And this is the output from grdinfo:

/data.nc: Title:
/data.nc: Command: gmt xyz2grd /data.txt -G/data.nc -I0.05 -R-127.5/-65/20/50 -rgridline
/data.nc: Remark:
/data.nc: Gridline node registration used [Cartesian grid]
/data.nc: Grid file format: nf = GMT netCDF format (32-bit float), CF-1.7
/data.nc: x_min: -127.5 x_max: -65 x_inc: 0.05 name: x n_columns: 1251
/data.nc: y_min: 20 y_max: 50 y_inc: 0.05 name: y n_rows: 601
/data.nc: v_min: 7.35750007629 v_max: 8.64949989319 name: z
/data.nc: scale_factor: 1 add_offset: 0
/data.nc: format: netCDF-4 chunk_size: 139,151 shuffle: on deflation_level: 3
/data.nc: Default CPT:

For reference, a similar dataset has the following output and does not produce an error:

/v.nc: Title:
/v.nc: Command: gmt xyz2grd /v.txt -G/v.nc -I0.05 -R-127.5/-65/20/50
/v.nc: Remark:
/v.nc: Gridline node registration used [Cartesian grid]
/v.nc: Grid file format: nf = GMT netCDF format (32-bit float), CF-1.7
/v.nc: x_min: -127.5 x_max: -65 x_inc: 0.05 name: x n_columns: 1251
/v.nc: y_min: 20 y_max: 50 y_inc: 0.05 name: y n_rows: 601
/v.nc: v_min: 7.6 v_max: 8.3 name: z
/v.nc: scale_factor: 1 add_offset: 0
/v.nc: format: netCDF-4 chunk_size: 139,151 shuffle: on deflation_level: 3
/v.nc: Default CPT:

From what I can tell, the only difference is the z range.

What GMT version?

For me this message is clear. The data (the grid) is confused about its identity. xx says is gridline while yy pixel registration (or vice-versa).

@pwessel It’s PyGMT version: v0.9.0
python: 3.11.4
machine: macOS-13.5-arm64-arm-64bit

Dependency information:
numpy: 1.25.2
pandas: 2.0.3
xarray: 2023.7.0
netCDF4: 1.6.4
packaging: 23.1
ghostscript: 9.54.0

GMT library information:
binary version: 6.4.0
grid layout: rows
padding: 2
version: 6.4.0

But I was having this issue before I updated to PyGMT v0.9.0 from v0.7.0

I think we can provide more useful help if you can upload your data.txt files to the forum or Google Drive.

I realized I was using the wrong function :sweat_smile: … Sorry for the trouble.
I haven’t worked with this dataset for awhile and forget this version uses an irregular grid.

Everything works perfectly when I triangulate the data. Thanks for your help!