如何在 Ipython Notebook 中画动态交互

1. 写在前面

好久好久之前,咱们在 python 里面画图都是用 matplotlib 这个包,固然如今好像也还在用它,不过我一直以来都不太喜欢这种方式,由于 matplotlib 画出来的图都是静态图片,虽然作简单的展现没什么压力,可是图形复杂后就不方面了,好比说下面这些场景:css

  • 一个数据有好几千个数据点,若是想观察其中某一个区间的数据点肿么办呢?
  • 同时画了好几条数据,若是只想观察其中某条数据的状况呢?
  • 想鼠标 hover 上去能够看到某条数据在某个数据点上的数据值?
  • 。。。
  • 。。。

因此差很少两年前左右,为了既能在 ipython notebook 里作数据分析和研究,又能有个地方来作数据展现,我搞了个开源项目:Ipython Notebookhtml

下面是一张在 github 上的项目介绍截图:前端

下面是在 youtube 上的 demo 视频,不要问我为何不放 youku 的连接,由于不想在优酷的广告时间插播,哈哈。python

https://user-gold-cdn.xitu.io/2017/12/6/1602b0948936aaad

当时这个项目作了几个月,小有成效,彻底够用,可是在 2016.04 后就没有再更新过了,由于当时这个项目是为了作数据展现用的,要展现的数据是本身作量化策略的一些分析结果,而后当时由于这个项目差很少已经够用了,就没有再继续作下去,而是把更多的时间花在量化策略研究上面了。git

而后在2016.04 到最近的一年多里,我发现有不少人 star 和 fork 了我这个项目,差很少从 200不到的 star 增长到近 300 个star了,说实话虽然不是不少,可是我内心仍是很感谢各位捧场的朋友的。只是我我的的行事风格向来都是 只关注最核心的事,因此之后也不会再花时间在这个项目上了,而且如今我已经有了更方便快捷好用的,直接能在 ipython notebook 里画动态交互图的方案,因此其实我本身也已经弃用了这个项目了。github

不过看到还有这么多人在关注这个项目,我想你们也许跟之前的我同样,很想要一种在 ipython notebook 里画动态交互图的工具和方法。因此我准备把如今本身是如何解决这个问题的方案写出来跟各位一块儿分享,算是感谢各位一直对这个项目的关注了。sql

2. 原理说明

  • ipython notebook 说白了,就是一个 html 格式的文档,那既然 notebook 自己就是 html,那原理上固然也能够把一个 html 格式的图嵌入到 notebook 里。
  • ipython 自己提供了一个函数,IPython.core.display.publish_display_data 这样一个内置函数,可让用户指定输出到 notebook 中要展现的数据是什么样的。
  • 因此,咱们所要作的工做就很简单了:
    • 须要生成一个 html 格式的图表数据
    • 调用 IPython.core.display.publish_display_data 函数把图表数据插入到 notebook 里面。

下面,咱们就从要作的工做出发,分两步来完成这个工做。后端

3. 若是经过 python 代码来生成 html 格式的图表数据

如今最经常使用的动态交互图的前端框架大概有下面几个:highcharts,d3.js,nvd3.js,echarts,c3js 这几个,首先明确一点,要想经过 python 来搞一个 html 格式的交互图,确定须要间接的经过上面这些 js 库来实现。你别跟我说你要用 python 来从 0 到 1 生成一个 html 格式的图,要否则我真的会对你五体投地~。既然如此,那就先看看 google 大法,分别搜搜 python highchartspython d3.js 啥的,看看有没有前人已经把轮子造好了。bash

果不其然,网上已经有很多轮子了,那接下来的工做就是众水三千,看你用哪一个瓢了,哦,不对,是看你喝哪一瓢了~前端框架

最后我选的是 highcharts 的一个实现,github.com/arnoutaertg…,缘由有几点:

  • highcharts 有个孪生兄弟 highstock,专门用于画股票行情 k 线的,很是不错,很适合我本身的应用场景
  • 咱们项目用来画图的库就是 highcharts,有大神在,出问题了能够秒问,省时省力
  • 这个库的接口看起来很简单,人家写的例子也不错,入手快:nbviewer.jupyter.org/github/arno…

ok,其实找到这个库以后,基本上就完成大半工做了,只须要把这个库针对数据分析,展现的场景再优化优化就能够了,因此接下来,我算是站在巨人的肩上,作了两件小事:

  • 优化了接口,专门适配 pandas dataframe 的数据格式
  • 结合 ipython notebook 场景,包装了 IPython.core.display.publish_display_data 函数

下面分开来讲:

3.1 dataframe + charts

都是简单的活儿,直接看核心代码咯,别跟我说看不懂代码,曾经一个同事要求跟我开发一个 module,结果尼玛他一个星期都看不懂千来行的代码,还让我给他画架构图,WTF~~~

def draw(df, x, y, title=None, **kwargs):
        """核心画图代码,传入 dataframe,和相关的配置,返回图表对象,在 notebook 场景下可直接展现 该函数包装了 charts 包的一个接口,使之更方便的适配 pandas dataframe 数据结构 参数: df:dataframe 数据结构 x(int / str): x 坐标轴,必须是传入的 df 的某一个 column y(list): y 坐标轴,必须在传入的 df 的column中出现 title:图表名字 kwargs:可选参数,默认都是 charts 支持的参数,如: x_type: x 坐标轴的数据类型,默认是 datetime 类型 x_labels: 可自定义 x 坐标轴的 label 内容 subtitle: 子标题内容,能够显示一些图标的统计指标 width: 图表宽度 height: 图表高度 options: 图表 options,不经常使用,能够直接参考源码中的默认配置 返回: charts 的图表对象,在 notebook 中能够直接运行展现 """
        my_options = copy.deepcopy(options)
    
        title = title if title else str(y)
        my_options['title']['text'] = title
        tmp = df[[x] + y]
    
        x_type = kwargs.pop('x_type') if 'x_type' in kwargs else 'datetime'
        x_labels = kwargs.pop('x_labels') if 'x_labels' in kwargs else None
        subtitle = kwargs.pop('subtitle') if 'subtitle' in kwargs else ''
         
        if x_type == 'datetime':
            tmp.set_index(x, inplace=True)
            tmp.index = tmp.index.to_datetime()
        else:
            my_options['xAxis']['type'] = x_type
            my_options['xAxis']['categories'] = df[x].tolist()
    
        if x_labels:
            my_options['xAxis']['categories'] = x_labels
    
        if 'options' in kwargs:
            my_options.update(kwargs.get('options'))
            kwargs.pop('options')
    
        if 'width' in kwargs:
            my_options['width'] = kwargs.get('width')
    
        if 'height' in kwargs:
            my_options['height'] = kwargs.get('height')
    
        if subtitle:
            my_options['subtitle']['text'] = subtitle
    
        return charts.plot(tmp, options=my_options, show='inline', display=y, **kwargs)

复制代码

ok, 到此,从 dataframe 到动态图表已经搞定了,接下来是如何结合到 ipython notebook 中,其实,上面几乎已经完成大半了,由于若是这个画图函数是在 notebook 中的单元格里最后运行的一个函数,且没有把返回结果显示的赋予一个变量的话,notebook 会默认展现函数输出的结果的。好比下面截图:

3.2 charts to ipython notebook

上面截图里,咱们把图表对象放到一个变量 figure 里了,这个 figure 变量有个属性:figure.data,里面存储的就是字符串格式的 html 格式的图表源码,so 那就简单多了,直接复用函数就搞定了: lambda figure: IPython.core.display.publish_display_data({'text/html': figure.data})

def print_html(html_text):
    """将 charts 图表的 html 数据手动展示,通常适用于循环做图的场景 """
    IPython.core.display.publish_display_data({'text/html': html_text})

复制代码

4. 效果展现

下面简单展现下效果,为了你们方便,我把测试数据也准备好了,因此这个 notebook 你们是能够直接下载下来运行的,个人环境是:python 2.7 + ipython 3.2.2

https://user-gold-cdn.xitu.io/2017/12/6/1602b0adaffa2dcb

按照节奏,如今通常应该把源码和案例全放上来了,ok:

回头再看看有木有必要提个 pr 到那哥们的 repo 里。

最后贴上我几乎每天在用的一个案例,真正实现了一键出图,哈哈:litaotao.github.io/files/repor…

5. 后记

首先仍是感谢各位 star 了个人项目的朋友们,下面大家能够来 star 个人博客吧,源码和demo我都放到博客下的 files 下面了。哈哈。虽然不会常常更新【常常更新就必定是好事?】,可是保证在一些场景下,绝对比之前的好用好多好多倍呢,因此快来 star 吧。

而后是想聊聊作这个项目的一些感触,如今回想,一开始作的时候超兴奋的,甚至有时候回家了还调试,特别是一边现学 html/css/js 那些东西,一边先后端结合起来调试,偶尔还有种 欲与天公试比高 的激动。不过当时作到后来,我竟然开始添加一些很鸡肋的功能【好比说 sql】,当时想的是添加一个 online sql query & visualization,幸亏 2016年初来了个股灾3.0,让亏了10几个点的我及时止步,我记得当时再决定是否要继续作这个 sql 工具的时候,我当时的心里独白大概是下面这样子的:

  • 我最须要的是啥?

一个能够动态画图的工具。

  • 我最在意的是啥?这个工具?仍是这个工具服务的对象:投资策略?

固然是投资策略了,你妹的,我搞工具干吗~

  • 那我为啥会蛋疼的相加一些炫酷的功能?

由于蛋疼,想在 github 上多攒点 star,哈哈。

  • 多攒 star 重要仍是研究投资策略闷声发财重要?

你妹的,这还用问吗?

  • 那如今工具够用了,你还要接着瞎搞仍是回来专心研究策略了呢?

好吧,我浪子回头,工具够用就好了,我要专心研究策略了。

如今,我仍是很庆幸当时没有继续搞这个项目,而是把这些时间放到研究上去了,这一年多了在研究方面积累了我我的看来至关有养分的东西。

其实结合起一些经验来看,我发现大千世界真的事事向通。好比说,最近两三年关于创业不少的几本书:《创业维艰》,《精益创业》,《The One Thing》,我总结下来,其实能够简单的说:找到一个核心问题,而且找到一个能解决这个核心问题的解决方案,而后不断的把这个方案作到极致。是否是很熟悉,立刻我就能在之前看过的鸡汤书里找到几句雷同的话,好比说我大新东方总教头余老师说的 “努力作到行业内的 top 20”;好比说如今的我大中华传承了几千年的经验 “360行,行行出状元”。若是这些都比较虚,那能够简单反思本身,在你买的不少东西中,无论网上网下,真实的仍是虚拟的,你是由于它功能丰富买单呢?仍是由于它真切的解决了你的某一项需求而付钱呢?相似的论断,我也在前段时间写的工做感悟中有提到,在这里,第八条: 工做 3 年后的一些思考【Part 3】

好像又扯了很多了,最后感谢下开发了这个 github.com/arnoutaertg… repo 的哥们,的确省了我很多时间,而后也感谢各位观众们,哈哈,不要忘了给我 star 啊,哈哈哈哈~~~

相关文章
相关标签/搜索