7

I have a shapefile, which I converted into GeoPandas DataFrame. I would like to round the coordinates to 5 decimals.

Is there a method/function in GeoPandas that can do this?

My shapefile contains MultiPolygons.

5
  • 2
    Be careful. Rounding of coordinates can damage polygon topology. Rounding degrees to 5 places could change coordinate placement by 1 meter.
    – Vince
    May 2, 2019 at 18:08
  • I saw the precision table and decided 1 meter is good enough for my application. Hence 5 decimals.
    – Vinay
    May 2, 2019 at 18:09
  • Except it doesn't work like that. If the data has centimeter resolution, coordinates may come closer than a meter, and the resulting truncation could cause polygon rings to touch. It takes a more sophisticated approach than just rounding coordinates.
    – Vince
    May 2, 2019 at 18:18
  • But why? What do you gain from this? The object will still occupy the same size in memory, you might snap nodes together and break topology, you'll modify the area and perimeter of your features. Maybe you can do this validly for point features, but I'd never do this for lines or polygons, unless its for display purposes only (ie showing a table of vertex coordinates).
    – Spacedman
    May 2, 2019 at 18:18
  • 1
    We are developing an interactive d3 visualization tool which shows all the US zips on a map with other features. Interaction speed is important in this case and I thought decreasing the precision will help in loading and displaying data fast. Is there any validity in my argument? @Vince - I really don't care if they overlap little bit.
    – Vinay
    May 2, 2019 at 18:24

6 Answers 6

5

You can use the regex module to find the coordinates in a wkt representation of the geometries, round and load back:

import geopandas as gpd
from shapely.wkt import loads
import re

simpledec = re.compile(r"\d*\.\d+")
def mround(match):
    return "{:.5f}".format(float(match.group()))

shapefile = '/home/bera/GIS/data/test/polys.shp'
df = gpd.read_file(shapefile)
df.geometry = df.geometry.apply(lambda x: loads(re.sub(simpledec, mround, x.wkt)))
df.to_file('/home/bera/GIS/data/test/polys_round.shp')

See: Rounding using regular expressions

enter image description here

Or try this: Is it possible to round all coordinates in shapely?

1
  • The second method doesn't work if there are multi-polygons in geometry. Although we can identify them and loop it differently.
    – Vinay
    May 2, 2019 at 19:49
4

I recommend researching topojson and mapshaper as these tools were created to intelligently simplify shapes, preserving topology. Both tools are written in javascript. Mapshaper has a precision option for the output. You can run Mapshaper through a website, mapshaper.org or download the command line tools.

4
  • Can't upvote due to reputation but it works.
    – Vinay
    May 2, 2019 at 19:01
  • Mapshaper is removing other properties in my shapefile and retaining only geometry. Is there a command to include properties? I remember this was not the case when I reduced a shapefile 6 months ago.
    – Vinay
    May 2, 2019 at 19:26
  • This might help with the attributes, gis.stackexchange.com/questions/238204/…
    – klewis
    May 2, 2019 at 19:53
  • I now tried Mapshaper for multiple times and it just keeps running and running over 6 hours + with the "-clean" flag (300mb geoJson). Whatever it's doing it sadly has no progress bar. Jan 13, 2022 at 20:38
1

Here's a solution which rounds the numbers directly without relying on regex. Built off of this one: https://gis.stackexchange.com/a/432720. The shapely.ops.transform function ensures it always works on all geometry types.

from shapely.ops import transform

def round_coordinates(geom, ndigits=2):
    
   def _round_coords(x, y, z=None):
      x = round(x, ndigits)
      y = round(y, ndigits)

      if z is not None:
          z = round(x, ndigits)
          return (x,y,z)
      else:
          return (x,y)
   
   return transform(_round_coords, geom)


import geopandas as gpd
from shapely.geometry import Point

point_geoms = [Point(10.1234567, 20.1234567), Point(30.5123456, 40.59876543)]
gdf = gpd.GeoDataFrame({'id':[1,2]}, geometry=gpd.GeoSeries(point_geoms))

gdf['geometry'] = gdf.geometry.apply(round_coordinates, ndigits=1)
gdf.to_wkt()

0

I encountered a similar issue and searching for a solution! How can I round the coordinates of the "SHAPE" column in an SDF created with pandas.DataFrame.spatial? The "round function would not work against "SHAPE" because it is not a number.

import pandas as pd
df = pd.DataFrame.spatial.from_featureclass("c:\\test.gdb\testFeatureClass")
df.round({"SHAPE": 5}) # TypeError: unsupported operand type(s) for *: 'Polyline' and 'float'

I am trying to use "merge" operation on 2 sdf to identify changes made in geometry. However, I found that "identical" feature from gdb and agol has tinny difference in coordinates (9th or 10th decimal in feet). I am thinking to use round the decimal of coordinates to 7 or 8 place.

0

I am not an expert. But the code below does the job for me. Consider 'gdf' is a geopandas dataframe.

gdf_rounded = gdf.__round__(5)
0
gdf_rounded = gdf.round(5)

Rounds the coordinates to 5 decimal places

2
  • I think the round method is inherited from pandas, since if you run it on the geometry column of a geopandas geodataframe it throws an error.
    – Shawn
    Nov 16, 2022 at 14:05
  • Could be the case, I noticed that __round__ worked in my case, as per a different answer here. My geodataframe in this case has only a geometry column, but it dud reduce the coordinate precision properly
    – wfgeo
    Nov 16, 2022 at 15:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.