[GIS] Adding circle polygon to folium map (using OGR and Python) creates an oval – why

coordinate systemfoliumogrpython

I am new to OGR and Folium but learning fast. In short, I have an issue which I think might be a projection problem.

Basically, I have three circles plotted in folium that work fine. Then I have a fourth circle that I created with OGR, by adding a point then buffering it and plotting the geoJSON polygone onto the folium map. This fourth circle comes out as an oval, see:

enter image description here

The code to make this is as follows:

import folium
import pandas as pd
import json
from numpy import median
from osgeo import ogr

# MY CO-ORDINATES -- FOUR POINTS

datatest = pd.read_csv('data.csv')

p1_lat, p1_lon, p2_lat, p2_lon, p3_lat, p3_lon, p4_lat, p4_lon = datatest['POINT1_LAT'], datatest['POINT1_LON'], datatest['POINT2_LAT'], datatest['POINT2_LON'], datatest['POINT3_LAT'], datatest['POINT3_LON'], datatest['POINT4_LAT'], datatest['POINT4_LON']

# CENTER THE MAP

middle_lat = median([p1_lat, p2_lat, p3_lat, p4_lat])
middle_lon = median([p1_lon, p2_lon, p3_lon, p4_lon])

testmap = folium.Map(location=[middle_lat, middle_lon], zoom_start=13)

# MAKE THREE FOLIUM CIRCULES

folium.Circle(location=[p1_lat, p1_lon], popup='Point 1A', fill_color='#000', radius=2000, weight=2, color="#000").add_to(testmap)
folium.Circle(location=[p2_lat, p2_lon], popup='Point 1B', fill_color='#000', radius=2000, weight=2, color="#000").add_to(testmap)
folium.Circle(location=[p3_lat, p3_lon], popup='Point 1C', fill_color='#008080', radius=1000, weight=2, color="#008080").add_to(testmap)

# MAKE A FOURTH CIRCULE IN OGR

p4_lat = float(p4_lat[0])
p4_lon = float(p4_lon[0])

point_four = ogr.Geometry(ogr.wkbPoint)
point_four.AddPoint(p4_lon, p4_lat)

bufferDistance = 0.01
poly = point_four.Buffer(bufferDistance)

geojson_poly = poly.ExportToJson()

# STYLING THE FOURTH CIRCLE (IGNORE THIS)

import random

def random_html_color():
    r = random.randint(0,256)
    g = random.randint(0,256)
    b = random.randint(0,256)
    return '#%02x%02x%02x' % (r, g, b)

def style_fcn(x):
    return { 'fillColor': random_html_color() }

def highlight_fcn(x):
    return { 'fillColor': '#ff0000' }

# ADD CIRCLE FOUR TO FOLIUM

folium.GeoJson(geojson_poly,name='geojson', style_function=style_fcn).add_to(testmap)

# GENERATE MAP SEEN IN IMAGE

testmap.save('testing_map.html')

So, can anyone tell me why my OGR point is an oval shape? Do I need to set the proper projection somewhere? Presumably to WGS 1984?

EDIT: CSV coordinates are (1-4 in rows, lat and lon):

40.729047,-73.957472
40.70797,-73.93095
40.706799,-73.958416
40.681289,-74.004936

Best Answer

Your buffer:

bufferDistance = 0.01
poly = point_four.Buffer(bufferDistance)

is applied to the Lat/Long point, so the value 0.01 is in units of degrees.

With the method folium.Circle the radius parameter is in units of meters.

Perhaps the simplest fix is to use folium.Circle to plot the forth circle as well.

It is a bit messier, but you could also reproject your points into a flat projection (maybe epsg:6347,) apply the buffer, and then plot.

Edit: Using GeoPandas for the second option (Warning, didn't actually run this code)

import pandas as pd
import geopandas as gpd
from shapely.geometry import Point
df = pd.DataFrame(
    {
        'lat':[p1_lat, p2_lat, p3_lat, p4_lat],
        'lon':[p1_lon, p2_lon, p3_lon, p4_lon],
        'rad':[2000, 2000, 1000, 100]
    }
)
df['geom'] = df.apply(lambda r: Point(r['lon'], r['lat']), axis=1)
gdf = gpd.GeoDataFrame(df, geometry='geom', crs='epsg:4326')
gdf_flat = gdf.to_crs('epsg:6347')
gdf_flat['geom'] = gdf_flat.geometry.buffer(df.rad)
gdf = gdf_flat.to_crs('epsg:4326')
gdf.to_file('data.geojson', driver='GeoJSON')