plotly是一款强大的作图工具,可以快速制作各种精美的图表,而且生成的图表可以实时与用户产生交互,大家可以参考官网的示例。
如散点图
3D图
plotly本身是基于javascript开发的,但是提供了大量与其他主流数据分析语言的API,比如Python, R, Matlab,可以参考https://plot.ly/api/。
如果你是Python用户,plotly不仅可以从原生的Python获得支持,如果你正在使用matplotlib,pandas等库,plotly也有专门为其量身定制的接口。
R语言用户想必已经熟悉ggplot2, 在R语言中只需要针对一个ggplot2图形对象p进行如下操作
ggplotly(p)
就会直接将其转化为一个plotly对象,十分方便。
个人觉得plotly与ggplot2在图形语法上有很多相似之处,所以R语言用户可能会很快上手,起初我也是在R语言环境中使用plotly,但是R语言中对于LaTeX的支持不是很好,从而转向Python。
plotly的官网文档十分详尽,然而对于初学者而言不太容易找到自己的需求。我接触plotly大概已经一个星期,所以在这里记录下我的一些最基本的经验,说不定谁看了这篇文章之后可以少走一些弯路。
Python用户可以直接使用pip安装plotly,我比较熟悉Python3.
sudo pip3 install plotly
本篇文章以我在自己科研中获取的一些数据为基础,绘制一幅最简单的散点图,并在图上添加一些基本的图形元素
首先,获得的数据(csv格式)如下,一共约15000条数据,这里只是头部
建议大家使用IPython Notebook,可以十分方便地与图形进行交互 。
首先导入plotly与pandas,可以用pandas中的read_csv直接读取原始数据。
下面就可以利用plotly绘制散点图。考虑到我们一共有7列数据,现在我们想研究前三列(MH, MH3, MH5)的相互关系,那么我们可以考虑将其中两个的数值映射到x, y轴,另一个变量的值可以用点的颜色来表征,下面是代码
绘制出的图像如下
其中有几点地方需要注意整个图像的比例不是很协调,需要我们重新调整其长和宽。
x轴,y轴,以及右侧的图例分别代表什么含义,这个图里并没有体现。
这个图中的配色方案是‘Viridis’,plotly默认了不少其他美观的配色方案,具体效果可以参考本文附录三。
接下来我们就涉及到了“图层”的概念,以上的图像仅仅就是将原始数据映射到坐标轴上,如果我们还想继续设置x轴的标题,y轴的标题,以及在图像上添加一些几何图形,那么就可以往上继续添加图层——layout(这里就是ggplot2作图的思想)
go.Layout就可以创建图层对象,具体用法如下:
得到的图像为
这样x轴, y轴以及整个图像都有了标题,而且图像的尺寸也得到了调整。
接下来我们可以往图上添加一些简单的几何图形,我们就以直线为例
同时在定义图层时加上shapes属性
我们得到
线段,圆形,矩形等plotly都有相应的选项,如果需要的话可以查看其关于shapes的文档https://plot.ly/python/shapes/
接下来我需要在图像上画一些交叉点,这个plotly自身并不支持(反正我没找到),但是我们可以用两条线段来组合成一个交叉点。
于是可以定义这样一个函数,给定一个坐标,返回组成这个交叉点的两条直线,这很简单
然后我们将layout中的shapes改成
最后得到我想要的图像
到这里我需要的图基本已经完成了,其实没有什么复杂的地方。认真的读者应该发现了,为什么我右侧的图例上没有标题?
这个问题非常好,因为我也不知道怎么在Python中在图例上添加标题。。
我查了不少官方的手册,到现在都没有一个比较好的解决办法,这个问题在R语言中是不存在的,这是R语言的代码,十分简洁,只是省略了line1,line2的定义
plot_ly(data, x=~MH5, y=~MH3, color=~MH, marker=list(size=3))%>%layout(shapes=list(line1,line2))
可以看到右侧图例的标题是自动加上的,而在Python中我却没有找到好的解决办法,如果大家知道的话请告诉我,感激不尽。。
(其实我强行找了一种十分丑陋的方法,但是也算勉强解决了问题,具体实现方法可以参考附录二)
以上就是我这几天来学习plotly的一些心得,刚开始接触的时候面对官方文档纷繁复杂无从下手,到现在稍微找到一些眉目,所以在这记录下来与大家分享,时间仓促中间不免有些疏漏,还请大家指正。
附录一:
完整的Python3代码
def cross(x, y):
line1 = dict(
type = 'line',
xref = 'x',
yref = 'y',
x0 = x - 4,
y0 = y - 5,
x1 = x + 4,
y1 = y + 5,
line = dict(
color = 'black',
width = 2,
)
)
line2 = dict(
type = 'line',
xref = 'x',
yref = 'y',
x0 = x - 4,
y0 = y + 5,
x1 = x + 4,
y1 = y - 5,
line = dict(
color = 'black',
width = 2,
)
)
return line1, line2
import plotly.plotly as py
import plotly.graph_objs as go
import pandas as pd
data = pd.read_csv('30_-10_full.csv')
aes = go.Scatter(
x = data['MH5'],
y = data['MH3'],
mode = 'markers',
name = 'MH',
marker = dict(
color = data['MH'],
size = '5',
colorscale = 'Viridis',
showscale = True
)
)
line1 = dict(
type = 'line',
xref = 'x',
yref = 'y',
x0 = 200,
y0 = 100,
x1 = 200,
y1 = 600,
line = dict(
color = 'black',
width = 2,
)
)
line2 = dict(
type = 'line',
xref = 'x',
yref = 'y',
x0 = 100,
y0 = 180.385,
x1 = 519.615,
y1 = 600,
line = dict(
color = 'black',
width = 2,
)
)
layout = go.Layout(
title = '$MH_5, MH_3$',
autosize = False,
width = 1000,
height = 800,
shapes = [line1, line2, cross(230, 530)[0], cross(230, 530)[1], cross(230, 430)[0], cross(230, 430)[1], cross(230, 330)[0], cross(230, 330)[1], cross(300, 530)[0], cross(300, 530)[1], cross(300, 430)[0], cross(300, 430)[1], cross(370, 530)[0], cross(370, 530)[1]],
xaxis = dict(
title = '$MH_5$'
),
yaxis = dict(
title = '$MH_3$'
),
)
fig = go.Figure(data=[aes], layout=layout)
py.iplot(fig)
附录二:
在Python环境下给右侧图例添加标题的一种方法:
然而其所用例子多是折线图, 图例的标题实际上是可以在go.Scatter中的‘name’选项定义的,就像这样
实际上如果大家加上这么一句再运行的话是不起任何效果的。
我发现这样一个事实,只有当存在至少两个data对象的时候才会显示legend的名字,所以我们可以在图中添加一个很小的白色的点,并且将它的名字设置为一个空格(即空白),但是单独作为一个对象,即
再在最后组合data与layout的语句中加上aes1
最后我们得到
可以看到右侧图例总算有了一个名字,虽然不在正上方,也不是很好看,不过至少有了。同时(300,300)新加的这个点根本看不见。
这个问题应当去阅读plotly的源码才能更好地解决,这里只是一个权宜之计。
附录三:
plotly自带的一些colorscale配色方案,方案的名字我已经写在图像的标题上了。
Viridis就是我们之前所用的颜色,如果你想使用下面的colorscale,只需将代码中的‘Viridis’改成相应的名称就好了