Python 在熊猫图中标记插值的NaN点

Python 在熊猫图中标记插值的NaN点,python,pandas,matplotlib,plot,data-visualization,Python,Pandas,Matplotlib,Plot,Data Visualization,当我在Pandas中使用插值(或fillna,或任何其他生成虚假数据的方法)时,我希望在我的绘图中显示这一点。理想情况下,我希望在绘图中为这些点使用不同的标记。对于常规点,我想使用填充圆('o'),对于伪数据,我想使用十字('x') 当然,我想用一个很好的蟒蛇紧身裤来做这件事 另一个复杂的问题是,我想使用plot函数中的subplot选项一次打印所有列。我希望用Matplotlib voodoo操纵子情节是没有必要的,尽管在这一点上这是我能想到的唯一选择 我使用的数据如下所示(放入文件“mete

当我在Pandas中使用插值(或
fillna
,或任何其他生成虚假数据的方法)时,我希望在我的绘图中显示这一点。理想情况下,我希望在绘图中为这些点使用不同的标记。对于常规点,我想使用填充圆(
'o'
),对于伪数据,我想使用十字(
'x'

当然,我想用一个很好的蟒蛇紧身裤来做这件事

另一个复杂的问题是,我想使用plot函数中的
subplot
选项一次打印所有列。我希望用Matplotlib voodoo操纵子情节是没有必要的,尽管在这一点上这是我能想到的唯一选择

我使用的数据如下所示(放入文件“meterstanden.ssv”):

下面是我用来处理它的脚本:

import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_table("meterstanden.ssv", delim_whitespace=True,
                   parse_dates=[[0, 1]], index_col=0, na_values=['-'])

df.interpolate(method='time').plot(subplots=True, layout=(2, 2),
                                   figsize=(14, 10), marker='o')
plt.show()

我希望表中的
-
条目用交叉标记进行绘制。

我想不出pythonic一行,但也许这样就可以了。(有了散点图,你会有更多的选择,比如使用
s
kwarg,尽管我不确定它最终是否比这个解决方案更好。)

我认为,无论采用何种确切方法,都有必要设置两个数据框,这两个数据框在包含插补值方面有所不同。我会这样做的

mask=df.isnull()
df=df.interpolate(method='time')
imputed=df[mask]
然后,这只是一个叠加两条直线图的问题。一个是正常的,但第二个是没有线,只包括插补值。您不关心插补值中的连接线,但您确实希望看到点,因此给它们一个区分标记。我按照您的要求使用了“o”而不是“x”,因为“o”显示得更清晰一些,但您当然可以更改它

for c in df.columns:
    plt.plot(df[c])
    plt.plot(imputed[c],linestyle='',marker='o')
    plt.show()

你也可以考虑使用线条颜色来传达关于图的哪些部分是基于估算值的信息。有几种方法可以做到这一点,这里有一种

not_imp=df[~mask]

for c in df.columns:
    plt.plot(df[c],color='r')
    plt.plot(not_imp[c],color='b',marker='o')
    plt.plot(imputed[c],color='r',marker='d',linestyle='')
    plt.show()
所以这里发生的事情是蓝色(圆圈)标记表示真实(非插补)值,蓝色线连接真实和真实。红色(菱形)标记表示插补值,红线将插补值连接到其他插补值或实际值


有意思。据我所知,利用
pandas.DataFrame.plot
函数中的
layout=
subplot=
选项来做你想做的事情,并没有一个好方法。在这方面不要说太多

我的尝试 首先我做了一些测试数据

df1 = pandas.DataFrame({'D':np.random.random(150) , 
                        'A':np.random.random(150),
                        'B':np.random.random(150), 
                        'C':np.random.random(150)})
df1[ df1 > 0.8] = np.nan
df1[ df1 < 0.1] = '-'
对于
'-'
标记,我将它们设置为某个值(您可能希望将它们设置为相应列的平均值或其他值),然后将所有其他值设置为
np.nan

#Similarly,  fill the '-' with another number
df3 = df1.copy()
df3[ df3 != '-'] = np.nan
df3[ df3 == '-'] = 0.5

# finally convert non-numerics to np.nan
df1[ df1=='-'] = np.nan
现在,我尝试绘制每个数据帧

# make plot options for each dataframe
opts =  ({ 'marker':'o' ,'color':'b', 'title':'data' },
        {'marker':'d', 'color':'g','title':'NaN' }, 
        {'marker':'x', 'color':'r','title':'"-" values'} )
dfs  = (df1,df2,df3 )
for opt,df in zip( opts, dfs ):
    df.plot( subplots=True, layout=(2,2), **opt)
plt.show()
这就产生了以下三个数字 ,这不是你想要的

直接使用pylab的替代方法 利用上面的原始数据帧,您可以直接(非常轻微地)利用pylab来完成您可能喜欢的事情:

cols     = ['D','A','B','C'] # the cols you want to plot
fig,axs = plt.subplots(nrows=2,ncols=2) # ncols*nrows should =len(cols)
axs     = [ ax for sublist in axs for ax in sublist]  # flatten the axs array

for ax,col in zip( axs, cols):
    df1[col].plot( ax=ax,marker='o',label='data')
    df2[col].plot( ax=ax,marker='d', label='NaN')
    df3[col].plot( ax=ax,marker='x',label='-')
    ax.set_title(col)
plt.show()

这就产生了以下问题

目前似乎没有办法令人满意地回答我的问题。主要基于JohnE的回答,这是我最终做的(这是太多的低级MatMattLIB IHHO,这就是为什么我不认为这个或其他答案到目前为止我的问题的答案):


这是一篇老文章,但有以下作品:

missing_df = df_ip.mask(df.notnull())

我一直无法对相同的子图/布局进行回复-出于某种原因,它总是生成一个新的图形..看来这确实是做不同标记的最佳方式,谢谢。不过,我仍然需要为子绘图执行Matplotlib魔术。@egpbos是的,很抱歉,我看不到如何将两者结合起来,但希望这是一个好的开始。如果我以后有什么发现,我会更新答案。
# make plot options for each dataframe
opts =  ({ 'marker':'o' ,'color':'b', 'title':'data' },
        {'marker':'d', 'color':'g','title':'NaN' }, 
        {'marker':'x', 'color':'r','title':'"-" values'} )
dfs  = (df1,df2,df3 )
for opt,df in zip( opts, dfs ):
    df.plot( subplots=True, layout=(2,2), **opt)
plt.show()
cols     = ['D','A','B','C'] # the cols you want to plot
fig,axs = plt.subplots(nrows=2,ncols=2) # ncols*nrows should =len(cols)
axs     = [ ax for sublist in axs for ax in sublist]  # flatten the axs array

for ax,col in zip( axs, cols):
    df1[col].plot( ax=ax,marker='o',label='data')
    df2[col].plot( ax=ax,marker='d', label='NaN')
    df3[col].plot( ax=ax,marker='x',label='-')
    ax.set_title(col)
plt.show()
df = pd.read_table("meterstanden.ssv", delim_whitespace=True,
                   parse_dates=[[0, 1]], index_col=0, na_values=['-'])

missing = df.isnull()
df_ip = df.interpolate(method='time')

fig, ax = plt.subplots(2, 2, figsize=(14, 10))
ax = ax.flatten()

for ix, col_name in enumerate(df.columns):
    df_ip[col_name].plot(marker=None, ax=ax[ix])
    df_ip[~missing][col_name].plot(marker='o', color='green', lw=0, ax=ax[ix])
    df_ip[missing][col_name].plot(marker='s', color='red', lw=0, ax=ax[ix])
    ax[ix].set_title(col_name)

plt.tight_layout()
plt.show()
missing_df = df_ip.mask(df.notnull())