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:
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? :)
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: