首页 > 解决方案 > 使用 matplotlib scatter 绘制负值

问题描述

我想在地球的全球地图上绘制对应于 6 个不同数据集的散点。问题是其中一些量具有负值并且它们没有出现在地图中。我试图通过获取数据的绝对值并将它们乘以(或乘以)某些因素来克服这个问题,但似乎没有什么能按我想要的方式工作。问题是数据集的范围非常不同。理想情况下,我希望它们都具有相同的规模,这样一切都会更有条理,但我不知道如何做到这一点。

我创建了一些合成数据来说明这个问题

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from mpl_toolkits.basemap import Basemap, addcyclic, shiftgrid
from matplotlib.pyplot import cm

np.random.seed(100)

VarReTx = np.random.uniform(low=-0.087, high=0.0798, size=(52,))
VarReTy = np.random.uniform(low=-0.076, high=0.1919, size=(52,))
VarImTx = np.random.uniform(low=-0.0331, high=0.0527, size=(52,))
VarImTy = np.random.uniform(low=-0.0311, high=0.2007, size=(52,))
eTx = np.random.uniform(low=0.0019, high=0.0612, size=(52,))
eTx = np.random.uniform(low=0.0031, high=0.0258, size=(52,))
obslat = np.array([18.62,   -65.25,   -13.8,     -7.95,   -23.77,    51.84,    40.14,    58.07,
 -12.1875, -35.32,    36.37,   -46.43,    40.957,  -43.474,   38.2 ,    37.09,
  48.17,     0.6946,  13.59,    28.32,    51.,     -25.88,   -34.43,    21.32,
 -12.05,    52.27,    36.23,   -12.69,    31.42,     5.21,   -22.22,    36.1,
  14.38,   -54.5,     43.91,    61.16,    48.27,    52.07,    54.85,    45.403,
  52.971,  -17.57,   -51.7,     18.11,    39.55,    47.595,   22.79,   -37.067,
  -1.2,     32.18,    51.933,   48.52])
obslong = np.array([-287.13,    -64.25,   -171.78,    -14.38,   -226.12,   -339.21,   -105.24,
 -321.77,   -263.1664, -210.64,   -233.146,  -308.13,   -359.667,  -187.607,
  -77.37,   -119.72,   -348.72,   -287.8463, -215.13,    -16.43,     -4.48,
 -332.29,   -340.77,   -158.,      -75.33,   -255.55,   -219.82,   -227.53,
 -229.12,    -52.73,   -245.9,    -256.16,    -16.97,   -201.05,   -215.81,
  -45.442,  -117.12,   -347.32,   -276.77,    -75.552,  -201.752,  -149.58,
  -57.89,    -66.15,     -4.35,    -52.677,  -354.47,    -12.315,   -48.5,
 -110.73,    -10.25,   -123.42,  ])

fig, ([ax1, ax2], [ax3, ax4], [eax1, eax2]) = plt.subplots(3,2, figsize=(24,23))
matplotlib.rc('xtick', labelsize=12) 
matplotlib.rc('ytick', labelsize=12)

plots = [ax1, ax2, ax3, ax4, eax1, eax2]
Vars = [VarReTx, VarReTy, VarImTx, VarImTy, eTx, eTy]
titles = [r'$\Delta$ ReTx', r'$\Delta$ ReTy', r'$\Delta$ ImTx', r'$\Delta$ ImTy', 'Error (X)', 'Error (Y)']
colors = iter(cm.jet(np.reshape(np.linspace(0.0, 1.0, len(plots)), ((len(plots), 1)))))

for j in range(len(plots)):
    c3 = next(colors)
    lat = np.arange(-91, 91, 0.5)
    long = np.arange(-0.1, 360.1, 0.5)
    longrid, latgrid = np.meshgrid(long, lat)   
    plots[j].set_title(titles[j], fontsize=48, y=1.05)
    condmap = Basemap(projection='robin', llcrnrlat=-90, urcrnrlat=90,\
                                    llcrnrlon=-180, urcrnrlon=180, resolution='c', lon_0=0, ax=plots[j])
    maplong, maplat = condmap(longrid, latgrid)
    condmap.drawcoastlines()
    condmap.drawmapboundary(fill_color='white') 
    parallels = np.arange(-90, 90, 15)
    condmap.drawparallels(parallels,labels=[False,True,True,False], fontsize=15)
    x,y = condmap(obslong, obslat)
    w = []

    for m in range(obslong.size):
        w.append(Vars[j][m])
    w = np.array(w)

    condmap.scatter(x, y, s = w*1e+4, c=c3)
    r = np.linspace(np.min(Vars[j]), np.max(Vars[j]), 4)

    for n in r:
        condmap.scatter([], [], c=c3, s=n*1e+4, label=str(np.round(n, 4)))
    plots[j].legend(bbox_to_anchor=(0., -0.2, 1., .102), loc='lower left',
                   ncol=4, mode="expand", borderaxespad=0., fontsize=16, frameon = False)

plt.show()
plt.close('all')

在此处输入图像描述

正如您在地图中看到的那样,负面数据并没有被展示出来。我希望它们都出现在地图中,并且所有散点图在各自的范围内都具有相同的比例。谢谢!

标签: pythonpython-3.xnumpymatplotlib

解决方案


看起来您正在尝试将数据集映射到点大小。显然你不能有负大小的点,所以那是行不通的。

相反,您需要将数据集标准化为严格的正范围,并将这些标准化值用于 size 参数。一个简单的方法是使用matplotlib.colors.Normalize(vmin, vmax),它允许您将区间 [vmin, vmax] 中的任何值映射到区间 [0,1]。

如果您想为所有数据集共享比例,首先找到全局最小值和最大值,并使用它来实例化您的规范化,然后在绘图时规范化每个数据集:

datasets = [VarReTx,VarReTy,VarImTx,VarImTy,eTx,eTx]

min_val = min([d.min() for d in datasets])
max_val = max([d.max() for d in datasets])

norm = matplotlib.colors.Normalize(vmin=min_val, vmax=max_val)
plt.scatter(x,y,s=norm(VarReTx)*100) # choose appropiate scaling factor instead of 100 to get nicely sized dots

推荐阅读