scverse / spatialdata

An open and interoperable data framework for spatial omics data
https://spatialdata.scverse.org/
BSD 3-Clause "New" or "Revised" License
233 stars 43 forks source link

`deepcopy` doesn't deepcopy `.attrs['transform']` in `GeoDataFrame` #286

Open LucaMarconato opened 1 year ago

LucaMarconato commented 1 year ago

This fails:

    import geopandas as gpd
    from shapely.geometry import Point
    import copy

    # Create a GeoDataFrame
    gdf = gpd.GeoDataFrame({
        'geometry': [Point(1, 1), Point(2, 2)],
        'value': [1, 2]
    })

    # Add an attribute to the GeoDataFrame
    gdf.attrs['transform'] = {}

    # Copy the GeoDataFrame
    gdf2 = copy.deepcopy(gdf)

    # Print the IDs
    print(id(gdf.attrs['transform']))  # ID of copied attribute
    print(id(gdf2.attrs['transform']))  # ID of original attribute

    # Assertion
    assert gdf.attrs['transform'] is not gdf2.attrs['transform']
LucaMarconato commented 1 year ago

Opened an issue in the geopandas repo: https://github.com/geopandas/geopandas/issues/2920

LucaMarconato commented 1 year ago

A workaround for deepcopy that overcomes this must be used in

LucaMarconato commented 1 year ago

Added this to spatialdata._utils and using this in the above mentioned locations.

def _deepcopy_geodataframe(gdf: GeoDataFrame) -> GeoDataFrame:
    """
    temporary fix for https://github.com/scverse/spatialdata/issues/286

    Parameters
    ----------
    gdf
        The GeoDataFrame to deepcopy

    Returns
    -------
    A deepcopy of the GeoDataFrame
    """
    #
    new_gdf = deepcopy(gdf)
    new_attrs = deepcopy(gdf.attrs)
    new_gdf.attrs = new_attrs
    return new_gdf