pythonmatplotlibgeometrylegendgeopandas

How to display a legend when plotting a GeoDataFrame


I have a GeoDataFrame I want to plot. This works fine, however somehow I cannot easily plot its legend. I have tried a number of alternatives and checked solutions from googling and LLM, but I do not understand why this does not work.

Code:

import geopandas as gpd
from shapely.geometry import box, Polygon, LineString

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

bounding_box = [9.454, 80.4, 12, 80.88]

polygon = box(*bounding_box)
gdf = gpd.GeoDataFrame(geometry=[polygon])
plot_obj = gdf.plot(ax=ax, edgecolor='red', facecolor='none', linewidth=2, label="user bbox query")

# plt.legend()  # does not work
# ax.legend(handles=[plot_obj], labels=["test"])  # does not work
ax.legend(handles=[plot_obj])  # does not work
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.show()

Result:

legend is empty

I get a warning:

<python-input-0>:16: UserWarning: Legend does not support handles for Axes instances.
A proxy artist may be used instead.
See: https://matplotlib.org/stable/users/explain/axes/legend_guide.html#controlling-the-legend-entries
  ax.legend(handles=[plot_obj])  # does not wor

But somehow I am not able to take advantage of it to make things work (I tried several ways to plot the legend from "handles", see the different attempts, but none work).

I am certainly missing something - any pointer to how this can be done simply? :)


Solution

  • The issue is that plot_obj = gdf.plot(...) returns an Axes object, not a plot "handle" that can be passed to legend().

    To display a legend, you need to create a proxy artist (e.g., a matplotlib.patches.Patch) that mimics the appearance of your GeoDataFrame's geometry (in your case, a red-bordered polygon with no fill), and then use that in ax.legend().

    Here’s how to fix your code to show the legend correctly:

    import geopandas as gpd
    from shapely.geometry import box
    import matplotlib.pyplot as plt
    from matplotlib.patches import Patch  # For the legend proxy
    
    fig, ax = plt.subplots()
    
    bounding_box = [9.454, 80.4, 12, 80.88]
    polygon = box(*bounding_box)
    
    gdf = gpd.GeoDataFrame(geometry=[polygon])
    
    # Plot the GeoDataFrame
    gdf.plot(ax=ax, edgecolor='red', facecolor='none', linewidth=2)
    
    # Create a legend proxy
    legend_patch = Patch(facecolor='none', edgecolor='red', linewidth=2, label='user bbox query')
    ax.legend(handles=[legend_patch])  # Use the proxy artist for legend
    
    plt.xlabel('Longitude')
    plt.ylabel('Latitude')
    plt.show()
    

    Result:

    enter image description here