英文:
Colors problem in plotting figure with matplotlib in python
问题
我试图绘制一个双部分图来突出两个排名之间的差异。我通过用彩色箭头将左侧列表中的城市与右侧列表中的相同城市相连接来实现这一目标。颜色应与排名差异成比例。
这是一个最小工作示例:
import matplotlib.pyplot as plt
# 示例数据
cities = ['City A', 'City B', 'City C', 'City D', 'City E',
'City F', 'City G', 'City H', 'City I', 'City J']
genepy_rank = [3, 1, 4, 2, 5, 8, 7, 10, 9, 6]
fitness_rank = [7, 9, 2, 5, 4, 6, 3, 1, 8, 10]
# 计算排名差异
diff_rank = [genepy - fitness for genepy, fitness in zip(genepy_rank, fitness_rank)]
# 绘制图形
fig, ax = plt.subplots()
for i, city in enumerate(cities):
x = [genepy_rank[i], fitness_rank[i]]
y = [i, i]
color = diff_rank[i]
ax.plot(x, y, color=color, marker='o')
ax.annotate(city, (x[0], y[0]), xytext=(-20, 20),
textcoords='offset points', ha='right', va='bottom',
bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'))
ax.set_xlim(0, 11)
ax.set_ylim(-1, 11)
ax.set_yticks([i for i in range(len(cities))])
ax.set_yticklabels(cities)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.yaxis.tick_right()
ax.yaxis.set_label_position("right")
plt.show()
问题是这会导致错误退出:ValueError:-4不是一个有效的颜色值,我理解这个问题。是否有一种方法可以确定颜色网格并基于diff_rank分配颜色给箭头?
谢谢。
英文:
I am trying to plot a bipartite graph to highlight the differences between two rankings. I am doing so by connecting the city in the left list to the same city on the right list with a colored arrow. The color should be proportional to the difference in rankings.
Here is a MWE:
import matplotlib.pyplot as plt
# Sample data
cities = ['City A', 'City B', 'City C', 'City D', 'City E',
'City F', 'City G', 'City H', 'City I', 'City J']
genepy_rank = [3, 1, 4, 2, 5, 8, 7, 10, 9, 6]
fitness_rank = [7, 9, 2, 5, 4, 6, 3, 1, 8, 10]
# Calculate the difference in ranking
diff_rank = [genepy - fitness for genepy, fitness in zip(genepy_rank, fitness_rank)]
# Plot the graph
fig, ax = plt.subplots()
for i, city in enumerate(cities):
x = [genepy_rank[i], fitness_rank[i]]
y = [i, i]
color = diff_rank[i]
ax.plot(x, y, color=color, marker='o')
ax.annotate(city, (x[0], y[0]), xytext=(-20, 20),
textcoords='offset points', ha='right', va='bottom',
bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
arrowprops=dict(arrowstyle = '->', connectionstyle='arc3,rad=0'))
ax.set_xlim(0, 11)
ax.set_ylim(-1, 11)
ax.set_yticks([i for i in range(len(cities))])
ax.set_yticklabels(cities)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.yaxis.tick_right()
ax.yaxis.set_label_position("right")
plt.show()
The problem is that this exits with an error: ValueError: -4 is not a valid value for color which I understand. Is there a way to determine a color grid and assign a color to the arrows based on diff_rank?
Thank you
答案1
得分: 0
不要指定颜色,为什么不使用颜色映射呢?
如果你想要显示颜色条(就像我所做的),请记住 plt.plot
不提供所需的 ScalarMappable
以实例化颜色条,所以你必须提供一个。
import matplotlib.pyplot as plt
from matplotlib.cm import ScalarMappable
from matplotlib.colors import BoundaryNorm
# 示例数据
cities = ['City A', 'City B', 'City C', 'City D', 'City E',
'City F', 'City G', 'City H', 'City I', 'City J']
genepy_rank = [3, 1, 4, 2, 5, 8, 7, 10, 9, 6]
fitness_rank = [7, 9, 2, 5, 4, 6, 3, 1, 8, 10]
# 计算排名差异
diff_rank = [genepy - fitness for genepy, fitness in zip(genepy_rank, fitness_rank)]
dmin, dmax = min(diff_rank), max(diff_rank)
boundaries = [dmin-0.5]+[d+0.5 for d in range(dmin, dmax+1)]
cm = plt.get_cmap('Spectral')
norm = BoundaryNorm(boundaries, 256)
print(type(norm))
# 绘制图表
fig, ax = plt.subplots(layout='constrained')
for i, city in enumerate(cities):
x = [genepy_rank[i], fitness_rank[i]]
y = [i, i]
color = cm(norm(diff_rank[i]))
ax.plot(x, y, color=color, marker='o')
ax.annotate(city, (x[0], y[0]), xytext=(-20, 20),
textcoords='offset points', ha='right', va='bottom',
bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'))
ax.set_xlim(0, 11)
ax.set_ylim(-1, 11)
cb = plt.colorbar(ScalarMappable(norm, cm), ax=ax)
cb.set_ticks(range(dmin, dmax+1))
cb.set_ticklabels(['%+2d'%t for t in range(dmin, dmax+1)])
cb.setlabel('排名差异(genepy - fitness)')
plt.show()
英文:
Instead of specifying a color, why don't you use a colormap?
If you want to show also a colorbar (as I did) remember that plt.plot
doesn't provide the ScalarMappable
that's necessary to instantiate a Colorbar, so you have to provide one.
import matplotlib.pyplot as plt
from matplotlib.cm import ScalarMappable
from matplotlib.colors import BoundaryNorm
# Sample data
cities = ['City A', 'City B', 'City C', 'City D', 'City E',
'City F', 'City G', 'City H', 'City I', 'City J']
genepy_rank = [3, 1, 4, 2, 5, 8, 7, 10, 9, 6]
fitness_rank = [7, 9, 2, 5, 4, 6, 3, 1, 8, 10]
# Calculate the difference in ranking
diff_rank = [genepy - fitness for genepy, fitness in zip(genepy_rank, fitness_rank)]
dmin, dmax = min(diff_rank), max(diff_rank)
boundaries = [dmin-0.5]+[d+0.5 for d in range(dmin, dmax+1)]
cm = plt.get_cmap('Spectral')
norm = BoundaryNorm(boundaries, 256)
print(type(norm))
# Plot the graph
fig, ax = plt.subplots(layout='constrained')
for i, city in enumerate(cities):
x = [genepy_rank[i], fitness_rank[i]]
y = [i, i]
color = cm(norm(diff_rank[i]))
ax.plot(x, y, color=color, marker='o')
ax.annotate(city, (x[0], y[0]), xytext=(-20, 20),
textcoords='offset points', ha='right', va='bottom',
bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
arrowprops=dict(arrowstyle = '->', connectionstyle='arc3,rad=0'))
ax.set_xlim(0, 11)
ax.set_ylim(-1, 11)
cb = plt.colorbar(ScalarMappable(norm, cm), ax=ax)
cb.set_ticks(range(dmin, dmax+1))
cb.set_ticklabels(['%+2d'%t for t in range(dmin, dmax+1)])
cb.setlabel('Ranking Difference (genepy -fitness)')
plt.show()
I have to say that I do not think this is a good way to show your data (even if it could be the best one, I don't know…).
Maybe this is better,
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论