问题描述
我正在使用geopandas绘制一个Choropleth地图,我需要绘制一个定制的表格图例. 此问题的答案说明了如何获取轮廓图的表格图例.我在下面的代码中使用它:
I am plotting a choropleth map using geopandas and I need to plot a customized tabular legend. This question's answer shows how to obtain a tabular legend for a contourf plot.And I'am using it in the code bellow :
import pandas as pd
import pysal as ps
import geopandas as gp
import numpy as np
import matplotlib.pyplot as plt
pth = 'outcom.shp'
tracts = gp.GeoDataFrame.from_file(pth)
ax = tracts.plot(column='Density', scheme='QUANTILES')
valeur = np.array([.1,.45,.7])
text=[["Faible","Ng<1,5" ],["Moyenne","1,5<Ng<2,5"],[u"Elevee", "Ng>2,5"]]
colLabels = ["Exposition", u"Densite"]
tab = ax.table(cellText=text, colLabels=colLabels, colWidths = [0.2,0.2], loc='lower right', cellColours=plt.cm.hot_r(np.c_[valeur,valeur]))
plt.show()
这是我得到的结果:
And here's the result i get :
因此,基本上,如您所见,地图和表中的类的颜色之间没有链接.我需要有我在地图上显示的表格中的确切颜色.图例中显示的"NG值"应从我正在绘制的"DENSITY"列中提取.
So basically, as you can see there is no link between the colors of the classes in the map and the table. I need to have the exact colors that i have in the table shown in the map. The 'NG value' shown in the legend should be extracted from the column 'DENSITY' that i am plotting.
但是,由于我没有等高线图可从中提取颜色图,因此我对如何将表格图例和地图颜色链接起来一无所知.
However, since I do not have a contour plot to extract the colormap from, I'm lost on how to link the tabular legend and the map's colors.
推荐答案
注意:此答案已过时.现代geopandas允许通过legend=True
参数使用普通图例.不过,我还是将其保留在此处以供参考,以防万一有人想要一个真正的表格状传说.
Note: This answer is outdated. Modern geopandas allows to use a normal legend via legend=True
argument. I still keep it here for reference though, or in case someone wants a truely tabular legend.
geopandas图不支持添加图例.它还不提供对其绘图对象的访问,仅返回形状为多边形的轴. (它甚至不提供可使用的PolyCollection).因此,为这样的情节创建一个普通的图例是一件繁琐的工作.
The geopandas plot does not support adding a legend. It also does not provide access to its plotting object and only returns an axes with the shapes as polygons. (It does not even provide a PolyCollection to work with). It is therefore a lot of tedious work to create a normal legend for such a plot.
幸运的是,示例笔记本中的某些工作已经完成了. -带有传奇人物
Fortunately some of this work is already beeing done in the example notebook Choropleth classification with PySAL and GeoPandas - With legend
因此,我们需要采用此代码并实现来自此答案的自定义表格说明.
So we need to take this code and implement the custom tabular legend which comes from this answer.
这是完整的代码:
def __pysal_choro(values, scheme, k=5):
""" Wrapper for choropleth schemes from PySAL for use with plot_dataframe
Parameters
----------
values
Series to be plotted
scheme
pysal.esda.mapclassify classificatin scheme ['Equal_interval'|'Quantiles'|'Fisher_Jenks']
k
number of classes (2 <= k <=9)
Returns
-------
values
Series with values replaced with class identifier if PySAL is available, otherwise the original values are used
"""
try:
from pysal.esda.mapclassify import Quantiles, Equal_Interval, Fisher_Jenks
schemes = {}
schemes['equal_interval'] = Equal_Interval
schemes['quantiles'] = Quantiles
schemes['fisher_jenks'] = Fisher_Jenks
s0 = scheme
scheme = scheme.lower()
if scheme not in schemes:
scheme = 'quantiles'
print('Unrecognized scheme: ', s0)
print('Using Quantiles instead')
if k < 2 or k > 9:
print('Invalid k: ', k)
print('2<=k<=9, setting k=5 (default)')
k = 5
binning = schemes[scheme](values, k)
values = binning.yb
except ImportError:
print('PySAL not installed, setting map to default')
return binning
def plot_polygon(ax, poly, facecolor='red', edgecolor='black', alpha=0.5, linewidth=1):
""" Plot a single Polygon geometry """
from descartes.patch import PolygonPatch
a = np.asarray(poly.exterior)
# without Descartes, we could make a Patch of exterior
ax.add_patch(PolygonPatch(poly, facecolor=facecolor, alpha=alpha))
ax.plot(a[:, 0], a[:, 1], color=edgecolor, linewidth=linewidth)
for p in poly.interiors:
x, y = zip(*p.coords)
ax.plot(x, y, color=edgecolor, linewidth=linewidth)
def plot_multipolygon(ax, geom, facecolor='red', edgecolor='black', alpha=0.5, linewidth=1):
""" Can safely call with either Polygon or Multipolygon geometry
"""
if geom.type == 'Polygon':
plot_polygon(ax, geom, facecolor=facecolor, edgecolor=edgecolor, alpha=alpha, linewidth=linewidth)
elif geom.type == 'MultiPolygon':
for poly in geom.geoms:
plot_polygon(ax, poly, facecolor=facecolor, edgecolor=edgecolor, alpha=alpha, linewidth=linewidth)
import numpy as np
from geopandas.plotting import (plot_linestring, plot_point, norm_cmap)
def plot_dataframe(s, column=None, colormap=None, alpha=0.5,
categorical=False, legend=False, axes=None, scheme=None,
k=5, linewidth=1):
""" Plot a GeoDataFrame
Generate a plot of a GeoDataFrame with matplotlib. If a
column is specified, the plot coloring will be based on values
in that column. Otherwise, a categorical plot of the
geometries in the `geometry` column will be generated.
Parameters
----------
GeoDataFrame
The GeoDataFrame to be plotted. Currently Polygon,
MultiPolygon, LineString, MultiLineString and Point
geometries can be plotted.
column : str (default None)
The name of the column to be plotted.
categorical : bool (default False)
If False, colormap will reflect numerical values of the
column being plotted. For non-numerical columns (or if
column=None), this will be set to True.
colormap : str (default 'Set1')
The name of a colormap recognized by matplotlib.
alpha : float (default 0.5)
Alpha value for polygon fill regions. Has no effect for
lines or points.
legend : bool (default False)
Plot a legend (Experimental; currently for categorical
plots only)
axes : matplotlib.pyplot.Artist (default None)
axes on which to draw the plot
scheme : pysal.esda.mapclassify.Map_Classifier
Choropleth classification schemes
k : int (default 5)
Number of classes (ignored if scheme is None)
Returns
-------
matplotlib axes instance
"""
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib.colors import Normalize
from matplotlib import cm
if column is None:
raise NotImplementedError
#return plot_series(s.geometry, colormap=colormap, alpha=alpha, axes=axes)
else:
if s[column].dtype is np.dtype('O'):
categorical = True
if categorical:
if colormap is None:
colormap = 'Set1'
categories = list(set(s[column].values))
categories.sort()
valuemap = dict([(j, v) for (v, j) in enumerate(categories)])
values = [valuemap[j] for j in s[column]]
else:
values = s[column]
if scheme is not None:
binning = __pysal_choro(values, scheme, k=k)
values = binning.yb
# set categorical to True for creating the legend
categorical = True
binedges = [binning.yb.min()] + binning.bins.tolist()
categories = ['{0:.2f} - {1:.2f}'.format(binedges[i], binedges[i+1]) for i in range(len(binedges)-1)]
cmap = norm_cmap(values, colormap, Normalize, cm)
if axes == None:
fig = plt.gcf()
fig.add_subplot(111, aspect='equal')
ax = plt.gca()
else:
ax = axes
for geom, value in zip(s.geometry, values):
if geom.type == 'Polygon' or geom.type == 'MultiPolygon':
plot_multipolygon(ax, geom, facecolor=cmap.to_rgba(value), alpha=alpha, linewidth=linewidth)
elif geom.type == 'LineString' or geom.type == 'MultiLineString':
raise NotImplementedError
#plot_multilinestring(ax, geom, color=cmap.to_rgba(value))
# TODO: color point geometries
elif geom.type == 'Point':
raise NotImplementedError
#plot_point(ax, geom, color=cmap.to_rgba(value))
if legend:
if categorical:
rowtitle = ["Moyenne"] * len(categories)
rowtitle[0] = "Faible"; rowtitle[-1] = u"Elevée"
text=zip(rowtitle, categories)
colors = []
for i in range(len(categories)):
color = list(cmap.to_rgba(i))
color[3] = alpha
colors.append(color)
colLabels = ["Exposition", u"Densité"]
tab=plt.table(cellText=text, colLabels=colLabels,
colWidths = [0.2,0.2], loc='upper left',
cellColours=zip(colors, colors))
else:
# TODO: show a colorbar
raise NotImplementedError
plt.draw()
return ax
if __name__ == "__main__":
import pysal as ps
import geopandas as gp
import matplotlib.pyplot as plt
pth = ps.examples.get_path("columbus.shp")
tracts = gp.GeoDataFrame.from_file(pth)
ax = plot_dataframe(tracts, column='CRIME', scheme='QUANTILES', k=5, colormap='OrRd', legend=True)
plt.show()
产生以下图像:
这篇关于如何为Geopandas绘图制作表格图例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!