ministep / SQL_DataAnalysis

SQL数据分析
9 stars 0 forks source link

可视化神器plotly(1):基础图表与画布、坐标轴 - 古明地盆 - 博客园 #72

Open kemistep opened 4 years ago

kemistep commented 4 years ago

作者:@古明地盆
喜欢这篇文章的话,就去 bilibili 看看我吧,虽然啥也没有。:https://space.bilibili.com/12921175


楔子

下面来看一下 plotly 这个绘图神器,废话不多说,直接正题走起。

图表绘制

import plotly as py
import plotly.graph_objs as go
import numpy as np
import pandas as pd

上面几个模块基本上先导入就行,plotly.graph_objs 是专门用来绘制图表的,比如 go.Scatter 就是散点图,在 plotly 中,绘制出来的图表称之为一个 trace(轨迹),然后轨迹显示在 figure(画布) 上面,当然一个画布是可以显示多个轨迹的。我们下面的代码在 jupyter notebook 上运行,可以直接显示图表。至于图表如何保存成图片,我们后面说。

散点图

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100)
random_y2 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0,  
    mode="markers",  
    name="markers"  
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
    mode="markers + lines",  
    name="markers + lines" 
)

trace2 = go.Scatter(
    x=random_x,  
    y=random_y2, 
    mode="lines",  
    name="lines"  
)  

fig = go.Figure(data=[trace0, trace1, trace2])

fig

此时画布上的图表就已经显示出来了,可以看到比 matplotlib 漂亮多了。此时我们使用了 4 个参数,回顾一下:

我们再来看一个参数,marker:

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
    mode="markers",  
    name="上方",  
    marker={
        "size": 8,  

        "color": "rgba(102, 198, 147, 0.7)",  
    }
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
    mode="markers",  
    name="下方",  
    marker={
        "size": 8,  
        "color": "rgba(252, 108, 117, 1)",  

        "line": {
            "width": 10,  
            "color": "rgba(1, 170, 118, 0.3)"  
        }
    }
)

fig = go.Figure(data=[trace0, trace1])
fig

现在我们有接触到了一个参数 marker,这个是给点设置样式的。结构如下:

marker = {

    "size": n,

    "color": "rgba(n1, n2, n3, n4)",

    "line": {"width": n, "color": "rgba(n1, n2, n3, n4)"}
    "showscale": True  
}

至于其它参数可以自己去查看,这里就不说了,只会说一些常用的,其它参数可能后面会涉及。但没涉及的话,可以通过help(go.Scatter)查看。不过可能有人会好奇,那如果我想添加标题以及坐标轴名称该怎么办?显然是可以添加的,只不过不在轨迹里面添加,而是在画布里面添加。

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
    mode="markers",  
    name="上方",  
    marker={
        "size": 8,  
        "color": "rgba(102, 198, 147, 0.7)",  
    }
)

fig = go.Figure(data=[trace0], layout={"title": "这是标题", 
                                       "xaxis_title": "这是x轴",
                                       "yaxis_title": "这是y轴",

                                       "xaxis": {"tickangle": 60}
                                      })
fig

我们看到通过向画布传入 layout 即可给画布设置一些额外属性,如下:

当然除了上面这些,我们再说几个常用的:

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
    mode="markers",  
    name="上方",  
    marker={
        "size": 8,  
        "color": "rgba(102, 198, 147, 0.7)",  
    }
)

fig = go.Figure(data=[trace0], layout={"template": "plotly_dark"})
fig

layout 还支持其它哪些参数,可以通过 help(go.Layout) 查看,当然我们后面可能也会介绍几个。

线形图

线形图,或者折线图,它也是通过 Scatter 来绘制的。


trace0 = go.Scatter(
    x=sick["date"],  
    y=sick["number"], 
)

fig = go.Figure(data=[trace0], layout={"template": "plotly_dark",
                                       "title": "当前的患者人数"})
fig

虽然名叫 Scatter,但是默认绘制的是折线图,还记得怎么绘制散点图吗?对的,指定 mode="markers" 即可。

如果我想给折线添加样式肿么办?我们给散点图添加样式通过参数 marker 指定,而给折线添加样式也有对应的参数。

sick = df.loc[(df["country"] == "China")&(df["status"] == "confirmed"), ["date", "number"]].groupby(by=["date"], as_index=False).sum().sort_values(by="date")

trace0 = go.Scatter(
    x=sick["date"],  
    y=sick["number"],
    line={
        "width": 3,  
        "color": "rgba(255, 30, 186, 1)"  
    }
)

fig = go.Figure(data=[trace0], layout={"template": "plotly_dark",
                                       "title": "当前的患者人数"})
fig

我们看到此时折线的样式就改变了,但是我们记得之前在设置散点图的时候好像也用到了 line,没错。只不过那个 line 是传给 marker 参数的字典里面的一个 key,用来设置点的线条、或者轮廓的样式的,而这里的 line 它是一个参数,和 marker 参数是同级别的,是用来设置折线的样式的。

参数 line 里面还可以指定折线的种类,是虚线、实线等等之类的。

trace0 = go.Scatter(
    x=sick["date"],  
    y=sick["number"],
    line={
        "width": 3,  
        "color": "rgba(255, 30, 186, 1)",  
        "dash": "dot"  
    }
)

fig = go.Figure(data=[trace0], layout={"template": "plotly_dark",
                                       "title": "当前的患者人数"})
fig

"dash" 表示指定线条的种类:

有时候,我们的数据并不是连续的,中间可能会出现断层,这个时候我们可以指定 connectgaps 参数,举个栗子

x = np.array([1, 2, np.nan, 4, 5]) 
y1 = x * 3 + 1
y2 = x * 3 + 2

trace0 = go.Scatter(
    x=x,  
    y=y1,
)

trace1 = go.Scatter(
    x=x,
    y=y2,
    connectgaps=True
)

fig = go.Figure(data=[trace0, trace1])
fig

当数据出现了空值的时候,那么折线默认是会出现断层的,而指定 connectgaps=True,那么会将缺失值两端的点直接相连,使得直线是完整的。

柱状图

最简单的柱状图如下:

trace0 = go.Bar(
    x=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    y=[17, 400, 16, 17],
)

fig = go.Figure(data=[trace0])
fig

这个图形看起来就很漂亮,再次踩一脚 matplotlib。当然我们可以绘制多个柱状图:

trace0 = go.Bar(
    x=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    y=[17, 400, 16, 17],
    name="bar1"
)

trace1 = go.Bar(
    x=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    y=[86, 90, 96, 87],
    name="bar2"
)

fig = go.Figure(data=[trace0, trace1])
fig

除此之外我们还可以指定层叠柱状图:

trace0 = go.Bar(
    x=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    y=[17, 400, 16, 17],
    name="bar1"
)

trace1 = go.Bar(
    x=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    y=[86, 90, 96, 87],
    name="bar2"
)

fig = go.Figure(data=[trace0, trace1], layout={"barmode": "stack"})
fig

我们看到层叠柱状图是在画布里面设置的,因为将两个轨迹怎么组合是通过画布来设置的,至于 Bar 里面的参数是设置轨迹本身, 比如我们还可以调节颜色什么的,通过参数 marker 指定:

trace0 = go.Bar(
    x=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    y=[17, 400, 16, 17],
    name="bar1",
    marker={

        "color": "pink",
        "opacity": 1,  
        "line": {
            "width": 3,  
            "color": "cyan",  
        },
    }
)

trace1 = go.Bar(
    x=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    y=[86, 90, 96, 87],
    name="bar2",
    marker={
        "color": "green"
    }
)

fig = go.Figure(data=[trace0, trace1], layout={"template": "plotly_dark"})
fig

我们看到轨迹的颜色什么的也是通过 marker 指定的,里面也可以设置轮廓,和 Scatter 是类似的。

至于支持的一些其它参数,可以通过 help(go.Bar) 查看。

水平柱状图

水平柱状图和柱状图类似,也是通过 go.Bar 来绘制,只不过需要多加一个参数。

trace0 = go.Bar(

    y=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    x=[17, 400, 16, 17],
    name="bar1",
    marker={
        "color": "pink",
    },

    orientation="h"
)

trace1 = go.Bar(
    y=["古明地觉", "芙兰朵露", "古明地恋", "椎名真白"],  
    x=[86, 90, 96, 87],
    name="bar2",
    marker={
        "color": "green"
    },
    orientation="h"
)

fig = go.Figure(data=[trace0, trace1], layout={"template": "plotly_dark"})
fig

柱状图有多高取决于 y 轴,而水平柱状图有多长就取决于 x 轴了,所以此时 x 轴就是代表数值的那一方。至于设置颜色、轮廓等参数,和之前的柱状图一样。

甘特图

甘特图又称横道图,是用来显示项目进度等与时间相关的数据的。直接看个栗子就很好理解了:


import plotly.figure_factory as ff

tasks = [
    {"Task": "任务A", "Start": "2018-1-1", "Finish": "2018-3-1"},
    {"Task": "任务B", "Start": "2018-2-1", "Finish": "2018-5-1"},
    {"Task": "任务C", "Start": "2018-2-1", "Finish": "2018-6-1"},
    {"Task": "任务D", "Start": "2018-4-1", "Finish": "2018-8-1"},
    {"Task": "任务E", "Start": "2018-8-1", "Finish": "2019-1-1"}
]

fig = ff.create_gantt(tasks, title="这是甘特图")

fig

里面也可以直接传递一个 DataFrame

import plotly.figure_factory as ff

df = pd.DataFrame({"Task": ["任务A", "任务B", "任务C", "任务D","任务E"],
                   "Start": ["2018-1-1", "2018-2-1", "2018-2-1", "2018-4-1", "2018-8-1"],
                   "Finish": ["2018-3-1", "2018-5-1", "2018-6-1", "2018-8-1", "2019-1-1"],
                   "Complete": [10, 80, 80, 76, 100]
                  })

fig = ff.create_gantt(df, index_col="Complete", show_colorbar=True)

traces = fig.data  

fig = go.Figure(data=traces, 
                layout={"template": "plotly_dark", 
                        "title": "这是我们自己创建的画布上面的甘特图"})  
fig

我们看到 Complete 对应值相同的任务,颜色是一致的。并且右侧的条表示颜色对应的任务进度,这是通过 show_colorbar=True 显示的。并且此时的数据我们用到了四个参数:Task、Start、Finish、Complete,前三个是固定的必须叫这几个名字,至于 Complete 就没有要求了,叫其他的名字也是可以的,但是最好要见名知意,然后设置为 index_col,指定 show_colorbar=True。

并且我们除了通过数值来表示进度,还可以使用文字。

df = pd.DataFrame({"Task": ["任务A", "任务B", "任务C", "任务D","任务E"],
                   "Start": ["2018-1-1", "2018-2-1", "2018-2-1", "2018-4-1", "2018-8-1"],
                   "Finish": ["2018-3-1", "2018-5-1", "2018-6-1", "2018-8-1", "2019-1-1"],
                   "Complete": ["干了一小半", "干了一半", "干了一半", "干了一大半", "全干完了"]
                  })

colors = {
    "干了一小半": "rgb(125, 135, 144)",
    "干了一半": "rgb(187, 20, 168)",
    "干了一大半": "rgb(14, 199, 250)",
    "全干完了": "rgb(250, 1, 144)"
}

fig = ff.create_gantt(df, index_col="Complete", show_colorbar=True, colors=colors)  
traces = fig.data 
fig = go.Figure(data=traces, 
                layout={"template": "plotly_dark", 
                        "title": "这是我们自己创建的画布上面的甘特图"})  
fig

面积图

绘制面积图依旧使用 Scatter,所以 Scatter 可以用来绘制三种图形了。我们说里面参数非常多,因为它可以针对不同的图表。所以这些参数没必要在刚学的 Scatter 的时候一下子全部掌握,再加上它可以用在不同的地方,因此一下子学习全部参数比较累。所以,最好的建议是,针对图表或者轨迹来使用,当前绘制的轨迹需要哪些参数就学习哪些参数、或者使用哪些参数即可。

绘制面积图关键在于里面的一个 fill 参数

x = np.linspace(0, 2, 100)
y0 = np.cos(x)
y1 = np.sin(x)

trace0 = go.Scatter(
    x=x,
    y=y0,
    name="cos",
    mode="markers",  
    fill="tozeroy"
)
trace1 = go.Scatter(
    x=x,
    y=y1,
    name="sin",
    mode="none",  
    fill="tozeroy"
)
fig = go.Figure(data=[trace0, trace1], layout={"title": "面积", "template": "plotly_dark"})
fig

我们看到面积图就是将轨迹和 x 轴围成的部分涂上颜色,仔细观察橘色的 sin,线段没了,因为围成的部分有颜色,所以线段或者此时的面积图的边界线就可以隐藏掉了。如果不指定 fill,直接指定 mode="none" 也是可以隐藏的,只不过此时绘制的线段你就看不到了。另外,我们看到即使是散点也是可以围成面积图的,会用线将点拟合起来,再绘制围成的面积图。

此时我们又看到了一个参数 fill,这个 fill 就是用来绘制面积图的,当然在学习或者绘制散点图的时候,这个 fill 无需鸟它。我们将 fill 指定为 "tozeroy" 表示绘制和 x 轴围城的部分,很好理解,"tozeroy" 不是就是 "to"(到)"zeroy"(y 为 0 的地方)嘛,所以是 x 轴。当然除了,"tozeroy",还可以为 "none",表示不围成面积,当然此时直接不指定 fill 就行了。除了这些,还可以指定为其它的一些值:

x = np.linspace(0, 2, 100)
y0 = np.cos(x)
y1 = np.sin(x)

trace0 = go.Scatter(
    x=x,
    y=y0,
    name="cos",
    mode="none",  
    fill="tozerox"  
)
trace1 = go.Scatter(
    x=x,
    y=y1,
    name="sin",
    mode="none",  
    fill="toself"  
)
fig = go.Figure(data=[trace0, trace1], layout={"title": "面积", "template": "plotly_dark"})
fig

上面三个属性则是专门用来绘制两条线围成的面积,只需要第一条轨迹不填充,第二条轨迹填充即可。

x = np.linspace(0, 2, 100)
y0 = np.cos(x)
y1 = np.sin(x)

trace0 = go.Scatter(
    x=x,
    y=y0,
    name="cos"  
)
trace1 = go.Scatter(
    x=x,
    y=y1,
    name="sin",
    mode="none",
    fill="tonexty"  
)
fig = go.Figure(data=[trace0, trace1], layout={"title": "面积", "template": "plotly_dark"})
fig

我们变得到了两条线、或者轨迹在 x 轴上围成的面积图,同理 tonextx 和 tonext 可以自己绘制一下。但是一般我们使用的是 tonexty,即、绘制两条线在 x 轴围成的面积图

除此之外,我们还可以绘制出堆叠面积图,当然方法还是类似的。

x = np.array([1, 3, 2, 3, 5])
y0 = x + 1
y1 = x + 2
y2 = x + 3
y3 = x + 4

trace0 = go.Scatter(
    x=x,
    y=y0,
    name="y0",
    fill="tonexty"
)
trace1 = go.Scatter(
    x=x,
    y=y1,
    name="y1",
    fill="tonexty"
)
trace2 = go.Scatter(
    x=x,
    y=y2,
    name="y2",
    fill="tonexty"
)
trace3 = go.Scatter(
    x=x,
    y=y3,
    name="y3",
    fill="tonexty"
)
fig = go.Figure(data=[trace0, trace1, trace2, trace3], layout={"title": "面积", "template": "plotly_dark"})
fig

直方图

直方图种类比较多,我们分个小标题吧

基本直方图

x = np.random.randint(1, 20, 1000)  

trace0 = go.Histogram(
    x=x,
)

fig = go.Figure(data=[trace0], layout={"title": "直方图", 
                                       "template": "plotly_dark",
                                      })
fig

但是我们看到可读有些不完美,就是跨越的太大了,从 0 直接到 5 了,所以我们可以指定 xaxis 属性。

x = np.random.randint(1, 20, 1000)  

trace0 = go.Histogram(
    x=x,
    histnorm="probability"  
)

fig = go.Figure(data=[trace0], layout={"title": "直方图", 
                                       "template": "plotly_dark",
                                       "xaxis": {"dtick": 2, "range": [1, 20]}  
                                      })
fig

我们看到 y 轴的数量变成了比例,当然最重要的就是我们知道了如何调整坐标范围与坐标刻度了,当然我们后面会对画布、坐标什么的做一个全面的总结,里面可以指定哪些属性、都具有哪些效果之类的,当然还是只会介绍我个人认为可能会用到的。如果没有你想要的,可以去官网查看,抱歉啦。

重叠直方图

忘记说了,其实所有的图表对应的类里面,很多参数都是相同的,比如 marker 设置图表本身的颜色透明度、以及轮廓的颜色、大小,name 设置图表的名称等等,这些参数我们不再赘述,而是会直接使用。

x0 = np.random.randn(1000) 
x1 = np.random.chisquare(5, 1000)
trace0 = go.Histogram(
    x=x0,
    histnorm="probability",
    marker={
        "opacity": 0.75
    }
)
trace1 = go.Histogram(
    x=x1,
    histnorm="probability",
    marker={
        "opacity": 0.75
    }
)
fig = go.Figure(data=[trace0, trace1], layout={"title": "直方图", 
                                               "template": "plotly_dark",
                                              })
fig

但是我们发现这个直方图貌似有些不对劲,因为 plotly 将多个直方图强制变窄了,我们需要将 barmode 指定为 "overlay"

x0 = np.random.randn(1000) 
x1 = np.random.chisquare(5, 1000)
trace0 = go.Histogram(
    x=x0,
    histnorm="probability",
    marker={
        "opacity": 0.75
    }
)
trace1 = go.Histogram(
    x=x1,
    histnorm="probability",
    marker={
        "opacity": 0.75
    }
)
fig = go.Figure(data=[trace0, trace1], layout={"title": "直方图", 
                                               "template": "plotly_dark",
                                               "barmode": "overlay"
                                              })
fig

堆叠直方图

和柱状图类似,需要指定 barmode 为 "stack"

x0 = np.random.randn(1000) 
x1 = np.random.randn(1000)
trace0 = go.Histogram(
    x=x0,
    histnorm="probability",
    marker={
        "opacity": 0.75
    }
)
trace1 = go.Histogram(
    x=x1,
    histnorm="probability",
    marker={
        "opacity": 0.75
    }
)
fig = go.Figure(data=[trace0, trace1], layout={"title": "直方图", 
                                               "template": "plotly_dark",
                                               "barmode": "stack"
                                              })
fig

累计直方图

直方图的累计形式,第 n+1 个区间的样本数是第 n-1 个区间的样本数加上第 n 个区间的样本数。

x0 = np.random.randn(1000) 
trace0 = go.Histogram(
    x=x0,
    histnorm="probability",
    marker={
        "opacity": 0.75
    },
    cumulative={"enabled": True}  
)

fig = go.Figure(data=[trace0], layout={"title": "直方图", 
                                               "template": "plotly_dark",
                                              })
fig

饼图

饼图就很简单了,使用 Pie 这个类,Scatter 里面的 x 和 y 对应 Pie 里面 labels 和 values

trace0 = go.Pie(
    labels=["古明地觉", "芙兰朵露", "古明地恋", "雾雨魔理沙", "紫妈"],
    values=[10, 25, 5, 35, 41]
)

fig = go.Figure(data=[trace0], layout={"title": "饼图", 
                                        "template": "plotly_dark",
                                      })
fig

我们还可以设置环形饼图,就是在中间挖一个洞

trace0 = go.Pie(
    labels=["古明地觉", "芙兰朵露", "古明地恋", "雾雨魔理沙", "紫妈"],
    values=[10, 25, 5, 35, 41],
    hole=0.7  
)

fig = go.Figure(data=[trace0], layout={"title": "饼图", 
                                        "template": "plotly_dark",
                                      })
fig

我们还可以将饼图旋转一定角度,我们看到最上方的两个部分明显是垂直分隔的,另外我们还可以使某一个部分突出。

trace0 = go.Pie(
    labels=["古明地觉", "芙兰朵露", "古明地恋", "雾雨魔理沙", "紫妈"],
    values=[10, 25, 5, 35, 41],
    pull=[0, 0, 0, 0, 0.1],  
    rotation=30,  

    marker={

        "colors": ["yellow", "green", "cyan", "pink", "blue"],  
        "line": {
            "width": 3,
            "color": "white",  
        }
    }
)

fig = go.Figure(data=[trace0], layout={"title": "饼图", 
                                        "template": "plotly_dark",
                                      })
fig

不是总结的总结

到目前为止,我们介绍了常用的几个图表。重点就是 plotly 里面的轨迹和画布两个概念,我们使用 Scatter、Pie、Bar 等等得到的都是轨迹,然后还需要创建画布,将轨迹写在画布上,然后显示画布即可。至于轨迹,不同的轨迹的参数不同,plotly 最让人想批评的就是它的使用太复杂,其实也不算复杂。说白了就是参数太多了,但是功能强大也是没办法的事情。不过虽然如此,可不同的轨迹有很多参数都是类似的,首先两个坐标轴的数据就不用说了。其次就是 name 和 marker,name 是给轨迹起名字,如果画布上有多条轨迹能够让我们区分。还有就是 marker,我们说 marker 结构如下:

{
    "color或者colors": "表示轨迹本身的颜色",
    "opacity": "透明度",
    "line": {
        "width": "线条或者轮廓的宽度",
        "color": "线条或者轮廓的颜色"
    }
}

而我们说通过 marker 就可以绘制出漂亮的图形了,其实 plotly 的图表本身就很漂亮。至于轨迹的其它参数就就取决于轨迹本身的类型了,其实只要把绘制每个轨迹的关键参数记住,也就那么几个,再搭配 marker,我们就能绘制出漂亮的图表的,因为 plotly 默认绘制的图表就很漂亮。

至于像标题、坐标轴名称什么的,我们是通过画布来指定的。我们使用 go.Figure 来创建画布,我们实例化 Figure 这个类的时候,里面传递了两个参数,一个是 data、一个是 layout。data 很好理解,就是多个轨迹组成的列表,一个轨迹也要放在列表里面传进去。而 layout 则就是我们关心的、设置画布的属性了,而 layout 我们目前是通过字典传递的。


fig = go.Figure(data=[trace0, ...], layout={"title": "xxx"})

layout = go.Layout(title="xxx")  
fig = go.Figure(data=[trace0, ...], layout=layout)

而 layout 我们目前都设置了哪些属性呢?

layout = {
    "title": "图表的标题",
    "xaxis_title": "x轴的名称",
    "yaxis_title": "y轴的名称",
    "template": "图表的风格,支持哪几种可以回头翻一翻,我个人非常喜欢plotly_dark",
    "xaxis": {"range": "坐标轴的范围", "dtick": "刻度大小", "tickangle": "坐标旋转角度"}  
    "yaxis": "和xaxis同理",
    "barmode": "设置柱状图和直方图的堆叠属性的"
}

尽管 layout 里面的可设置的属性比较多,但是有的是通用的,比如:title、xaxis_title、yaxis_title、template、xaxis、yaxis,但有些则是针对特定轨迹的,比如 barmode。

掌握上面这些,对于工作中差不多够用了。但是我们还是要介绍一些更高级的东西,比如时间序列、多图绘制等等,不过要在下一篇博客中说了。

其它轨迹

都说了,上面不是总结了。我们再来说一下其它的轨迹(包含上面已经介绍的轨迹),至于长什么样子,可以自己尝试。这些都可以通过 plotly.graph_objs 进行调用,里面的参数可以通过 help(go.xxx) 查看

2d 平面轨迹

3d 立体轨迹

maps 地图

当然 plotly.graph_objs 里面支持的轨迹还不止上面说的这些,有兴趣可以自己查看。

layout

重点来了,我们说 layout 是给画布设置属性的,我们通过一个字典传递,那么通过字典都能传递哪些属性呢?下面来看一看,还是介绍我个人认为会使用的,有些参数会简单说明,有些参数我们以折线图举例说明。

title:标题

xaxis_title:x 轴名称

yaxis_title:y 轴名称

template:背景风格

template:支持 ggplot2,seaborn,simple_white,plotly,plotly_white,plotly_dark,presentation,xgridoff,ygridoff,gridon,none。默认是 plotly

titlefont:标题字体

autosize:自动调整大小 (不常用)

bargap:柱状图间距

bargroupgap:柱状图组间距,如果绘制多个柱状图的话

barmode:柱状图或直方图模式

boxgap:箱型图间距

boxgroupgap:箱型图组间距

boxmode:箱型图模式

calendar:日历

calendar:可以是以下字符串gregorian,chinese,coptic,discworld,ethiopian,hebrew,islamic,julian,mayan,nanakshahi,nepali,persian,jalali,taiwan,thai,ummalqura之一

direction:方向

可以是clockwise(顺时针)、counterclockwise(逆时针)之一

dragmode:图形拽动模式

可以是zoom,pan,select,lasso,orbit,turntable,False(布尔)之一

font:字体

传入一个字典:{"color": "颜色", "family": "字体类型", "size": "字体大小"},当然颜色、字体类型、大小不一定要全部指定

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"font": {"color": "green", "size": 20, "family": "stcaiyun"}, 
                                        })
fig

我们看到字体的颜色、大小、类型都变了。

geo:地理参数

height:图表高度,默认 450

width:图表宽度,默认 700

legend:设置右上角那个东东的属性

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"legend": {"bgcolor": "pink"}, 
                                        })
fig

我们看到变成了粉色。

hovermode:鼠标指针悬停时显示的数据

这个在 jupyter notebook 中使用,选项为: "x","y","closest",False 之一

margin:图表边缘间距

orientation:方向,针对柱状图。默认是竖向,横向需要指定此参数为 "h"

paper_bgcolor:画布背景颜色

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={
    "paper_bgcolor": "yellow"
})
fig 

plot_bgcolor:图形背景颜色,坐标轴围成的区域

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"plot_bgcolor": "#ACFFCF",  
                                        })
fig

如果和 template 搭配使用会是什么效果?

指定 template 为 "plotly_dark" 的时候会变成这样子,个人觉得不太行,你觉得呢?

showlegend:默认为 True,如果为 False,那么右上角的那个东东就不显示了,就是我们在轨迹中指定的 name

images:我个人觉得最牛的一个功能,就是可以将图片作为背景。

from PIL import Image
im = Image.open(r"C:\Users\satori\Desktop\bg\雾雨魔理沙.png")
random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100)
random_y2 = np.random.randn(100) - 5
trace0 = go.Scatter(
    x=random_x, 
    y=random_y0,  
    mode="markers",  
    name="markers"  
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
    mode="markers + lines", 
    name="markers + lines" 
)

trace2 = go.Scatter(
    x=random_x,  
    y=random_y2, 
    mode="lines",  
    name="lines"  
)
fig = go.Figure(data=[trace0, trace1, trace2], 
               layout={
                   "images": [
                       {"source": im,  
                        "sizex": 1, 
                        "sizey": 1, 
                        "yanchor": "bottom", 
                        "opacity": 0.3,  
                        }
                   ],

                   "width": im.width - 41,
                   "height": im.height,
                },

               )
fig

xaxis 和 yaxis:非常重要的属性,关键的东西我们留到最后。

xaxis 和 yaxis 支持的属性是一样,都是坐标轴,就一起说了。

anchor:锚点

autorange:自动范围

默认为 True,绘制的图表显示的坐标轴的范围会和数据集的范围大致匹配。

calendar:日历模式

color:颜色,针对于当前坐标轴的刻度

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"color": "red"}
                                              })
fig

dtick:坐标刻度的步进值

很重要的一个参数,我们说它描述的是坐标轴上坐标的紧密程度,一般会搭配 range 来使用。

range:坐标轴范围

如果是 m 到 n,那么就是"range": [m, n],再搭配 dtick,假设为 1。那么坐标轴就是 m、m+1、m+2、......、n,两者搭配可以对坐标轴刻度做任意的调整。

fixedrange:固定坐标轴范围

我们说交互式下绘制的图表的坐标轴只会显示和数据集接近的一部分,但是我们可以对坐标轴进行拖拽让它显示其它的部分,如果设置 fixedrange 为 False,那么就不可拖拽,默认是 True。

gridcolor:网格线颜色

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"gridcolor": "yellow"}
                                              })
fig

gridwidth:网格线宽度

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"gridwidth": 5, "gridcolor": "cyan"}
                                              })
fig

hoverformat:鼠标指针悬停格式

linecolor、linewidth:坐标轴线条颜色与宽度

这两个放在一起说,因为一起演示效果更明显。

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"linecolor": "yellow", "linewidth": 5}
                                              })
fig

nticks:坐标轴呈现多少个刻度

个人觉得和 dtick 有点重合,range 的范围再除以 dtick 就等同于 nticks。因此不指定步进值,也可以直接指定坐标轴上的刻度数。

rangeslider:范围滑块

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"rangeslider": {"bgcolor": "cyan"}}
                                              })
fig

下方有一个滑块,可以拖动,然后显示对应的图形部分。

showgrid:显示网格

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"showgrid": False},
                                               "yaxis": {"showgrid": False}
                                              })
fig

showline:显示线条开关

side:设置坐标轴刻度位置

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"side": "top"},
                                               "yaxis": {"side": "right"}
                                              })
fig

spikecolor:峰值数据颜色

tickangle:刻度角度,之前用过的。

tickangle:刻度角度,之前用过的。

tickprefix、ticksuffix:刻度前缀和后缀

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"tickprefix": "<<", "ticksuffix": ">>"},
                                              })
fig

title、titlefont:等价于 layout 中的 xaxis_title 或 yaxis_title、标题字体

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"title": "x轴描述", "titlefont": {"color": "cyan", "size": 30}},
                                              })
fig

type:刻度类型,可以是'-', 'linear', 'log', 'date', 'category',
'multicategory'之一

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"type": "category"}
                                              })
fig

zeroline:是否显示零线、就是值全部为 0 的线,对于 xaxis 就是 y 轴,对于 yaxis 就是 x 轴。

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"zeroline": False},
                                               "yaxis": {"zeroline": False},
                                              })
fig

zerolinecolor、zerolinewidth:零线的颜色和宽度

random_x = np.linspace(0, 2, 100)  
random_y0 = np.random.randn(100) + 5
random_y1 = np.random.randn(100) - 5

trace0 = go.Scatter(
    x=random_x,  
    y=random_y0, 
)

trace1 = go.Scatter(
    x=random_x,  
    y=random_y1, 
)

fig = go.Figure(data=[trace0, trace1], layout={"xaxis": {"zerolinecolor": "cyan", "zerolinewidth": 5},
                                               "yaxis": {"zerolinecolor": "pink", "zerolinewidth": 5},
                                              })
fig

保存图表

我们上面就介绍完了大部分内容,一些参数什么的,下面我们还需要将图表保存起来。

保存为 html

保存图表可以保存为 html,但是 html 显示的不是图片,而是 js 生成的可以动态交互的数据,所以保存的 html 会非常大,大概几 M。


fig.write_html("xxx.html")  

import plotly.io as pio
pio.write_html(fig, "xxx.html")

保存为 json

将图表保存为 json 的格式,里面主要是图表的核心数据。

fig.write_json("xxx.json")  

import plotly.io as pio
pio.write_json(fig, "xxx.json")

保存为图片

保存为图片应该是最常用的,因为很多时候我们绘制完图表之后需要展示在网页上或者做其它的什么事情,总是就是需要一个图片。

保存为图片稍微有点复杂,这也是没有放在第一个说的原因。因为保存为 html、json 直接保存即可,但是保存为图片不行,需要一个东西,叫 orca。估计很多小伙伴在保存为图片的时候都遇到这个问题:


fig.write_image("xxx.png")  

import plotly.io as pio
pio.write_image(fig, "xxx.png")

"""
...
...
...
If you haven't installed orca yet, you can do so using conda as follows:

    $ conda install -c plotly plotly-orca

Alternatively, see other installation methods in the orca project README at
https://github.com/plotly/orca

After installation is complete, no further configuration should be needed.

If you have installed orca, then for some reason plotly.py was unable to
locate it. In this case, set the `plotly.io.orca.config.executable`
property to the full path of your orca executable. For example:

    >>> plotly.io.orca.config.executable = '/path/to/orca'

After updating this executable property, try the export operation again.
If it is successful then you may want to save this configuration so that it
will be applied automatically in future sessions. You can do this as follows:

    >>> plotly.io.orca.config.save()

If you're still having trouble, feel free to ask for help on the forums at
https://community.plot.ly/c/api/python

"""

原因就在于你没有安装 orca,所以我们需要安装一下。

Windows 安装 orca

首先要pip3 install psutil requests,然后我们需要去https://github.com/plotly/orca/releases上面下载对应操作系统的 orca 安装文件,各种系统都有。我们需要下载 Windows 版本的 orca 安装文件,下载之后是一个 zip 包。解压即可,然后安装的 exe 文件就在里面,点击安装,然后将安装之后的目录添加到环境变量里面即可。但是我这里直接将安装文件和安装之后的目录提供给你们,可以直接从百度云下载即可。

下面的 orca.exe 就是安装的 exe 文件,上面的 orca 目录就是安装之后的结果,这两个东西的百度云链接如下,我也放在了一个 zip 包里面。

链接:https:
提取码:pi30 

下载下来之后解压,你可以点击 orca.exe 重新安装,也可以不用管那个 exe 文件,而是直接把上面 orca 目录设置到环境变量里面即可,因为 orca 就是 orca.exe 安装之后的目录,这两个东西我都提供了。个人建议直接把 orca 目录设置到环境变量里面就行,没必要再单独安装了。

就是这位老铁所在的目录,生成图片就全靠它了。

Linux 安装 orca

首先还是要pip3 install psutil requests安装这两个包,然后:


yum install fuse-libs-2.9.2-11.el7.x86_64
yum install gtk2-2.24.31-1.el7.x86_64
yum install desktop-file-utils 
yum install Xvfb
yum install xdg-utils-1.1.0-0.17.20120809git.el7.noarch

然后下载 orca,这个是绘制成图表所必须的


xvfb-run -a xxx.AppImage "$@"

mv xxx.AppImage orca

chmod 755 orca

Mac 安装 orca

mac 安装 orca,我没有试过,但是下载 mac 版本的 orca 还是去我们上面说的那个页面。具体怎么安装可以网上搜索,嘿嘿,让人怪不好意思的(手动表情包)

安装之后,我们就可以保存图片啦。另外除了 write_image,还有一个 to_image,这个不需要保存的文件名,而是调用之后直接返回图片的字节流,相当于使用 rb 模式对图片进行读取。比起图片本身,我们可能更常用字节流,直接渲染到页面上,或者生成 base64 字节。同理还有 to_html、to_json,可以自己尝试一下。另外:to_image 同样需要 orca,而 to_html 和 to_json 则不需要

真的是总结

plotly 真的是一个绘图神器,我们中间说的好多一些画布、坐标轴的属性,图表我们只介绍了几个基础的,里面的参数也只说了一部分。至于其它的图表可以去官网查看,支持很多的图表。加油,拥抱 plotly 吧。不过最让我满意的就是,居然可以嵌入图片作为背景。 https://www.cnblogs.com/traditional/p/12505154.html