如何根据 df.idxmax 系列制作基于日期的彩条?

How to make a date-based color bar based on df.idxmax series?

Python beginner/first 海报在这里。

我 运行 在向散点图添加颜色条时遇到了麻烦。我有两种类型的图:一种显示按日期颜色编码的所有数据,另一种只显示按日期颜色编码的数据的最大值。在第一种情况下,我可以使用 df.index(即日期时间)来制作颜色条,但在第二种情况下,我使用 df2['col'].idxmax 来生成颜色,因为我df2 是一个 df.groupby 对象,我用它来生成数据中的每日最大值,但它没有可访问的索引。

对于第一种类型的图,我已经成功地使用下面的代码生成了一个基于日期的颜色条,这些代码是从在线示例中拼凑而成的:

fig, ax = plt.subplots(1,1, figsize=(20,20))

smap=plt.scatter(df.col1, df.col2, s=140, 
             c=[date2num(i.date()) for i in df.index],
             marker='.')

cb = fig.colorbar(smap, orientation='vertical',
              format=DateFormatter('%d %b %y'))  

但是对于第二种类型的图,我尝试使用 df2['col'].idxmax 来创建日期系列而不是 df.index,以下方法不起作用:

for n in cols1:
    for m in cols2:
        fig, ax = plt.subplots(1,1, figsize=(15,15))

        maxTimes=df2[n].idxmax()
        PlottableTimes=maxTimes.dropna() #some NaNs in the 
        #.idxmax series were giving date2num trouble

        smap2=plt.scatter(df2[n].max(), df2[m].max(),
             s=160, c=[date2num(i.date()) for i in PlottableTimes], 
             marker='.')

        cb2 = fig.colorbar(smap2, orientation='vertical',
                      format=DateFormatter('%d %b %y'))  

        plt.show()

错误是:'length of rgba sequence should be either 3 or 4'

因为报错颜色参数,我分别检查了各自绘图命令中颜色(即c=)参数的输出,和我看起来很像,所以我想不通为什么一个颜色参数有效而另一个无效:

有效的:

[736809.0, 736809.0, 736809.0, 736809.0, 736809.0, 736809.0, 736809.0, 736809.0, 736809.0, 736809.0, ...]

一个不起作用:

[736845.0, 736846.0, 736847.0, 736848.0, 736849.0, 736850.0, 736851.0, 736852.0, 736853.0, 736854.0, ...]

有什么建议或解释吗?我是 运行 python 3.5.2。预先感谢您帮助我理解这一点。

编辑1:我做了下面的例子供其他人探讨,在这个过程中意识到问题的症结与我的第一个问题不同。下面的代码按照我想要的方式工作:

df=pd.DataFrame(np.random.randint(low=0, high=10, size=(169, 8)), 
            columns=['a', 'b', 'c', 'd', 'e','f','g','h']) #make sample data
date_rng = pd.date_range(start='1/1/2018', end='1/8/2018', freq='H')
df['i']=date_rng
df = df.set_index('i') #get a datetime index
df['ts']=date_rng #get a datetime column to group by

from pandas import Grouper
df2=df.groupby(Grouper(key='ts', freq='D'))

for n in ['a','b','c','d']: #now make some plots
for m in ['e','f','g','h']:
    print(m)
    print(n)

    fig, ax = plt.subplots(1,1, figsize=(5,5))
    maxTimes=df2[n].idxmax()
    PlottableTimes=maxTimes.dropna()

    smap=plt.scatter(df2[n].max(), df2[m].max(), s=160, 
                     c=[date2num(i.date()) for i in PlottableTimes], 
                     marker='.')
    cb = fig.colorbar(smap, orientation='vertical',
                      format=DateFormatter('%d %b %y'))  
    plt.show()

我的真实数据和这个例子的唯一区别是我的真实数据有很多分散在各处的 NaN。所以,我认为出了什么问题是 'c=' 参数不够长,绘图命令无法将其解释为涵盖整个日期范围......?例如,如果我手动输入 c= 命令的输出,我会得到以下同样有效的代码:

for n in ['a','b','c','d']:
    for m in ['e','f','g','h']:
        print(m)
        print(n)

        fig, ax = plt.subplots(1,1, figsize=(5,5))
        maxTimes=df2[n].idxmax()
        PlottableTimes=maxTimes.dropna()

        smap=plt.scatter(df2[n].max(), df2[m].max(), s=160, 
                     c=[736809.0, 736810.0, 736811.0, 736812.0, 736813.0, 736814.0, 736815.0, 736816.0], 
                     marker='.')
        cb = fig.colorbar(smap, orientation='vertical',
                      format=DateFormatter('%d %b %y'))  
        plt.show()

但是,如果我将 c= 数组缩短一些,以模拟当从 idxmax 中删除 NaN 时我的代码中发生的情况,它会给出与我看到的相同的错误:

for n in ['a','b','c','d']:
    for m in ['e','f','g','h']:
        print(m)
        print(n)

        fig, ax = plt.subplots(1,1, figsize=(5,5))
        maxTimes=df2[n].idxmax()
        PlottableTimes=maxTimes.dropna()

        smap=plt.scatter(df2[n].max(), df2[m].max(), s=160, 
                     c=[736809.0, 736810.0, 736811.0, 736812.0, 736813.0, 736814.0], 
                     marker='.')
        cb = fig.colorbar(smap, orientation='vertical',
                      format=DateFormatter('%d %b %y'))  
        plt.show()

所以这意味着真正的问题是:当 none 的列似乎可以用 df2.col 抓取时,如何在从 groupby 对象分组后抓取石斑鱼列?我希望能够从以下内容中获取 'ts' 并将其用作颜色数据,而不是使用 idxmax:

df2['a'].max()

ts
2018-01-01    9
2018-01-02    9
2018-01-03    9
2018-01-04    9
2018-01-05    9
2018-01-06    9
2018-01-07    9
2018-01-08    8
Freq: D, Name: a, dtype: int64

本质上,您的 Grouper 调用类似于在日期时间列上建立索引并调用pandas.DataFrame.resample 指定聚合函数:

df.set_index('ts').resample('D').max()
#             a  b  c  d  e  f  g  h
# ts                                
# 2018-01-01  9  9  8  9  9  9  9  9
# 2018-01-02  9  9  9  9  9  9  9  9
# 2018-01-03  9  9  9  9  9  9  9  9
# 2018-01-04  9  9  9  9  9  9  9  9
# 2018-01-05  9  9  9  9  9  9  9  9
# 2018-01-06  9  9  9  8  9  9  9  9
# 2018-01-07  9  9  9  9  9  9  9  9
# 2018-01-08  2  8  6  3  1  3  2  7

因此,df2['a'].max() 的 return 是一个 Pandas 重采样器对象,与 Pandas 系列非常相似,因此带有索引 属性您可以使用颜色条规格:

df['a'].max().index

# DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
#                '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'],
#               dtype='datetime64[ns]', name='ts', freq='D')

从那里你可以在没有列表理解的情况下传递到 date2num:

date2num(df2['a'].max().index)

# array([736695., 736696., 736697., 736698., 736699., 736700., 736701., 736702.])

总而言之,只需在循环中使用上面的内容即可,无需 maxTimesPlottableTimes:

fig, ax = plt.subplots(1, 1, figsize = (5,5))

smap = plt.scatter(df2[n].max(), df2[m].max(), s = 160, 
                   c = date2num(df2[n].max().index), 
                   marker = '.')
cb = fig.colorbar(smap, orientation = 'vertical',
                  format = DateFormatter('%d %b %y'))