Home > Software design >  Add padding in a Geopandas plot
Add padding in a Geopandas plot

Time:01-27

I would like to make a Geopandas plot with a few dots. Often, my points are pretty much aligned, horizontally or vertically, which makes my plot to be very wide or narrow. Example:

df = gpd.GeoDataFrame([{"name": "a", "geom": shapely.geometry.Point(473600, 6660740)},
                   {"name": "b", "geom": shapely.geometry.Point(473580, 6660750)},
                   {"name": "c", "geom": shapely.geometry.Point(473470, 6660750)}
                  ]).set_geometry("geom")
ax = df.plot()

This gives:

enter image description here

Adding a "figsize" does not change anything. Is there any way to force geopandas/matplotlib to show a more balanced plot, adding padding, without having to play manually with xlim/ylim ?

Thanks!

CodePudding user response:

Assuming there is no solution to tell GeoPandas to automatically (and smartly) adapt its margins to avoid unbalanced plots, here is my solution. Improvement welcome!

def set_optimal_limits(ax, df):
"""
Adapt xlim/ylim to a GeoDataFrame point plot to avoid plot to be too wide when 
points are horizontally aligned, and to narrow when points are vertically aligned

Usage : 

ax = df.plot()
set_optimal_limits(ax, df)

Parameters
----------
ax: AxesSubplot
   plot to resize
df: GeoDataFrame
   data to be plotted

Returns
-------
    None
"""

plot_ratio = 1.5 # optimal ratio between "one horizontal degree" and "one vertical degree". It depends of the CRS. 
                 # For "polar" CRS, it may also depend of the place on the globe

margins = 1.1 # Avoid having dots on edges of the plot


# Compute dimension of the data
xmin, ymin, xmax, ymax = df.total_bounds
height = (ymax - ymin) 
width = (xmax - xmin)

opt_height = max(height, width / plot_ratio)
opt_width  = max(width , height*plot_ratio)

# If plot is too narrow, increase xmin. If plot is too wide, increase ylim

if opt_height > height :
    ymid = (ymax ymin)/2
    mid_height = opt_height * margins / 2
    ax.set_ylim(ymid - mid_height, ymid   mid_height)
if opt_width > width:
    xmid = (xmax xmin)/2
    mid_width = opt_width* margins/2
    ax.set_xlim(xmid - mid_width, xmid   mid_width)

With the example above, it gives the following figure : enter image description here

CodePudding user response:

You can add margins on either of axes with matplotlib.

df = geopandas.GeoDataFrame([{"name": "a", "geom": shapely.geometry.Point(473600, 6660740)},
                   {"name": "b", "geom": shapely.geometry.Point(473580, 6660750)},
                   {"name": "c", "geom": shapely.geometry.Point(473470, 6660750)}
                  ]).set_geometry("geom")
ax = df.plot()
plt.margins(y=1)

enter image description here

The second solution is to specify xlim and ylim based on total bounds.

df = geopandas.GeoDataFrame([{"name": "a", "geom": shapely.geometry.Point(473600, 6660740)},
                   {"name": "b", "geom": shapely.geometry.Point(473580, 6660750)},
                   {"name": "c", "geom": shapely.geometry.Point(473470, 6660750)}
                  ]).set_geometry("geom")

margin_y = .5  # margin on y axis as a ratio of y extent
margin_x = .5  # margin on x axis as a ratio of y extent

xmin, ymin, xmax, ymax = df.total_bounds
y_margin = (ymax - ymin) * margin_y
x_margin = (xmax - xmin) * margin_x

ax = df.plot()
ax.set_xlim(xmin - x_margin, xmax   x_margin)
ax.set_ylim(ymin - y_margin, ymax   y_margin)

You can play with various options of that to the padding you like.

  •  Tags:  
  • Related