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

  • In addition to the previous answer, set the legend on free space:

    import geopandas as gpd
    from shapely.geometry import box
    import matplotlib.pyplot as plt
    import matplotlib.patches as mpatches
    
    fig, ax = plt.subplots()
    
    bounding_box = [9.454, 80.4, 12, 80.88]
    
    polygon = box(*bounding_box)
    gdf = gpd.GeoDataFrame(geometry=[polygon])
    gdf.plot(ax=ax, edgecolor='red', facecolor='none', linewidth=2)
    
    # Create legend handle
    legend_handle = mpatches.Patch(facecolor='none', edgecolor='red', linewidth=2, label='user bbox query')
    
    # Add legend positioned outside the plot area
    ax.legend(handles=[legend_handle], bbox_to_anchor=(1.05, 1), loc='upper left')
    
    plt.xlabel('Longitude')
    plt.ylabel('Latitude')
    plt.tight_layout()  # Adjust layout to make room for the legend
    plt.show()
    

    Output: enter image description here