Pandas 将方波边缘时间戳数据转换为适合打印的数据

Pandas 将方波边缘时间戳数据转换为适合打印的数据,pandas,bokeh,Pandas,Bokeh,这是我正在处理的数据的一个示例: 这是对布尔方波的描述,具有以下特征: “向下”列中的数字是随机整数,但总是被画成零 “向上”列中的数字也是随机整数,但始终绘制为1 大多数时候,“上”和“下”定期交替出现,但偶尔会出现额外的“下”或“上” 转换之间的延迟是不规则的,“时间”列中的值应被视为随机的,但是连续的(排序的) 这是我要找的bokeh代表: 需要同时查看原始点(包括重复点,如t=1.2的点)和线重叠 我的理解是,最简单的方法是在每一对之间插入一个点,y值是上一点的上/下值,x值是下一

这是我正在处理的数据的一个示例:

这是对布尔方波的描述,具有以下特征:

  • “向下”列中的数字是随机整数,但总是被画成零
  • “向上”列中的数字也是随机整数,但始终绘制为1
  • 大多数时候,“上”和“下”定期交替出现,但偶尔会出现额外的“下”或“上”
  • 转换之间的延迟是不规则的,“时间”列中的值应被视为随机的,但是连续的(排序的)
这是我要找的bokeh代表:

需要同时查看原始点(包括重复点,如t=1.2的点)和线重叠

我的理解是,最简单的方法是在每一对之间插入一个点,y值是上一点的上/下值,x值是下一点的值。然后,在bokeh中,将原始数据绘制为散点图,将数据+插值数据绘制为线图。这意味着绘图中有两个不同的图示符,我宁愿避免(为了能够使用新的legend.click_policy=“hide”),但这是可以接受的

插值很容易用常规python代码实现,但为了代码的一致性,我更愿意用pandas实现插值。熊猫是这种插值的合适工具吗

一个最佳的解决方案将导致博克出现一个标志符号。我愿意牺牲业绩来实现这一目标。
一个好的解决方案将我的纯python代码替换为pandas代码。

这应该让您开始学习。请注意,matplotlib是直接使用的,而不是pandas(实际上使用matplotlib)进行绘图

import pandas as pd
import matplotlib.pyplot as plt
将数据映射到熊猫:

data = pd.read_csv('wave_data.csv', sep=';')

def boolean_map(row):
   if pd.notnull(row.Down):
      return 0
   else:
      return 1

data['BooleanMapped'] = data.apply(boolean_map, axis=1)

绘制数据:

x = list(data['Time'])
y = list(data['BooleanMapped'])
plt.ylim(-0.1, 1.5)
plt.xlim(0.9, 2)
plt.step(x, y, where='post')
plt.show()

下面是一个适用于Bokeh的完整脚本

import pandas as pd

from bokeh.io import output_file, show
from bokeh.plotting import figure

output_file("signal.html")

data = pd.DataFrame(dict(
    time=[1, 1.1, 1.2, 1.5, 1.8], 
    down=[19371, None, None, 38175, None],
    up=[None, 36823, 91046, None, 47722]
))

data['mapped'] = data.up.isnull()

# This computes the "step" data
x, y = [], []
prev = -1
for index, row in data.iterrows():
    if row.mapped != prev and prev>=0:
        x.append(row.time)
        y.append(prev)
    x.append(row.time)
    y.append(int(row.mapped))
    prev = int(row.mapped)

p = figure()
p.line(x=x, y=y, legend="signal")
p.circle(x=data.time, y=data.mapped, legend="signal")

p.legend.click_policy="hide"

show(p)
这将产生以下带有交互式图例的Bokeh图:


正如我在评论中宣布的,以下是我目前使用的代码:

    import timeit
    start_time = timeit.default_timer()

    import io
    import os
    import sys
    import math

    import pandas

    from bokeh.io import output_file, show
    from bokeh.plotting import figure

    output_file("signal.html")

    def fillSquareWave(xi, downi, upi):
        resultx = [0,]
        resulty = [0,]
        lasty = 0
        for x, down, up in zip(xi, downi, upi):
            if (math.isnan(down)) and (math.isnan(up)):
                # no dropna() at pandas level, since it'd drop if EITHER is a nan (we only drop if BOTH are)
                pass
            else:
                # append extra point
                resultx.append(x)
                resulty.append(lasty)

                # append real, current point
                resultx.append(x)
                if (not math.isnan(down)) and (math.isnan(up)):
                    resulty.append(0)
                    lasty = 0
                elif (math.isnan(down)) and (not math.isnan(up)):
                    resulty.append(1)
                    lasty = 1
                else:
                    print("x: ", x, " down: ", down, " up: ", up)
                    assert(False)
        return resultx, resulty

    sourcefile = os.path.basename(sys.argv[1])
    bothpts = pandas.read_csv(sourcefile, usecols=['Time', 'down', 'up'])
    uppts = pandas.read_csv(sourcefile, usecols=['Time', 'up']) 
    uppts.dropna(inplace=True)
    uppts['up'] = 1
    downpts = pandas.read_csv(sourcefile, usecols=['Time', 'down']) 
    downpts.dropna(inplace=True)
    downpts['down'] = 0

    php = figure()
    php.scatter(uppts['Time'], uppts['up'], legend='up',)
    php.scatter(downpts['Time'], downpts['down'], legend='down')
    xdata, ydata = fillSquareWave(bothpts['Time'], bothpts['down'], bothpts['up'])
    php.line(xdata, ydata, legend='overlay')
    php.legend.click_policy = "hide"

    show(php)

    print("Rendered in %.2fs" % (timeit.default_timer() - start_time))
此代码生成的绘图与问题略有不同-它从(0,0)开始绘制,而不是从CSV文件中第一个点的坐标开始绘制

编辑:可以使用以下代码删除多个read\u csv()调用,但执行时间基本不变

    bothpts = pandas.read_csv(sourcefile, usecols=['Time', 'down', 'up'])
    uppts = copy(bothpts)
    del uppts['down']
    uppts.dropna(inplace=True)
    uppts['up'] = 1
    downpts = copy(bothpts)
    del downpts['up']
    downpts.dropna(inplace=True)
    downpts['down'] = 0

问题是关于如何使用Bokeh而不是Matplotlib创建交互式绘图。谢谢。有趣的是,matplotlib对这个确切的用例有很好的解释。然而,我已经非常喜欢Bokeh绘图了,所以我的纯Python解决方案现在必须要做,特别是因为基准测试已经证明它是可以接受的。非常好的答案,Pandas和Bokeh都有很多值得学习的地方,特别是通过给它们相同的图例名来合并多个glyph是可能的。谢谢然而,您的答案有一个很大的缺点-它比我当前的代码慢得多:在我的7700点测试文件中大约是2.4s,而我的大约是1.4s。我怀疑对boolean_map()的7700次调用会伤害到你。我将发布我的代码作为答案,以防感兴趣。很可能,数据大小没有说明,所以我选择了“最简单”的东西。我已经更新了答案,以便它可能更有效。它应该是down.isnull()或up.notnull(),但由于我无法解释的原因,它仍然需要相同的2.4s。哦,好吧。