Skip to content

get_collection_map() now defaults to using collection's spatial extent - #2475

Open
ricardogsilva wants to merge 3 commits into
geopython:masterfrom
ricardogsilva:2442-default-crs-for-map-extent-does-not-respect-collection-config
Open

ricardogsilva wants to merge 3 commits into
geopython:masterfrom
ricardogsilva:2442-default-crs-for-map-extent-does-not-respect-collection-config

Conversation

@ricardogsilva

Copy link
Copy Markdown
Member

This PR makes the default bbox used when responding to get collection map requests be the one defined in the collection's own config, as discussed in #2442.

The change is that instead of assigning a static bbox, we read the collection's config and get its own spatial extent to be used as the default.

Important

I also included this minor change that was not strictly in scope for the issue:

the pygeoapi/api/maps.py module had a couple of places where a variable assigned to the provider configuration was erroneously named collection_def when it contained in fact the provider_def instead - this tripped me up when working on the code and got me quite confused until I realized the name of the variable was misleading.

I decided to include the change here for brevity.

Dependency policy (RFC2)

  • I have ensured that this PR meets RFC2 requirements

Contributions and licensing

  • I have already previously agreed to the pygeoapi Contributions and Licensing Guidelines

@github-actions github-actions Bot added the Human generated Label for the detect-ai workflow classifier label Oct 29, 2026
@ricardogsilva
ricardogsilva marked this pull request as ready for review October 29, 2026 16:33
@ricardogsilva
ricardogsilva force-pushed the 2442-default-crs-for-map-extent-does-not-respect-collection-config branch from 3e35129 to 16b4c32 Compare October 29, 2026 17:06

@doublebyte1 doublebyte1 left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you, @ricardogsilva ! I think it is nicer to to provide the map extent as default bbox, but I am a bit puzzled about what to do regarding the default bbox (see my comment inline).

When you have the chance, please also update the docs with this change:

If `crs-bbox` is not provided, it will default to `CRS84`. If the `bbox` is not provided, it will default to `-180, -90, 180, 90`.

Comment thread pygeoapi/api/maps.py
if 'crs' not in request.params:
query_args['crs'] = collection_def.get('storage_crs',
DEFAULT_CRS)
query_args['crs'] = provider_def.get('storage_crs', DEFAULT_CRS)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actually, the standard states that the default CRS should be CRS84; see: https://docs.ogc.org/is/20-058/20-058.html#_8bcbded1-5f70-4020-b90a-596fe8b8326b 13.2.1. Parameter bbox-crs -> c

Not really sure how to deal with this, when we default to a bbox that may have any crs.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This bit of the code was not modified by this PR, except for the rename of the variable from collection_def to provider_def - I'm not changing the behavior of the code here, just giving it a clearer meaning.

Also, looking at section 16.2.1 - Parameter CRS, NOTE 1 of the standard, it reads:

When no crs parameters are specified, please refer to the Maps API core conformance class to know about the default CRS.

and the respective core conformance class section 7.2.2 Response, Requirement 2, point B reads:

The map response SHALL be in the storage CRS specified in the description of the geospatial resource (such as the associated collection or dataset), or https://www.opengis.net/def/crs/OGC/1.3/CRS84 if none is specified, unless overridden by a specific query parameter (see Requirements Class “Coordinate Reference System”).

So this part of the code seems to conform to the standard.

The reference you quoted is dealing with the bbox-crs query parameter, which is used for subsetting, and is only relevant when the request includes a bbox query param. I don't think it is applicable to this passage of the code.

Comment thread pygeoapi/api/maps.py
except AttributeError:
bbox = DEFAULT_BBOX
# in the absence of user-supplied bbox, use collection spatial extent
bbox = collection_def['extents']['spatial']['bbox']

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For the sake of consistency, I think we should either have a fallback for DEFAULT_BBOX here, or remove the fallback to the DEFAULT_CRS on the next line. I am assuming that either we have both, bbox and bbox-crs, or none.

@ricardogsilva ricardogsilva Oct 29, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

two points being made here:

  1. pygeoapi already makes it mandatory for all collections to have a spatial extent and with a mandatory bbox - as per its own configuration format and schema - therefore there is no need to add a fallback DEFAULT_BBOX.

    On the other hand, according to the pygeoapi config schema, the collection config's spatial extent is not required to have the crs property, in which case it is assumed to be CRS84. So this code seems correct to me.

  2. It is possible that a request provides a bbox query param and does not provide bbox-crs, in which case, like you pointed out in your other comment, the standard says, bbox-crs is assumed to be CRS84.

Comment thread pygeoapi/api/maps.py
except AttributeError:
bbox = DEFAULT_BBOX
# in the absence of user-supplied bbox, use collection spatial extent
bbox = collection_def['extents']['spatial']['bbox']

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn' t collection_def here also be replaced by provider_def ?

@ricardogsilva ricardogsilva Oct 29, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

no, because the spatial extent is a property of the collection, not of the provider. That was one of the things which tripped me when looking at this code because the variable was erroneously named.

Comment thread tests/api/test_maps.py

# response extent comes in the collection's storage crs (CRS84)
content_bbox = [float(c) for c in rsp_headers['Content-Bbox'].split(',')]
assert content_bbox == pytest.approx(

@doublebyte1 doublebyte1 Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe we could also add an assertion here for the bbox-crs?

@ricardogsilva ricardogsilva Oct 29, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

bbox-crs is a parameter of the request, not something returned in the response.

Maybe you meant to write that we should check the response contains the Content-Crs header with the correct value?

It is already implied in the assertion, as the coordinates would only make sense if the content CRS would be CRS84 (e.g. the collection's storage CRS in this case), but I will also add the explicit assertion for this response header, as I agree that having it explicitly checked is best.

They now mention that the default bbox is the
collection's configured spatial extent

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Human generated Label for the detect-ai workflow classifier

Projects

None yet

Development

Successfully merging this pull request may close these issues.

default CRS for getting a map does not respect collection's default spatial extent

2 participants