PROJ icon indicating copy to clipboard operation
PROJ copied to clipboard

TransformerGroup does not handle cases where both the allow_superseded and always_xy user arguments is used

Open phaarnes opened this issue 1 year ago • 12 comments

Example code

Ex. 1 TransformerGroup fails to list up available transformations when specifying both always_xy and allow_superseded

from pyproj.transformer import TransformerGroup
TransformerGroup("EPSG:4230", "EPSG:4326", allow_superseded=True, always_xy=True).transformers

Outputs:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/pyproj/transformer.py", line 207, in __init__
    super().__init__(
  File "pyproj/_transformer.pyx", line 241, in pyproj._transformer._TransformerGroup.__init__
  File "pyproj/_transformer.pyx", line 602, in pyproj._transformer._Transformer._from_pj
  File "pyproj/_transformer.pyx", line 653, in pyproj._transformer._Transformer._init_from_crs
  File "pyproj/_transformer.pyx", line 359, in pyproj._transformer._Transformer._initialize_from_projobj
pyproj.exceptions.ProjError: Input is not a transformation.

Ex.2 TransformerGroup should return 36 available transformations when allow_superseded not defined

ct_lst = TransformerGroup("EPSG:4230", "EPSG:4326").transformers
print(len(ct_lst))

Outputs:

36

Ex.3 TransformerGroup should return 37 available transformations when allow_superseded is set to True

ct_lst = TransformerGroup("EPSG:4230", "EPSG:4326", allow_superseded=True).transformers
print(len(ct_lst))

Outputs:

37

ct_lst = TransformerGroup("EPSG:4230", "EPSG:4326", allow_superseded=True).transformers print(len(ct_lst))

Problem description

TransformerGroup fails to a create a list of all available transformation objects when the user set both always_xy and allow_superseded equals True.

Environment Information

pyproj version 3.6.1 python 3.11

Installation method

pip wheel

phaarnes avatar Dec 09 '24 13:12 phaarnes

An issue is created in PyProj GitHub repo.

phaarnes avatar Dec 09 '24 13:12 phaarnes

This feels more like a pyproj bug, than a PROJ one. At least the exception comes from https://github.com/pyproj4/pyproj/blob/42aa92f489bd266749a44cb78101eae28e20f5c3/pyproj/_transformer.pyx#L341

rouault avatar Dec 09 '24 14:12 rouault

Hi Even, I see. Feel free to delete this issue if you think its only related to pyproj

phaarnes avatar Dec 09 '24 14:12 phaarnes

I did some debugging and this is what I found:

  • allow_superseded calls proj_operation_factory_context_set_discard_superseded and creates a PJ object for ED50 to WGS 84 (15) with the PJ_TYPE_TRANSFORMATION when calling proj_create_operations.
  • Combining allow_superseded with always_xy causes an issue because the PJ object is PJ_TYPE_TRANSFORMATION. Due to this proj_coordoperation_is_instantiable returns True. However, proj_normalize_for_visualization returns a PJ object of type PJ_TYPE_CONCATENATED_OPERATION for ED50 to WGS 84 (15). This is the source of the error when attempting to create the Transformer.
from pyproj import Transformer

print(Transformer.from_pipeline("ED50 to WGS 84 (15)").description)
"ED50 to WGS 84 (15)"

I modified the pyproj code to run proj_normalize_for_visualization on ED50 to WGS 84 (15) (cannot do this normally with the current release):

from pyproj._transformer import _Transformer

_Transformer.from_pipeline("ED50 to WGS 84 (15)", always_xy=True)
...
pyproj.exceptions.ProjError: Input is not a transformation.

This produces the error above.

@rouault is it expected for proj_normalize_for_visualization convert a PJ_TYPE_TRANSFORMATION into PJ_TYPE_CONCATENATED_OPERATION?

snowman2 avatar Feb 13 '25 04:02 snowman2

Hi @rouault, @snowman2

Has this been investigated further? Any conclusion on where the issue resides?

phaarnes avatar Nov 01 '25 06:11 phaarnes

is it expected for proj_normalize_for_visualization convert a PJ_TYPE_TRANSFORMATION into PJ_TYPE_CONCATENATED_OPERATION?

@snowman2 yes, that's exactly how the implementation works: it takes the original transformation and prepends / appends axis swap operations to it where needed, and returns a concatenated operation

rouault avatar Nov 01 '25 11:11 rouault

yes, that's exactly how the implementation works: it takes the original transformation and prepends / appends axis swap operations to it where needed, and returns a concatenated operation

Thank you for clarifying that. That sounds like it is not the issue.

To further debug the issue, I ran proj_coordoperation_is_instantiable on the PJ * object after calling proj_normalize_for_visualization and it raised the error: missing required input. Is it expected that a PJ * that was instantiable before calling proj_normalize_for_visualization to no longer be instantiable after?

snowman2 avatar Nov 03 '25 19:11 snowman2

and it raised the error: missing required input

proj_coordoperation_is_instantiable() returns that error if the passed PJ* object is NULL.

rouault avatar Nov 03 '25 20:11 rouault

and it raised the error: missing required input

proj_coordoperation_is_instantiable() returns that error if the passed PJ* object is NULL.

Huh, you're correct. proj_normalize_for_visualization is returning NULL now. I wonder what version of PROJ I was using that returned a PJ_TYPE_CONCATENATED_OPERATION 🤔.

snowman2 avatar Nov 03 '25 20:11 snowman2