Select to view content in your preferred language

xy(z) table to point feature, varying coordinate-systems

1063
8
Jump to solution
08-03-2022 12:26 AM
Maps-Berlin
New Contributor III

Hello everybody,

I was wondering if it is possible to create a point feature from an xy table which contains coordinates in different coordinate systems if the table has a column containing the epsg-code for each row. Same goes for z-value and a column containing information about the vertical reference. 

I know i can split the table by coordinate system, create point features for each and then merge but I was wondering if there is a possibility to to this in a single operation, basically choose the coordinate system by attribute.

Thanks is advance

 

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

Not out of the box, but it's possible with a little Python.

This is only for x and y, because I have no clue about vertical reference.

 

def xy_to_point_enhanced(in_table, x_field, y_field, epsg_field, out_fc, out_epsg):
    """Converts tabular coordinates into a point feature class, analogous to XY Table To Point. coordinates can be from different coordinate systems.

    in_table: str, path to the input table or table name in map
    x_field, y_field, epsg_field: str, names of the coordinate fields and the field that contains the epsg code
    out_fc: str, path of the output point feature class
    out_epsg: epsg code of the output feature class
    
    """
    from pathlib import Path
    import arcpy
    out_ws = str(Path(out_fc).parent)
    out_name = str(Path(out_fc).name)
    out_sr = arcpy.SpatialReference(out_epsg)
    in_fields = arcpy.ListFields(in_table)
    
    # create output feature class
    arcpy.management.CreateFeatureclass(out_ws, out_name, "POINT", spatial_reference=out_sr)
    for f in in_fields:
        if f.type not in ["OID", "GlobalID"]:
            arcpy.management.AddField(out_fc, f.name, f.type)
    # fill output feature class
    field_names = [f.name for f in in_fields]
    with arcpy.da.InsertCursor(out_fc, field_names + ["SHAPE@"]) as icur:
        with arcpy.da.SearchCursor(in_table, field_names) as scur:
            for row in scur:
                row_dict = dict(zip(field_names, row))
                # create a point geometry from the input coordinates
                in_sr = arcpy.SpatialReference(row_dict[epsg_field])
                in_point = arcpy.PointGeometry(arcpy.Point(row_dict[x_field], row_dict[y_field]), in_sr)
                # project the point geometry to the output coordinate system
                out_point = in_point.projectAs(out_sr)
                # insert the row values and the new geometry into the feature class
                icur.insertRow(list(row) + [out_point])


# and then you can call it like this
xy_to_point_enhanced("TestTable", "X", "Y", "EPSG", "memory/TestPoints", 25832)

 

 


Have a great day!
Johannes

View solution in original post

8 Replies
DanPatterson
MVP Esteemed Contributor

Splitting by coordinate system and projecting to a common one and merging the resultant bits is the way to go.  You would probably want to script it if you have numerous ones or you have to do it on a regular basis


... sort of retired...
0 Kudos
JohannesLindner
MVP Frequent Contributor

Not out of the box, but it's possible with a little Python.

This is only for x and y, because I have no clue about vertical reference.

 

def xy_to_point_enhanced(in_table, x_field, y_field, epsg_field, out_fc, out_epsg):
    """Converts tabular coordinates into a point feature class, analogous to XY Table To Point. coordinates can be from different coordinate systems.

    in_table: str, path to the input table or table name in map
    x_field, y_field, epsg_field: str, names of the coordinate fields and the field that contains the epsg code
    out_fc: str, path of the output point feature class
    out_epsg: epsg code of the output feature class
    
    """
    from pathlib import Path
    import arcpy
    out_ws = str(Path(out_fc).parent)
    out_name = str(Path(out_fc).name)
    out_sr = arcpy.SpatialReference(out_epsg)
    in_fields = arcpy.ListFields(in_table)
    
    # create output feature class
    arcpy.management.CreateFeatureclass(out_ws, out_name, "POINT", spatial_reference=out_sr)
    for f in in_fields:
        if f.type not in ["OID", "GlobalID"]:
            arcpy.management.AddField(out_fc, f.name, f.type)
    # fill output feature class
    field_names = [f.name for f in in_fields]
    with arcpy.da.InsertCursor(out_fc, field_names + ["SHAPE@"]) as icur:
        with arcpy.da.SearchCursor(in_table, field_names) as scur:
            for row in scur:
                row_dict = dict(zip(field_names, row))
                # create a point geometry from the input coordinates
                in_sr = arcpy.SpatialReference(row_dict[epsg_field])
                in_point = arcpy.PointGeometry(arcpy.Point(row_dict[x_field], row_dict[y_field]), in_sr)
                # project the point geometry to the output coordinate system
                out_point = in_point.projectAs(out_sr)
                # insert the row values and the new geometry into the feature class
                icur.insertRow(list(row) + [out_point])


# and then you can call it like this
xy_to_point_enhanced("TestTable", "X", "Y", "EPSG", "memory/TestPoints", 25832)

 

 


Have a great day!
Johannes
Maps-Berlin
New Contributor III

Thanks a lot, I'm going to try it like this

 

0 Kudos
Maps-Berlin
New Contributor III

sadly I wasn't able to get it to work, seems to be a conflict with the ObjectID-field. After trying for the last two hours I keep getting either error.

ERROR 000012: OBJECTID ist bereits vorhanden.

or 

WARNING 000012: ObjectID ist bereits vorhanden.
ERROR 000800: Der Wert ist kein Mitglied von Text | Float (einfache Genauigkeit) | Double (doppelte Genauigkeit) | Short (kleine Ganzzahl) | Long (große Ganzzahl) | Datum | Blob (Binärdaten) | Raster-Bilddaten | GUID (Globally Unique Identifier).
Fehler beim Ausführen von (AddField).

I'm not much of a programmer, so I dont really know how do go from here apart from somehow trying to get rid of the ObjectID in my input table .. as the field is generated automatically this idea proved fruitless to far..

 

0 Kudos
JohannesLindner
MVP Frequent Contributor

I tested it on a table without ObjectID field...

I edited the code in my original comment, so that it skips copying ObjectID and GlobalID fields (line 20).


Have a great day!
Johannes
Maps-Berlin
New Contributor III

To follow up on my error message from a few weeks ago. I finally got some time to dive a bit into my problem and found that it didn't work with the text field-type for the epsg-field as the expression

row_dict[epsg_field] returned the referency system like this: "31467" instead of 31467 which is what arcpy.SpatialReference() seemst to expect.

Changing the epgs-field type to long fixed the problem. Works like a charm now, thanks again. 

0 Kudos
Maps-Berlin
New Contributor III

Hey, thanks for taking the time. Unfortunately I am still getting a runtime error:

Traceback (most recent call last):
File "<string>", line 1, in <module>
File "<string>", line 21, in xy_to_point_enhanced
File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\arcobjects\mixins.py", line 942, in __init__
self._arc_object.createFromFile(item, vcs)
RuntimeError: SpatialReference: Error in CreateFromFile

I feel like this might be specific to my computer/installation, might try it out on another machine.

Still thank you and have a great day aswell!

0 Kudos
nsidaniel
New Contributor III

Hi @Maps-Berlin I know it's been awhile, but I had the same error ... and it was because I misspelled the spatial reference.

Based on your code it looks like that's "out_epsg". I'm sure you've worked it out by now, but I hope you're having a good day.

 

0 Kudos