python - 如何在不更改 yticks 的情况下使用 Matplotlib 实现非重叠文本
问题描述
我正在使用下面的代码实现下图。
数据:
df={'continent': {0: 'BJP', 1: 'INC', 2: 'BSP'},
'1952': {0: 10650, 1: 30047, 2: 36828},
'1957': {0: 42369, 1: 4482, 2: 4069}}
代码:
import matplotlib.lines as mlines
# Import Data
#df = pd.read_csv("C:\\Daman\\abccc.csv")
left_label = [str(c) + ', '+ str(round(y)) for c, y in zip(df.continent, df['1952'])]
right_label = [str(c) + ', '+ str(round(y)) for c, y in zip(df.continent, df['1957'])]
klass = ['red' if (y1-y2) < 0 else 'green' for y1, y2 in zip(df['1952'], df['1957'])]
# draw line
# https://stackoverflow.com/questions/36470343/how-to-draw-a-line-with-matplotlib/36479941
def newline(p1, p2, color='black'):
ax = plt.gca()
l = mlines.Line2D([p1[0],p2[0]], [p1[1],p2[1]], color='red' if p1[1]-p2[1] > 0 else 'green', marker='o', markersize=6)
ax.add_line(l)
return l
fig, ax = plt.subplots(1,1,figsize=(7,7), dpi= 80)
# Vertical Lines
ax.vlines(x=1, ymin=3500, ymax=45000, color='black', alpha=0.7, linewidth=1, linestyles='dotted')
ax.vlines(x=3, ymin=3500, ymax=45000, color='black', alpha=0.7, linewidth=1, linestyles='dotted')
# Points
ax.scatter(y=df['1952'], x=np.repeat(1, df.shape[0]), s=10, color='black', alpha=0.7)
ax.scatter(y=df['1957'], x=np.repeat(3, df.shape[0]), s=10, color='black', alpha=0.7)
# Line Segmentsand Annotation
for p1, p2, c in zip(df['1952'], df['1957'], df['continent']):
newline([1,p1], [3,p2])
ax.text(1-0.05, p1, c + ', ' + str(round(p1)), horizontalalignment='right', verticalalignment='center', fontdict={'size':14})
ax.text(3+0.05, p2, c + ', ' + str(round(p2)), horizontalalignment='left', verticalalignment='center', fontdict={'size':14})
# 'Before' and 'After' Annotations
ax.text(1-0.05, 23000, 'BEFORE', horizontalalignment='right', verticalalignment='center', fontdict={'size':18, 'weight':700})
ax.text(3+0.05, 23000, 'AFTER', horizontalalignment='left', verticalalignment='center', fontdict={'size':18, 'weight':700})
# Decoration
ax.set_title("Vote Swing", fontdict={'size':22})
ax.set(xlim=(0,4), ylim=(0,14000), ylabel='Votes')
ax.set_xticks([1,3])
ax.set_xticklabels(["2012", "2017"])
plt.yticks(np.arange(3500, 45000, 2000), fontsize=12)
# Lighten borders
plt.gca().spines["top"].set_alpha(.0)
plt.gca().spines["bottom"].set_alpha(.0)
plt.gca().spines["right"].set_alpha(.0)
plt.gca().spines["left"].set_alpha(.0)
plt.show()
我的问题是:
- 如何删除这种重叠的文本,因为它们不可读。
- 如何在线条上方放置百分比(摆动)。
df2={'continent': {0: 'BJP', 1: 'INC', 2: 'BSP'},
'Swing': {0: 31.9, 1: 9.9, 2: -42.5}}
解决方案
您可以使用adjust_text。尝试使用参数来获得适合您的外观:
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from adjustText import adjust_text
df=pd.DataFrame({'continent': {0: 'BJP', 1: 'INC', 2: 'BSP'},
'1952': {0: 10650, 1: 30047, 2: 36828},
'1957': {0: 42369, 1: 4482, 2: 4069}})
# Import Data
#df = pd.read_csv("C:\\Daman\\abccc.csv")
left_label = [str(c) + ', '+ str(round(y)) for c, y in zip(df.continent, df['1952'])]
right_label = [str(c) + ', '+ str(round(y)) for c, y in zip(df.continent, df['1957'])]
klass = ['red' if (y1-y2) < 0 else 'green' for y1, y2 in zip(df['1952'], df['1957'])]
# draw line
def newline(p1, p2, color='black'):
ax = plt.gca()
l = mlines.Line2D([p1[0],p2[0]], [p1[1],p2[1]], color='red' if p1[1]-p2[1] > 0 else 'green', marker='o', markersize=6)
ax.add_line(l)
return l
fig, ax = plt.subplots(1,1,figsize=(7,7), dpi= 80)
# Vertical Lines
ax.vlines(x=1, ymin=3500, ymax=45000, color='black', alpha=0.7, linewidth=1, linestyles='dotted')
ax.vlines(x=3, ymin=3500, ymax=45000, color='black', alpha=0.7, linewidth=1, linestyles='dotted')
# Points
ax.scatter(y=df['1952'], x=np.repeat(1, df.shape[0]), s=10, color='black', alpha=0.7)
ax.scatter(y=df['1957'], x=np.repeat(3, df.shape[0]), s=10, color='black', alpha=0.7)
# Line Segmentsand Annotation <------------- This is where you use adjust_text
texts = []
swing_texts = []
for p1, p2, c, s in zip(df['1952'], df['1957'], df['continent'], df['Swing']):
newline([1,p1], [3,p2])
texts.append(plt.text(1-0.05, p1, c + ', ' + str(round(p1))))
texts.append(plt.text(3+0.05, p2, c + ', ' + str(round(p2))))
swing_texts.append(plt.text(2, 0.5*(p1 +p2), s))
adjust_text(texts)
adjust_text(swing_texts, arrowprops=dict(arrowstyle="->", color='r', lw=0.5))
# 'Before' and 'After' Annotations
ax.text(1-0.05, 23000, 'BEFORE', horizontalalignment='right', verticalalignment='center', fontdict={'size':18, 'weight':700})
ax.text(3+0.05, 23000, 'AFTER', horizontalalignment='left', verticalalignment='center', fontdict={'size':18, 'weight':700})
# Decoration
ax.set_title("Vote Swing", fontdict={'size':22})
ax.set(xlim=(0,4), ylim=(0,14000), ylabel='Votes')
ax.set_xticks([1,3])
ax.set_xticklabels(["2012", "2017"])
plt.yticks(np.arange(3500, 45000, 2000), fontsize=12)
# Lighten borders
plt.gca().spines["top"].set_alpha(.0)
plt.gca().spines["bottom"].set_alpha(.0)
plt.gca().spines["right"].set_alpha(.0)
plt.gca().spines["left"].set_alpha(.0)
plt.show()
推荐阅读
- wpf - 如何绑定到 MouseDragElementBehavior 的 X 位置?
- java - 如何将 Dto 修补到实体?
- caching - pyspark cache() 数据框问题
- python - 请求自动化
- shell - 为什么在 cp/mv 失败的情况下文件重定向会成功?
- android - 如何在 Firebase ML KIT 中使用前置摄像头进行条码扫描
- ruby-on-rails - 安装mysql(2.9.1)时出错,Bundler无法继续
- javascript - Javascript fs 模块:输出写入到哪里?
- python - python中的通用行语法解析器
- php - 访问 WooCommerce 中的特定页面时如何将产品添加到购物车?