Python基础小项目

plotly绘图说明

2019-02-01  本文已影响1141人  栽生物坑里的信息汪

(可以不看的废话)

从上篇博客开始就一直在忙,忙了好几个月的文章以后,最近终于是在一个deadline之前把文章投了出去,所以也就可以重新回归写博客的日子了。在新年之前,再看看能不能写一两篇的博客吧。当然看的人可能也不是很多就是。
关于今天的这篇博客,主要还是来讲一下我现在超级超级超级喜爱和用的也很得心应手的python的一个画图的包--plotly。

更新预告(flag): 可能会写一些关于speciation的东西。

plotly介绍

plotly是一个开源的python的库,本质上它应该是一个收费的企业级的软件,官网在plotly,它对自己公司的定位即

Modern Analytics Apps for the Enterprise

所以其实是它们的公司想必除了开发plotly以外还是想做一些分析的平台的工作的,应该是偏向于统计分析的部分,当然这不是我们需要关注的地方。回到plotly本身,plotly其实主要是一个基于d3.js开发的一个js的库,而除了js的开发以外,它也对不同的编程语言开发了多种多样的库和工具包。例如R、matlab、python。由于它的核心代码其实js,其它的工具包和库其实仅仅是作为一个相应的编程软件对js的一个API,所以我们就不详细的讨论它的源代码了 (毕竟我也看不太懂。。。),而在plotly.py中,相关的内容也藏的比较深,结构比较复杂,我也不想过于深入的去讨论它的源码。

除了对plotly的背景介绍外,plotly能做的事情当然是重中之重的介绍点。基于js的绘图库最大的特点就是可交互。最原始的output结果是html格式的,所以输出的结果就是一个使用plotly.js进行绘制的一个网页,当然如果是需要它生成一个静态的图的话也是没什么问题的,它同样也支持直接生成pdf,png之类的。

plotly的资料

plotly这个软件在国内的使用率似乎并不高,所以很多中文的相关资料都十分的匮乏,所以资料方面也不是很多,这里就只放一个plotly的官网以及一个Stack Overflow的专区的链接好了。

官网链接
stack overflow tagged plotly

plotly的起始(哲学)

由于我使用plotly也有一段时间了,加上如果我从基础开始讲一个库的使用其实也十分的没有意思,还不如让你们直接去看官网的教程(毕竟我自己就是这么开始的),所以我在这里从着重讲一些高度概括的,一些更为核心的东西。不要求初学者一看就能懂,但是可以在听说了这些哲学以后,在学习和掌握plotly中更为得心应手,我也觉得这才是一个博客的意义所在,而不是照搬照抄,那完全只是一堆冗余知识的堆叠。

  1. 层/踪迹(trace)的思想

plotly的设计上相较于matplotlib这些库,思想上更为接近photoshopillustrator。所以对于接触过这些的人来说也更为便于学习和理解。意思就是说,在画一张图时,基本单位应该是一层,这一层原则上应该是同类的对象(例如scatter, bar, box, heatmap等),初学者都可以把这些认为是一些对象(高级玩家可以自定义对象,因为像heatmap就是一堆bar的堆叠嘛。)

  1. data与layout分离

除了上一个中说的层的思想,层都是在data内部的。然后就是说layout和data都是分离的,这个其实很好理解,因为像matplotlib之类的绘图库其实也差不多,所以这个也不多加讲解。

  1. 基于dict (json)的数据结构

在上述的plotly的介绍中其实讲到了一个很重要的一点,也就是plotly的核心是一个js的库,那么与库交流时,最常见的是一种叫json的数据结构,json的数据结构在python中不是一种常规的数据结构,但是最为相近的也就是dict,所以plotly.py在设计时,也就将一张图的数据,定位在dict上。
那么plotly的这种思想有什么特点呢?在后面具体的例子中大家应该会有更深的体会,这里只简单的说。dict类似的数据结构,非常方便大家记忆和查找相关的属性。像最为基础的python的一个绘图库matplotlib,我用不惯的原因很大程度上就是因为它的互相引用和数据结构过于复杂弯曲,一个figure有axes,axes又可以绕回figure,所以不是一个单向的纯粹的层级结构。plotly的设计则十分的简洁明了。

  1. 子图(subfigure)和坐标轴(axes)及其标签(ticklabels)是相互独立的

在绘图时,除开了以上几点,最需要细心的地方也是最容易出问题的地方就是子图或者坐标轴这些问题了。其中坐标轴的标签也是劝退大部分人的地方,plotly的设计我也不确定是好是坏,但是它将每一个子图和坐标轴割裂开了,通过layout中的一些名称进行绑定,你可以使坐标轴绑定多个子图,也可以让子图自由的伸展、排布成不同的布局。同时,标签这些也是很容易的去设置,只要你了解不论是类别变量的标签(ticktext)还是数值变量的标签(ticktext)其实本质都是基于数值变量的标签(tickvalues),前两个是看到的,最后一个大部分时候是隐藏的

  1. 交互动画的开关机制

上面讲的一些其实都是跟交互没太大关系的,最终当然也能实现交互的结果,不过那些更多的是由于本身就自带的缩放(scale/zoom)的功能了。plotly中,所有的交互,例如button、slider和play都是在layout中的,这一点一定程度上是为了适应js的代码吧。因为plotly的基本逻辑是这样的,你把所有你需要绘制的东西全部一次性的放在一个figure内部,然后通过layout中的updatemeanus内的开关进行调控。而这些开关其实都直接对应到了js的一些function,然后通过这些函数实现点击(click)button/拖动slider时,隐藏某些traces,显示某些traces这样子的功能以达到交互(interactive)的功能。

plotly的哲学基本上以上的几点,在了解和知道这些的基础上,我觉得可以更好的去理解和使用这个绘图的库。

plotly的基本使用(结合上述提到的所谓plotly哲学的一些demo)

trace和dict

import plotly
import plotly.graph_objs as go

import numpy as np

N = 1000
random_x = np.random.randn(N)
random_y = np.random.randn(N)

# Create a trace
trace1 = go.Scatter(
    x = random_x,
    y = random_y,
    mode = 'markers'
)
random_y2= np.random.randn(N)

trace2 = go.Bar(x = random_x,y = random_y2)
data = [trace,trace2]

plotly.offline.plot(dict(data=[trace,trace2]))
demo1

最终它可以输出这样的一个图,其实理论上说这个图(毫无意义),也很,但其实我只是为了说明bar 图和scatter图的共存,在plotly中,他们两个属于两个互不干扰的trace,并且,每次初始化一个trace时,除了直接使用go.Scatter或者go.Bar以外,内容物真的只需要通过类似于dict的方式就可以指定。如上的代码。

subplot、interactive和dict

import plotly
import plotly.graph_objs as go
import plotly.figure_factory as ff
import numpy as np
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X_full, y_full = dataset.data, dataset.target

X = X_full[:, [0, 5]]

distributions = dict([
    ('Unscaled data', X),
    ('Data after standard scaling',
        StandardScaler().fit_transform(X)),
    ('Data after min-max scaling',
        MinMaxScaler().fit_transform(X)),
    ('Data after max-abs scaling',
        MaxAbsScaler().fit_transform(X)),
    ('Data after robust scaling',
        RobustScaler(quantile_range=(25, 75)).fit_transform(X)),
    ('Data after power transformation (Yeo-Johnson)',
     PowerTransformer(method='yeo-johnson').fit_transform(X)),
    ('Data after power transformation (Box-Cox)',
     PowerTransformer(method='box-cox').fit_transform(X)),
    ('Data after quantile transformation (gaussian pdf)',
        QuantileTransformer(output_distribution='normal')
        .fit_transform(X)),
    ('Data after quantile transformation (uniform pdf)',
        QuantileTransformer(output_distribution='uniform')
        .fit_transform(X)),
    ('Data after sample-wise L2 normalizing',
        Normalizer().fit_transform(X)),
])

y = minmax_scale(y_full)
# scale the output between 0 and 1 for the colorbar

# 
fig = plotly.tools.make_subplots(rows=2,cols=2,specs=[[{},None],[{},{}]],shared_xaxes=True,shared_yaxes=True)
#This is the format of your plot grid:
#[ (1,1) x1,y1 ]      (empty)    
#[ (2,1) x2,y2 ]  [ (2,2) x3,y3 ]
# 初始化了一个如上的一个figure布局,以便进行绘图

traces = []
for scaler,scaled_X in list(distributions.items())[:1]:
# 只画第一个的话,如下
    _fig1 = ff.create_distplot([scaled_X[:,0]], [each_X],show_hist=False,show_rug=False)
    _fig2 = ff.create_distplot([scaled_X[:,1]],[each_X],show_hist=False,show_rug=False)
    trace = go.Scatter(x=scaled_X[:,0],y=scaled_X[:,1],mode='markers',marker=dict(color=y),yaxis='y2',xaxis='x2',name=scaler,legendgroup=scaler)
    fig.append_trace(go.Scatter(x=_fig1.data[0]['x'],y=_fig1.data[0]['y'],mode='lines',name='upper left',legendgroup=scaler),1,1)
    fig.append_trace(go.Scatter(x=_fig2.data[0]['y'],y=_fig2.data[0]['x'],mode='lines',name='down right',legendgroup=scaler),2,2)
    fig.append_trace(trace,2,1)

fig.layout.xaxis1.domain = [0,0.8]
fig.layout.xaxis2.domain = [0.85,1.0]
fig.layout.yaxis1.domain = [0.85,1.0]
fig.layout.yaxis2.domain = [0,0.8]
fig.layout.width = 1000
fig.layout.height = 1000
plotly.offline.plot(fig)

上面的代码画出来是这样的。


demo2

由于是交互的,我觉得大家最好还是自己试一试会体会更深。(当然我要是放在jupyter notebook上也就更好了,但是我有点懒。。。)

那么我们上面的代码仅仅只画了一个,那怎么能行呢!对吧。接下来我们在上面的代码的基础上,再加一些东西,使它更有意思起来。

上一篇下一篇

猜你喜欢

热点阅读