使用 matplotlib 更改线条样式比例间距
Changing line style proportional spacing using matplotlib
对于分布不均的数据,几乎所有点的颜色都过于相似。例如。下图表示对应value < 12000
的颜色太浅。
所以,我考虑使用 Pysal 将数据范围分成几个 class 并将颜色图平均分配给这些 classes。
这是我的尝试
Lat
是各点的纬度
Lon
是每个点的经度
Value
是我想用不同标记颜色和大小绘制的每个点对应的属性
我的粗略工作
from pysal.esda.mapclassify import Natural_Breaks as nb
import pysal.esda.mapclassify as mpc
from matplotlib.colors import Normalize
my_bins = [ 20,200,600,1600, 4000, 36000]
breaks =mpc.User_Defined(value,my_bins)
bin_labels = ["%0.0f" % b for b in breaks.bins]
bins = pd.DataFrame({'Class': breaks.yb},)
然后,每个点都有一个基于其值的数据范围的class。
fig = plt.figure()
ax =plt.subplot()
cmap = plt.get_cmap('coolwarm')
norm1 = Normalize(vmin=bins['Class'].min(), vmax=bins['Class'].max())
em_plot = plt.scatter(px[:],py[:], linewidth='0',c =
np.array(bins['Class']),s =(value**0.4)*10, cmap = cmap,\
norm = norm1,alpha = 0.7)
cbaxes = fig.add_axes([0.6625, 0.175, 0.175, 0.04])
cbar = plt.colorbar(em_plot,cax=cbaxes,orientation='horizontal')
value_list = np.array([1,3,5,]) ### THE CLASS
value_label = ['200', '1600','36000'] ### THE VALUE CORRESPONDING TO CLASS
cbar.set_ticks(value_list)
cbar.set_ticklabels(value_label)
cbar.ax.tick_params(labelsize=8)
我的目标
我想用离散的圆圈标记散点,而不是条形图例颜色:每个圆圈代表主要图形上特定值的大小和颜色。
此处显示我在 Internet 上找到的插图:
如上图所示,不同颜色的percentage
图例就是我理想的目标!
如有任何建议,我们将不胜感激!
更新
感谢您的回答。我试过你的方法。但似乎并不完全符合我的目标。
这是我的图,以答案为参考。
从图例和颜色条中,我们可以发现由于映射策略不同,颜色不一样(colorbar -> classify result; legend -> REAL VALUE)
然后,我做一些这样的调整:
cmap = plt.get_cmap('coolwarm')
colors=cmap(np.arange(6)/6.0)
ls = [Line2D(range(1), range(1), linewidth=0,
color=colors[np.where(np.array(my_bins) == v)[0]], \
marker='o', ms=(v**0.2)*2) for v in my_bins]
plt.legend(ls,my_bins)
但是出错了:
ValueError: to_rgba: Invalid rgba arg "[[ 0.2298057 0.29871797 0.75368315 1. ]]"
length of rgba sequence should be either 3 or 4
更新 2
感谢戴维斯的回答,我想生成my_bins
的元素的索引。因此,我尝试使用 np.where(my_bins == element).
来获取索引
但它失败了。然后,我尝试使用:
..., color = colors[i], ms=(v**0.2)*2) for i,v in enumerate(my_bins)
有效!
我认为 "easiest" 会为您的图例创建一个 proxy artist。
以下是可行的,但需要根据您的需要进行调整,我不确定色图的归一化和点的大小是否正确。
from matplotlib.lines import Line2D
cmap = plt.get_cmap('coolwarm')
my_bins = [20,200,600,1600, 4000, 36000]
ls = [Line2D(range(1), range(1), linewidth=0, color=cmap(v), marker='o', ms=(v**0.2)) for v in my_bins]
plt.plot()
plt.legend(ls,my_bins)
更新
关于您更新的问题:您的问题与 color=colors[np.where(np.array(my_bins) == v)[0]]
有关。说实话,我不知道你想在这里做什么。您应该传递一个 (6, 4)
数组,但您传递了一个 (1, 4)
数组。
如果我理解你的代码,你也许应该试试这个:
cmap = plt.get_cmap('coolwarm')
colors=cmap(np.arange(6)/6.0)
ls = [Line2D(range(1), range(1), linewidth=0,
color=colors[i], \
marker='o', ms=(v**0.2)*2) for i,v in enumerate(my_bins)]
plt.legend(ls,my_bins)
对于分布不均的数据,几乎所有点的颜色都过于相似。例如。下图表示对应value < 12000
的颜色太浅。
所以,我考虑使用 Pysal 将数据范围分成几个 class 并将颜色图平均分配给这些 classes。
这是我的尝试
Lat
是各点的纬度Lon
是每个点的经度Value
是我想用不同标记颜色和大小绘制的每个点对应的属性
我的粗略工作
from pysal.esda.mapclassify import Natural_Breaks as nb
import pysal.esda.mapclassify as mpc
from matplotlib.colors import Normalize
my_bins = [ 20,200,600,1600, 4000, 36000]
breaks =mpc.User_Defined(value,my_bins)
bin_labels = ["%0.0f" % b for b in breaks.bins]
bins = pd.DataFrame({'Class': breaks.yb},)
然后,每个点都有一个基于其值的数据范围的class。
fig = plt.figure()
ax =plt.subplot()
cmap = plt.get_cmap('coolwarm')
norm1 = Normalize(vmin=bins['Class'].min(), vmax=bins['Class'].max())
em_plot = plt.scatter(px[:],py[:], linewidth='0',c =
np.array(bins['Class']),s =(value**0.4)*10, cmap = cmap,\
norm = norm1,alpha = 0.7)
cbaxes = fig.add_axes([0.6625, 0.175, 0.175, 0.04])
cbar = plt.colorbar(em_plot,cax=cbaxes,orientation='horizontal')
value_list = np.array([1,3,5,]) ### THE CLASS
value_label = ['200', '1600','36000'] ### THE VALUE CORRESPONDING TO CLASS
cbar.set_ticks(value_list)
cbar.set_ticklabels(value_label)
cbar.ax.tick_params(labelsize=8)
我的目标
我想用离散的圆圈标记散点,而不是条形图例颜色:每个圆圈代表主要图形上特定值的大小和颜色。
此处显示我在 Internet 上找到的插图:
如上图所示,不同颜色的percentage
图例就是我理想的目标!
如有任何建议,我们将不胜感激!
更新
感谢您的回答。我试过你的方法。但似乎并不完全符合我的目标。
这是我的图,以答案为参考。
从图例和颜色条中,我们可以发现由于映射策略不同,颜色不一样(colorbar -> classify result; legend -> REAL VALUE)
然后,我做一些这样的调整:
cmap = plt.get_cmap('coolwarm')
colors=cmap(np.arange(6)/6.0)
ls = [Line2D(range(1), range(1), linewidth=0,
color=colors[np.where(np.array(my_bins) == v)[0]], \
marker='o', ms=(v**0.2)*2) for v in my_bins]
plt.legend(ls,my_bins)
但是出错了:
ValueError: to_rgba: Invalid rgba arg "[[ 0.2298057 0.29871797 0.75368315 1. ]]" length of rgba sequence should be either 3 or 4
更新 2
感谢戴维斯的回答,我想生成my_bins
的元素的索引。因此,我尝试使用 np.where(my_bins == element).
来获取索引
但它失败了。然后,我尝试使用:
..., color = colors[i], ms=(v**0.2)*2) for i,v in enumerate(my_bins)
有效!
我认为 "easiest" 会为您的图例创建一个 proxy artist。
以下是可行的,但需要根据您的需要进行调整,我不确定色图的归一化和点的大小是否正确。
from matplotlib.lines import Line2D
cmap = plt.get_cmap('coolwarm')
my_bins = [20,200,600,1600, 4000, 36000]
ls = [Line2D(range(1), range(1), linewidth=0, color=cmap(v), marker='o', ms=(v**0.2)) for v in my_bins]
plt.plot()
plt.legend(ls,my_bins)
更新
关于您更新的问题:您的问题与 color=colors[np.where(np.array(my_bins) == v)[0]]
有关。说实话,我不知道你想在这里做什么。您应该传递一个 (6, 4)
数组,但您传递了一个 (1, 4)
数组。
如果我理解你的代码,你也许应该试试这个:
cmap = plt.get_cmap('coolwarm')
colors=cmap(np.arange(6)/6.0)
ls = [Line2D(range(1), range(1), linewidth=0,
color=colors[i], \
marker='o', ms=(v**0.2)*2) for i,v in enumerate(my_bins)]
plt.legend(ls,my_bins)