【问题标题】:Matplotlib: bring one set of scatter plot data to frontMatplotlib:将一组散点图数据放在前面
【发布时间】:2019-04-12 07:54:56
【问题描述】:

我有一系列带有红色和蓝色标记的子图,我对红色标记最感兴趣,所以想把它们带到图的前面:

数据结构是这样的:

            SzT     Pcp     Pcp_3day    Pcp_7day    Pcp_10day   Pcp_14day   Pcp_21day   Pcp_28day
date        
2017-12-04  0.0     8.382   19.304      21.082      40.132      40.132      42.418      71.374
2017-12-05  0.0     12.192  20.574      33.020      42.164      52.324      52.578      81.534
2017-12-06  0.0     1.016   21.590      33.020      34.290      53.340      53.594      82.550
2017-12-07  0.0     12.700  25.908      45.466      46.990      66.040      66.040      95.250
2017-12-08  0.0     5.080   18.796      50.292      51.816      71.120      71.120      88.900

颜色由每个数据点所属的 'SzT' 的值决定,它可以是 1 或 0(尽管在上面只显示了 '0')。我用下面的代码构造了这个:

colors = {0 : 'b',
          1 : 'r'}


fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(111)
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)

c = [colors[i] for i in RGDFT8mm['SzT']]
m = [marker[i] for i in RGDFT8mm['SzT']]
ax1.scatter(RGDFT8mm['Pcp'], RGDFT8mm['Pcp_3day'], c=c)
ax2.scatter(RGDFT8mm['Pcp'], RGDFT8mm['Pcp_7day'], c=c)
ax3.scatter(RGDFT8mm['Pcp'], RGDFT8mm['Pcp_14day'], c=c)
ax4.scatter(RGDFT8mm['Pcp'], RGDFT8mm['Pcp_28day'], c=c)

ax.set_title('Daily Rainfall vs antecedent rainfall from Rain Gauges 2001-2017')
ax.set_xlabel('Daily Rainfall (mm)')
ax.set_ylabel('Antecedent rainfall (mm)')
ax.set_yticklabels([])
ax.set_xticklabels([])

ax1.set_title('3 Day')
ax2.set_title('7 Day')
ax3.set_title('14 Day')
ax4.set_title('28 Day')

我在其他地方找不到任何有用的信息。有什么想法吗?

谢谢!

更新:对于糟糕的原始结构表示歉意,我已在 FYI 上方添加了数据结构。

【问题讨论】:

标签: python matplotlib scatter


【解决方案1】:

起初,如果不知道数据框中数据的结构,很难说出具体的内容,因此请考虑发布例如RGDFT8mm.head()

也就是说,我至少从您的代码中看到,您在一个数据框中混合了红色和蓝色数据,而在散点图之前没有对其进行分组(=分离)。因此,一个 scatter 命令包含两种颜色,因此不可能在前景中获得一种颜色。
如果您重新构建每个散点图命令仅绘制一种颜色,则每个散点图都将绘制在前一个散点图的顶部,除此之外,您可以使用zorder kwarg 随意定义每个数据集的层。

对于分组,您可以使用 RGDFT8mm.groupby('SzT') 之类的东西 - 但是,为了从这里提供有用的提示,我宁愿等待确切地知道您的数据帧结构。
但我的第一个猜测是:

for grpname, grpdata in RGDFT8mm.groupby('SzT'):
    ax1.scatter(grpdata['Pcp'], grpdata['Pcp_3day'])
    ax2.scatter(grpdata['Pcp'], grpdata['Pcp_7day'])
    ax3.scatter(grpdata['Pcp'], grpdata['Pcp_14day'])
    ax4.scatter(grpdata['Pcp'], grpdata['Pcp_28day'])

编辑 举例说明

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

data = lambda n: np.random.lognormal(sigma=.5, size=n)
np.random.seed(42)
df = pd.DataFrame({'Pcp': data(500), 'Pcp_3day': data(500), 'SzT': (np.random.random(500)>.9).astype(int)})
print(df.head())

fig, axs = plt.subplots(2, 2, sharex=True, sharey=True)

szt_hi = df.SzT > 0

axs[0, 0].set_title('plot red before blue')
axs[0, 0].scatter(df.loc[szt_hi, 'Pcp'], df.loc[szt_hi, 'Pcp_3day'], c='r', label='SzT=1')
axs[0, 0].scatter(df.loc[~szt_hi, 'Pcp'], df.loc[~szt_hi, 'Pcp_3day'], c='b', label='SzT=0')
axs[0, 0].legend()

axs[0, 1].set_title('plot blue before red')
axs[0, 1].scatter(df.loc[~szt_hi, 'Pcp'], df.loc[~szt_hi, 'Pcp_3day'], c='b', label='SzT=0')
axs[0, 1].scatter(df.loc[szt_hi, 'Pcp'], df.loc[szt_hi, 'Pcp_3day'], c='r', label='SzT=1')
axs[0, 1].legend()

colors = {0 : 'b', 1 : 'r'}
layer = {0: 1, 1: 0}
axs[1, 0].set_title('plot by looping over groups\n(leading to blue first here)')
for i, (n, g) in enumerate(df.groupby('SzT')):
    axs[1, 0].scatter(g.Pcp, g.Pcp_3day, c=colors[i], label='SzT={}'.format(n))
axs[1, 0].legend()

axs[1, 1].set_title('plot by looping over groups \n(leading to blue first here)\nwith manipulating zorder')
for i, (n, g) in enumerate(df.groupby('SzT')):
    axs[1, 1].scatter(g.Pcp, g.Pcp_3day, c=colors[i], zorder=layer[i], label='SzT={}'.format(n))
axs[1, 1].legend()

plt.show()    


...打印legend 的次数更少,如

for a in axs.flatten():
    a.legend()

在绘制所有子图之后。

但是,在您的情况下,与我的示例相比,您的图例都是相同的,因此整个人物的一个图例会更好。为此,只需使用

fig.legend()

可使用与轴图例相同的参数进行修改。

【讨论】:

  • 您好,非常感谢您的回复!我现在已经更新了这个问题(对不起,我在漫长的一天结束时问了这个问题,所以没有像我应该的那样描述性)。你能扩展你到目前为止所说的话吗?例如,您能否建议我将如何设置哪一组点(红色或蓝色)将出现在前面?
  • 到目前为止,正如我所说,这将导致最后一个绘图位于顶部。想想不透明的油漆,在这里也一样。但是如果你想改变这个,在分散命令中添加一个zorder kwarg。据我所知,值越高,顶部越多。
  • 谢谢,如果我很无聊,很抱歉,但我不明白我应该在哪里放置 zorder 命令以指定哪个应该放在最前面。从下面的示例中,我了解到每一行都在 plot 命令中接收一个命令,但是如果我对您上面的建议做了同样的事情,那么我肯定会将 zorder 应用于两个类,因为它正在循环...plt.plot(x, np.sin(x), label='zorder=10', zorder=10) # on top; plt.plot(x, np.sin(1.1*x), label='zorder=1', zorder=1) # bottom; plt.plot(x, np.sin(1.2*x), label='zorder=3', zorder=3)
  • 正确,所以如果你想要一个 zorder 在几个循环迭代中改变,你只需要给它一个取决于例如的值。在循环计数器上而不是常量上。
  • 剧本中经常出现“传奇”是有原因的……传奇,非常感谢
【解决方案2】:

只需设置散点的 alpha。类似于以下代码。当然,您可以使用 alpha 值。

colors = {0 : (0, 0, 1, 0.3),
          1 : (1, 0, 0, 1.0)}


fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(111)
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)

c = [colors[i] for i in RGDFT8mm['SzT']]
m = [marker[i] for i in RGDFT8mm['SzT']]

ax1.scatter(RGDFT8mm['Pcp'], RGDFT8mm['Pcp_3day'], c=c)
ax2.scatter(RGDFT8mm['Pcp'], RGDFT8mm['Pcp_7day'], c=c)
ax3.scatter(RGDFT8mm['Pcp'], RGDFT8mm['Pcp_14day'], c=c)
ax4.scatter(RGDFT8mm['Pcp'], RGDFT8mm['Pcp_28day'], c=c)

ax.set_title('Daily Rainfall vs antecedent rainfall from Rain Gauges 2001-2017')
ax.set_xlabel('Daily Rainfall (mm)')
ax.set_ylabel('Antecedent rainfall (mm)')
ax.set_yticklabels([])
ax.set_xticklabels([])

ax1.set_title('3 Day')
ax2.set_title('7 Day')
ax3.set_title('14 Day')
ax4.set_title('28 Day')

也只是一个建议:在绘制多个图时使用 plt.subplots() 和 zip。我觉得这很整洁而且很有帮助。检查this

【讨论】:

  • 您好,非常感谢您的评论。不幸的是,这似乎对我不起作用。我收到一个错误提示“TypeError:alpha 必须是浮点数或无”,即使我将两个指定的 alpha 值都更改为浮点数
  • @SHV_la 当您在 scatter 方法中调用它时,您是否更改了 alpha。检查我对我的帖子所做的编辑。据我了解,它应该可以工作。
  • 哈哈,所以,我已经完成了你编辑的内​​容,现在它给了我这个'TypeError:float()参数必须是一个字符串或一个数字,而不是'列表''我真的不明白为什么这么说...
  • @SHV_la 你能试试我最近的编辑吗?发现 matplotlib scatter 不接受 alpha 列表,但似乎我们可以设置 RGBA 值,所以我将这些值作为元组给出。还要检查这个答案stackoverflow.com/questions/24767355/…。似乎这次它会起作用。 :\
  • 这是一件非常有用的事情,所以谢谢你,但它并没有达到我想要的效果,因为红色标记仍在蓝色后面......
猜你喜欢
  • 2014-06-16
  • 1970-01-01
  • 1970-01-01
  • 2020-07-22
  • 1970-01-01
  • 2014-12-31
  • 1970-01-01
  • 2019-01-02
相关资源
最近更新 更多