我找到了许多示例,这些示例如何避免在matplotlib上重叠文本,但是没有一个我能弄清楚如何应用于我的案例。
我有一个数据框(mapadf1),其中包含有关巴西直辖市的一些信息,并绘制了圣保罗州(sp)的shapefile。
我创建了一个变量“ l”,其中包含市政名称和我要突出显示的数字。当数字为0时,字符串为空白。
好,所以我设法用以下代码绘制地图:
# set the range for the choropleth values
vmin, vmax = 0, 1
# create figure and axes for Matplotlib
fig, ax = plt.subplots(1, figsize=(30, 10))
# remove the axis que mostra latitude e longitude
ax.axis('off')
# add a title and annotation
ax.set_title('Número leitos inaugurados: 22/03', fontdict={'fontsize': '25', 'fontweight' : '3'})
ax.annotate('Fonte: Governo do Estado de São Paulo', xy=(0.6, .05), xycoords='figure fraction', fontsize=12, color='#555555')
# empty array for the data range
sm.set_array([]) # or alternatively sm._A = []. Not sure why this step is necessary, but many recommends it
# create map
mapa_df1.plot(column='tem_leito',cmap='Paired', linewidth=0.8, ax=ax, edgecolor='0.8')
# Add Labels
mapa_df1['coords'] = mapa_df1['geometry'].apply(lambda x: x.representative_point().coords[:])
mapa_df1['coords'] = [coords[0] for coords in mapa_df1['coords']]
for idx, row in mapa_df1.iterrows():
plt.annotate(s=row['l'], xy=row['coords'])
我的地图:
如何避免文本重叠?!
谢谢!
答案 0 :(得分:0)
实际上,通过plt.annotate
调用创建的对象是matplotlib“注释”(具有很多方法)和边界框,可以通过在以下位置调用.get_window_extent()
来检索边界框返回的对象。
如果没有数以万计的点(无论如何也不适合这种绘图),则可以将这些坐标存储在列表中,并在添加另一个对象时线性检查碰撞。 (对于成千上万个对象,这变得不可行,必须使用比线性策略更好的策略。)
现在还有另一个问题:如果发生碰撞该怎么办? 更简单的解决方法是不显示有问题的标签-但您可以尝试稍微重新放置新注释,以使其不会重叠。这样做可能很复杂-但是,如果我们选择一种简单的天真策略,例如,只需将y轴上的元素移动到不再重叠,就可以得到一个相当稀疏的贴图的好结果,即使有一些错误。
“更智能”的策略可以收集附近所有标签,然后尝试以紧密的方式重新定位,这将需要几个小时甚至几天的工作。
因此,由于您没有可以在本地复制的数据示例,因此我将编写“在y轴上向下移动注解,直到适合为止”策略。”至少您将获得一个起点。
from matplotlib.transforms import Bbox
...
text_rectangles = []
y_step = 0.05
# This will have far better results if the labels are sorted descending in the y axis -
#
mapa_df1["sort_key"] = [coord[1] for coord in mapa_df1["coords"]]
mapa_df1.sort_values("sort_key", ascending=False, inplace=True)
del mapa_df1["sort_key"]
for idx, row in mapa_df1.iterrows():
text = plt.annotate(s=row['l'], xy=row['coords'])
rect = text.get_window_extent()
for other_rect in text_rectangles():
while bbox.intersection(rect, other_rect): # overlapping
x, y = text.get_position()
text.set_position(x, y - y_step)
rect = text.get_window_extent()
text_rectangles.append(rect)
此后,您可以掌握以交互方式创建的Annotation实例之一,并探索其方法和属性-然后甚至有可能与Pointer交互,具体取决于渲染后端,因此,例如,标签可以是以透明级别绘制,然后在鼠标指针悬停时变为完全不透明(例如,请参见Possible to make labels appear when hovering over a point in matplotlib?。