鹤啸九天 自律更自由,平凡不平庸 Less is More

数据可视化-data-visualization

Notes(温馨提示):

  1. ★ 首次阅读建议浏览:导航指南, 或划到本页末尾, 或直接点击跳转, 查看全站导航图
  2. 右上角工具条搜索文章,右下角二维码关注微信公众号(鹤啸九天),底栏分享、赞赏、评论
  3. ★ 转载请注明文章来源,知识点积累起来不容易,水滴石穿,绳锯木断,谢谢理解
  4. ★ 如有疑问,邮件讨论,欢迎贡献优质资料


总结

  • 可视化方法
  • 【2020-8-7】Python数据可视化工具测评:5大工具谁是第一?
    • Matplotlib、Pyecharts、Seaborn、Plotly、Bokeh这五大工具
    • 评测维度
  • Seaborn和Plotly、bokeh有一个共同的地方就是虽然强大,但是网上有关这三个库的教程、讨论都远少于Pyecharts与Matplotlib
工具 得分 分布 示例
Pyecharts 85
Matplotlib 77
Plotly 76
Bokeh 71
Seaborn 72

可视化知识

什么场景用什么图

1.关联

  • 散点图
    • Scatteplot是用于研究两个变量之间关系的经典和基本图。如果数据中有多个组,则可能需要以不同颜色可视化每个组。在Matplotlib,你可以方便地使用。
  • 带边界的气泡图
    • 在边界内显示一组点以强调其重要性。在此示例中,从应该被环绕的数据帧中获取记录,并将其传递给下面的代码中描述的记录。encircle()
  • 带线性回归最佳拟合线的散点图
    • 了解两个变量如何相互改变
  • 抖动图
    • 通常多个数据点具有完全相同的X和Y值。结果多个点相互绘制并隐藏。为避免这种情况,请稍微抖动点,以便您可以直观地看到它们
  • 计数图
    • 避免点重叠问题的另一个选择是增加点的大小,这取决于该点中有多少点。因此,点的大小越大,周围的点的集中度就越大。
  • 边缘直方图
    • 边缘直方图具有沿X和Y轴变量的直方图。这用于可视化X和Y之间的关系以及单独的X和Y的单变量分布。该图如果经常用于探索性数据分析(EDA)
  • 边缘箱形图
    • 边缘箱图与边缘直方图具有相似的用途。然而,箱线图有助于精确定位X和Y的中位数,第25和第75百分位数。
  • 相关图
    • Correlogram用于直观地查看给定数据帧(或2D数组)中所有可能的数值变量对之间的相关度量。
# Import Dataset
df = pd.read_csv("https://github.com/selva86/datasets/raw/master/mtcars.csv")

# Plot
plt.figure(figsize=(12,10), dpi= 80)
sns.heatmap(df.corr(), xticklabels=df.corr().columns, yticklabels=df.corr().columns, cmap='RdYlGn', center=0, annot=True)

# Decorations
plt.title('Correlogram of mtcars', fontsize=22)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.show()
  • 矩阵图
    • 成对图是探索性分析中的最爱,以理解所有可能的数字变量对之间的关系。它是双变量分析的必备工具。
# Load Dataset
df = sns.load_dataset('iris')

# Plot
plt.figure(figsize=(10,8), dpi= 80)
sns.pairplot(df, kind="scatter", hue="species", plot_kws=dict(s=80, edgecolor="white", linewidth=2.5))
plt.show()

2.偏差

  • 发散型条形图
    • 想根据单个指标查看项目的变化情况,并可视化此差异的顺序和数量,那么发散条是一个很好的工具。它有助于快速区分数据中组的性能,并且非常直观,并且可以立即传达这一点。
  • 发散型文本
    • 分散的文本类似于发散条,如果你想以一种漂亮和可呈现的方式显示图表中每个项目的价值
  • 发散型包点图
    • 发散点图也类似于发散条。然而,与发散条相比,条的不存在减少了组之间的对比度和差异。
  • 带标记的发散型棒棒糖图
  • 面积图

3.排序

  • 有序条形图
  • 棒棒糖图
  • 包点图
  • 坡度图
    • 斜率图最适合比较给定人/项目的“之前”和“之后”位置。
  • 哑铃图

4.分布

  • 连续变量的直方图
    • 直方图显示给定变量的频率分布。下面的表示基于分类变量对频率条进行分组,从而更好地了解连续变量和串联变量
  • 类型变量的直方图
    • 分类变量的直方图显示该变量的频率分布。通过对条形图进行着色,您可以将分布与表示颜色的另一个分类变量相关联。
  • 密度图
    • 密度图是一种常用工具,可视化连续变量的分布。通过“响应”变量对它们进行分组,您可以检查X和Y之间的关系。以下情况,如果出于代表性目的来描述城市里程的分布如何随着汽缸数的变化而变化。
  • 直方密度线图
    • 带有直方图的密度曲线将两个图表传达的集体信息汇集在一起,这样您就可以将它们放在一个图形而不是两个图形中
  • Joy Plot
    • Joy Plot允许不同组的密度曲线重叠,这是一种可视化相对于彼此的大量组的分布的好方法。它看起来很悦目,并清楚地传达了正确的信息。它可以使用joypy基于的包来轻松构建matplotlib。
  • 分布式包点图
  • 包点+箱形图
  • Dot + Box Plot
  • 小提琴图
  • 人口金字塔
  • 分类图

5.组成

  • 华夫饼图
  • 饼图
  • 树形图
  • 条形图

6.变化

  • 时间序列图
  • 带波峰波谷标记的时序图
  • 自相关和部分自相关图
  • 交叉相关图
  • 时间序列分解图
  • 多个时间序列
  • 使用辅助Y轴来绘制不同范围的图形
  • 带有误差带的时间序列
  • 堆积面积图
  • 未堆积的面积图
  • 日历热力图
  • 季节图

7.分组

  • 树状图
  • 簇状图
  • 安德鲁斯曲线
  • 平行坐标

可视化工具

方案有如下可选型:

  • 一、传统的matplotlibicon,seaborn,绘制的是静态图。
  • 二、pyecharts,plotly,使用纯python代码,但生成的是htmlicon,可以缩放之类的。
  • 三、bokeh,plotly+dash,交互式的,有相应的控件。也是使用python的方式,生成html。
  • 四、streamlit。
  • dataprep:一次性EDA工具

自动生成分析报告

【2022-1-25】5个方便好用的Python自动化脚本

可视化一般会用pandas、matplotlib等工具来探索数据,但需要自己编写大量代码,如果想提高效率,Dtale是个不错的选择。

  • Dtale特点是用一行代码生成自动化分析报告,它结合了Flask后端和React前端,提供了一种查看和分析Pandas数据结构的简便方法。
  • 可以在Jupyter上实用Dtale。

需要的第三方库:

  • Dtale - 自动生成分析报告
### Importing Seaborn Library For Some Datasets
import seaborn as sns
### Printing Inbuilt Datasets of Seaborn Library
print(sns.get_dataset_names())
### Loading Titanic Dataset
df=sns.load_dataset('titanic')
### Importing The Library
import dtale
#### Generating Quick Summary
dtale.show(df)

效果:

Notebook

dataprep

dataprep EDA 工具,直接展示 各个属性取值、相关性、热力图等信息

安装 dataprep 工具包

pip install -U dataprep

以官方数据集为例,做EDA分析

from dataprep.datasets import load_dataset
from dataprep.eda import create_report
from dataprep.eda import plot, plot_correlation, plot_missing

# 内置数据集信息
from dataprep.datasets import get_dataset_names
get_dataset_names()
# ['covid19',
#  'wine-quality-red',
#  'iris',
#  'waste_hauler',
#  'countries',
#  'patient_info',
#  'house_prices_train',
#  'adult',
#  'house_prices_test',
#  'titanic']

# 加载内置数据集
df = load_dataset("adult") # 
df = load_dataset("titanic") # 泰坦尼克数据集
# 属性取值分析
from dataprep.eda import plot
plot(df) # 所有属性取值分布(柱状图)
plot(df, 'queryChanging') # 单个属性取值分布,额外新增饼图、词云、词长
# 相关性分析: 显示3种相关性结果
from dataprep.eda import plot_correlation
plot_correlation(df)
# 计算相关性, 输出到文件
from dataprep.eda import compute_correlation
from dataprep.datasets import load_dataset
df = load_dataset("titanic")
imdt = compute_correlation(df)
imdt.save("imdt.json")
imdt
# 缺失值分析
from dataprep.eda import plot_missing
plot_missing(df)
# 多数据集对比分析: 各数据集格式相同
from dataprep.eda import plot_diff
from dataprep.datasets import load_dataset
df1 = load_dataset("house_prices_test")
df2 = load_dataset("house_prices_train")
plot_diff([df1, df2])
# 创建报表: 汇总分析结果,点击单个属性的详情(detail)就会出现各种类型的图表
r = create_report(df)
r = create_report(df, title='泰坦尼克分析报告')
r # 在 notebook 中展示
r.show_browser() # 浏览器页面
r.save(filename='report', to='~/Desktop') # 保存为本地文件
# 部分显示
plot(df) # 变量可视化
plot_correlation(df) # 不同类型相关图

# ---- 定制报表 -----
from dataprep.eda import plot,create_report
from dataprep.datasets import load_dataset
df = load_dataset('titanic')
# 显示指定tab页: display 参数
plot(df, 'Pclass', display=['Stats', 'Bar Chart', 'Pie Chart'])
plot(df, display=["Stats", "Insights"])
# 指定tab页
create_report(df,display=["Overview","Interactions"])
# 定制图标属性: config 参数
plot(df, "Pclass", config={'bar.bars': 10, 'bar.sort_descending': True, 'bar.yscale': 'linear', 'height': 400, 'width': 450, })
plot(df,config={'insight.missing.threshold':20, 'insight.duplicates.threshold':20})

Facet Dive

【2017-7-30】Google开发的数据可视化web工具Facet Dive

【2018-3-13】可以嵌入jupyter notebook做特征工程可视化分析, 安装方法参考PAIR-CODE,Google AI

【2018-9-11】集成到tensorboard工具中:what-if

【2020-1-8】北京大学高维数据可视化

  • facets

Bamboolib

媲美 Jupyter Notebook 的交互式数据分析库:Bamboolib(数据可视化篇)

  • 无需写代码
pip install bamboolib
#pip install --upgrade bamboolib --user

使用方法

import bamboolib as bam
# Type bam > Read CSV file > Navigate to your file > Choose the file name > Open CSV file
bam # type

PyGWalker

【2024-10-6】PyGWalker 将 pandas DataFrame 数据交互可视化

安装

pip install pygwalker --upgrade

示例

import pygwalker as pyg
import pandas as pd

df = pd.read_csv("data.csv")

pyg.walk(df)

DM软件

Weka

【2018-6-15】数据挖掘软件:

  • weka适用于EDA探索性数据分析

Orange

  • Orange数据挖掘和机器学习软件

OLAP工具

SAIKU

地图数据可视化

BI

Tableau

TabPy(Tableau Python Server)是一种分析扩展实现,允许用户通过 Tableau 表计算执行Python脚本和保存的函数,从而扩展了Tableau的功能。

通过使用与Python编程集成的Tableau,可以创建多个动态的高级报告,并为ML集成做好准备。

好处是:

  • 高级分析
  • 机器学习就绪仪表板
  • 高级计算
  • 有效的探索性数据分析

安装

pip install tabpy==2.3.1
tabpy # 链接服务器

服务地址

本地 Tableau 软件

  • ”Help” -> “Settings and Performance” -> “Manage External Service Connectiontableau”在tableau中连接tabpy。
  • 端口号指定 9004 并登录。
  • 用户可以选中”Require SSL”复选框以加密通过网络发送的数据。
  • 最后,点击”Test Connection”,将显示后续连接成功。

Matplotlib

  • Python 有非常丰富的第三方绘图库,matplotlib 使用起来也许并不是很便捷,因为图上每个元素都需要自己来定制。但仔细体会 matplotlib 背后的设计思想是很有趣的事情。seaborn 之类的绘图库是基于 matplotlib 封装的,因而后期需要自己灵活定制图形时就大大受用了。本文的两幅思维导图是基于两种不同的思路绘制的,偶有内容交叉,日常使用可以选择自己熟悉的方式(网上的教程大多是基于过程的函数式编程,即 pyplot 方法)。建议配合最后附上出的参考资料学习

Reference

《Python for data analysis》
Matplotlib: Python plotting — Matplotlib 2.0.2 documentation
绘图: matplotlib核心剖析
【数据可视化】 之 Matplotlib
Python–matplotlib绘图可视化知识点整理
一份非常好的Matplotlib 教程

  • 绘制热力图
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

# 这里是创建一个数据
vegetables = ["cucumber", "tomato", "lettuce", "asparagus",
              "potato", "wheat", "barley"]
farmers = ["Farmer Joe", "Upland Bros.", "Smith Gardening",
           "Agrifun", "Organiculture", "BioGoods Ltd.", "Cornylee Corp."]

harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                    [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                    [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                    [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                    [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                    [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                    [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])

# 这里是创建一个画布
fig, ax = plt.subplots()
im = ax.imshow(harvest)

# 这里是修改标签
# We want to show all ticks...
ax.set_xticks(np.arange(len(farmers)))
ax.set_yticks(np.arange(len(vegetables)))
# ... and label them with the respective list entries
ax.set_xticklabels(farmers)
ax.set_yticklabels(vegetables)

# 因为x轴的标签太长了,需要旋转一下,更加好看
# Rotate the tick labels and set their alignment.
plt.setp(ax.get_xticklabels(), rotation=45, ha="right",
         rotation_mode="anchor")

# 添加每个热力块的具体数值
# Loop over data dimensions and create text annotations.
for i in range(len(vegetables)):
    for j in range(len(farmers)):
        text = ax.text(j, i, harvest[i, j],
                       ha="center", va="center", color="w")
ax.set_title("Harvest of local farmers (in tons/year)")
fig.tight_layout()
plt.colorbar(im)
plt.show()

from matplotlib import pyplot as plt
from matplotlib import cm as cm

def correlation_matrix(df):
    fig = plt.figure(figsize=(50,30))
    ax1 = fig.add_subplot(111)
    ax1.set_title('intent translate map',fontsize=40,color='b')
    cmap = cm.get_cmap('jet', 30) 
    cax = ax1.imshow(df.corr(), interpolation="nearest", cmap=cmap)
    ax1.grid(True)
    #plt.title('Abalone Feature Correlation') 
    labels_x = df.index
    labels_y = df.columns
    #labels=['Sex','Length','Diam','Height','Whole','Shucked','Viscera','Shell','Rings',]
    ax1.set_xticklabels(labels_x,fontsize=20)
    ax1.set_yticklabels(labels_y,fontsize=20)
    # Add colorbar, make sure to specify tick locations to match desired ticklabels
    fig.colorbar(cax, ticks=[.75,.8,.85,.90,.95,1])
    plt.show()

correlation_matrix(df)

turtle

import turtle

turtle.shape('turtle')
turtle.speed(9)            # 画笔速度
turtle.pensize(2)			# 画笔的宽度
turtle.bgcolor("black")		# 画布背景色
colors = ["red","yellow","green","blue"]	# 定义画笔线色

for i in range(255):		# 循环一次 画一条线
    turtle.forward(2 * i) 	        # 向当前方向前进n像素
    turtle.color(colors[i % 4])	# 根据求余 调整画笔线色
    turtle.left(91)                # 向左旋转91度

turtle.done()

streamlit

使用Streamlit快速搭建数据科学Web App

Streamlit简介

Streamlit 是 Python 的一个用于创建 Web App 的框架,类似于 R 的 Shiny。其功能虽不如 R Shiny 强大,更不如专门的 Python Web 框架如 Flask、Djiango 等强大,但其使用非常直观和简单,不需要过多的 Web 知识。如果之前用过 Markdown 或 Jupyter Notebook 等,便能快速上手,创建自己的 Web App。

Streamlit 的使用场景,如:

  • 研究开发了一个临床预测模型,使用 Streamlit 将该预测模型搭建在网站上随论文发表或供别人体检。
  • 公司某部门人员需要批量处理 Excel 文件,因而可以写一个 python 脚本自动化处理;但部门人员并不会用 python、也未安装 python 环境,此时便可将该脚本使用 Streamlit 部署成 Web App,部门人员使用时只需点击上传 Excel 文件,然后点击下载处理完成的文件即可。

Streamlit 安装

Streamlit 安装

pip install streamlit # 安装
streamlit hello # 创建本地app

命令行中运行:streamlit hello,便可创建一个本地的 Web App,点击 URL 地址(http://localhost:8502)在浏览器打开

Streamlit 自定义app

Streamlit 写 App 就是创建一个 py 文件,而不需要分别创建前端和后端。

import streamlit as st
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 展示文本;文本直接使用Markdown语法
st.markdown("# Streamlit示例")
st.markdown("""
            - 这是
            - 一个
            - 无序列表
            """)

# 展示pandas数据框
st.dataframe(pd.DataFrame([[1, 2], [3, 4]], columns=["a", "b"]))

# 展示matplotlib绘图
arr = np.random.normal(1, 1, size=100)
plt.hist(arr, bins=20)
plt.title("matplotlib plot")
st.pyplot()

# 加入交互控件,如输入框
number = st.number_input("Insert a number", 123)
st.write("输入的数字是:", number)

该 py 文件放在某文件夹下,cmd 中 cd 到该文件夹

  • 输入命令
streamlit run example.py # 执行
streamlit run example.py --server.port 80 # 指定 App 在 80 端口运行
  • 点击出现的 URL 后可见界面:

上述方式将 App 搭建在本地机上,如果想将 App 供别人访问,则需将 App 搭建在服务器如阿里云服务器或者部署在托管网站如 heroku 再或者使用内网穿透软件如 花生壳。

Streamlit 语法

Streamlit 主要用法总结

import streamlit as st
import pandas as pd
import numpy as np
import time
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.figure_factory as ff
import altair as alt
from PIL import Image
import base64

文字、公式

对照输出查看显示效果

st.title("st.title")
st.header("st.header")
st.subheader("st.subheader")

st.markdown("# markdown一级标题")
st.markdown("## markdown二级标题")
st.markdown("### markdown三级标题")
# ------------------------------------
st.write("st.write")
st.markdown("markdown普通文字")
st.text("st.text")
# ------------------------------------
st.markdown("""
Markdown列表:
- hello 
- world
- China
""")
st.markdown("***markdown粗斜体***")
# ------------------------------------
st.latex("\sum_{i=1}^{n}")
# ------------------------------------

st.write(1234)
st.write("1234")
st.write("1 + 1 = ", 2)

st.write()

st.write () 是一个泛型函数,根据传入对象不同采取不同的展示方式,比如传入 pandas.DataFrame 时,st.write (df) 默认调用 st.dataframe (),传入 markdown 时,st.write (markdown) 默认调用 st.markdown ();跟 R 的泛型函数非常类似。可传入的对象有:

  • write(data_frame) : Displays the DataFrame as a table.
  • write(func) : Displays information about a function.
  • write(module) : Displays information about the module.
  • write(dict) : Displays dict in an interactive widget.
  • write(obj) : The default is to print str(obj).
  • write(mpl_fig) : Displays a Matplotlib figure.
  • write(altair) : Displays an Altair chart.
  • write(keras) : Displays a Keras model.
  • write(graphviz) : Displays a Graphviz graph.
  • write(plotly_fig) : Displays a Plotly figure.
  • write(bokeh_fig) : Displays a Bokeh figure.
  • write(sympy_expr) : Prints SymPy expression using LaTeX.
  • write(markdown):
# 字典
st.write({"a": [1, 2, 3], 
          "b": [2, 3, 4]})

# pandas数据框
st.write(pd.DataFrame({
    "a": [1, 2, 3, 4, 5],
    "b": [4, 5, 6, 7, 8]
}))

# Markdown文字
st.write("Hello, *World!* :sunglasses:")

# 绘图对象
df = pd.DataFrame(
    np.random.randn(200, 3),
    columns=["a", "b", "c"]
)

c = alt.Chart(df).mark_circle().encode(
    x="a", y="b", size="c", color="c", tooltip=["a", "b", "c"])
st.write(c)

表格

两种表格,动态表格和静态表格

# 动态表格(表格太大时只展示一部分,可滑动表格下方滑动条查看不同部分)
# st.write默认调用st.dataframe()
df = pd.DataFrame(
    np.random.randn(10, 20),
    columns=('col %d' % i for i in range(20)))
st.write(df)

# 静态表格(展示表格全部内容,太大时滑动App界面下方的滑动条查看不同部分)
df = pd.DataFrame({
    "a": [1, 2, 3, 4, 5],
    "b": [4, 5, 6, 7, 8]
})
st.table(df)
# pandas.DataFrame 的 style 也可正常显示
df = pd.DataFrame(
    np.random.randn(10, 20),
    columns=('col %d' % i for i in range(20)))

st.dataframe(df.style.highlight_max(axis=0))

动态扩增表格或动态绘图

  • 表格、图片可以使用 add_rows() 方法添加新数据
df1 = pd.DataFrame(
    np.random.randn(5, 5),
    columns=("col %d" % i for i in range(5))
)
tb_table = st.table(df1)

for i in range(10):
    df2 = pd.DataFrame(
        np.random.randn(1, 5),
        columns=("col %d" % i for i in range(5))
    )
    tb_table.add_rows(df2)
    time.sleep(0.5)

Code

仅展示 Code,Code 不执行

code = """
def sum_(x):
    return np.sum(x)
"""
st.code(code, language="python")

code = """
for (i i 1:10) {
    print(i)
}
"""
st.code(code, language="r")

st.markdown("""
​```python
print("hello")
""")

展示 Code,同时执行 Code;需要将 code 放入 st.echo() 内

with st.echo():
    for i in range(5):
        st.write("hello")

各种控件

# 数字输入框
number = st.number_input("Insert a number", 123)
# 单行文本输入框
word = st.text_input("Insert a word", "123")
st.write("The number is", number, "The word is", word)
# 多行文本输入框
st.text_area("Text to analyze", "I love China")
# 日期输入框
st.date_input("Insert a date")
# 时间输入框
st.time_input("Insert a time")
# 点击按钮
number = st.button("click it")
st.write("返回值:", number)
# 滑动条
x = st.slider("Square", min_value=0, max_value=80)
st.write(x, "squared is", np.power(x, 2))
# 检查框
res = st.checkbox("I agree")
st.write(res)
# 单选框
st.selectbox("Which would you like", [1, 2, 3])
# 单选按钮
st.radio("Which would you like", [1, 2, 3])
# 多选框
selector = st.multiselect("Which would you like", [1, 2, 3])
st.write(selector)

上传 csv 文件

uploaded_file = st.file_uploader("Choose a CSV file", type="csv")

if uploaded_file is not None:
    data = pd.read_csv(uploaded_file)
    st.write(data)

下载:

  • 目前 Streamlit 还没有专门的下载控件,下载 pandas Dataframe 为 csv 文件可通过以下方式实现
  • 点击 Download CSV File 便可下载文件
data = [(1, 2, 3)]
df = pd.DataFrame(data, columns=["Col1", "Col2", "Col3"])
csv = df.to_csv(index=False)

b64 = base64.b64encode(csv.encode()).decode()
href = f'<a href="data:file/csv;base64,{b64}">Download CSV File</a> (right-click and save as &lt;some_name&gt;.csv)'
st.markdown(href, unsafe_allow_html=True)

侧边栏控件

以上控件大部分都有对应的侧边栏形式,如上述 st.selectbox 若想放置在侧边栏,可使用 st.sidebar.selectbox

# 单选框
st.sidebar.selectbox("Which would you like", [1, 2, 3], key="1")

# 单选按钮
st.sidebar.radio("Which would you like", [1, 2, 3], key="1")

# 多选框
selector = st.sidebar.multiselect("Which would you like", [1, 2, 3], key="3")
st.write(selector)

绘图、图片、音频、视频

支持的绘图库:

  • streamlit 自带绘图:st.line_chart()、bar_chart() 等
  • matplotlib 或 seaborn:st.pyplot()
  • altair:st.altair_chart()
  • vega: st.vega_lite_chart()
  • plotly: st.plotly_chart()
  • bokeh: st.bokeh_chart()

streamlit 自带绘图

  • st.line_chart() 和 st.bar_chart()
st.line_chart(np.random.randn(10, 2))

chart_data = pd.DataFrame(
    np.random.randn(50, 3),
    columns=["a", "b", "c"]
)
st.bar_chart(chart_data)

matplotlib 或 seaborn 绘图

st.markdown("# matplotlib绘图")

arr = np.random.normal(1, 1, size=100)
plt.hist(arr, bins=20)
st.pyplot()

st.markdown("# seaborn绘图")

tips = sns.load_dataset("tips")
sns.set(style="darkgrid")
sns.scatterplot(x="total_bill", y="tip", hue="smoker", data=tips)
st.pyplot()

地图

# 绘制1000个点的坐标
map_data = pd.DataFrame(
    np.random.randn(1000, 2) / [50, 50] + [37.76, -122.4],
    columns=['lat', 'lon'])

st.map(map_data)

展示图片、音频、视频

  • 图片:st.image ()
  • 音频:st.audio ()
  • 视频:st.video ()

状态

st.error("错误显示为")
st.warning("警告显示为")
st.info("普通消息显示为")
st.success("成功消息显示为")

进度条

# 添加占位符
placeholder = st.empty()
# 创建进度条
bar = st.progress(0)

for i in range(100):
    time.sleep(0.05)
    # 不断更新占位符的内容
    placeholder.text(f"Iteration {i+1}")
    # 不断更新进度条
    bar.progress(i + 1)

# 状态
st.success("Finished")

等待条

with st.spinner("Wait for it..."): 
    for i in range(100):
        print("hello")
        time.sleep(0.05)

st.success("Done!")

seaborn

  • 建立在matplotlib上
  • Seaborn的heatmap参数介绍
    • data:矩阵数据集,可以使numpy的数组(array),如果是pandas的dataframe,则df的index/column信息会分别对应到heatmap的columns和rows
    • linewidths,热力图矩阵之间的间隔大小
    • vmax,vmin, 图例中最大值和最小值的显示值,没有该参数时默认不显示
    • cmap:matplotlib的colormap名称或颜色对象;如果没有提供,默认为cubehelix map (数据集为连续数据集时) 或 RdBu_r (数据集为离散数据集时)
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
import random

np.random.seed(1)
data = np.random.rand(16, 16)

sns.set()
ax = sns.heatmap(data, center=0)
#plt.savefig('res.png', dpi=300)
plt.show()

f, (ax1,ax2) = plt.subplots(figsize = (10, 8),nrows=2)
# cubehelix map颜色
cmap = sns.cubehelix_palette(start = 1.5, rot = 3, gamma=0.8, as_cmap = True)
sns.heatmap(pt, linewidths = 0.05, ax = ax1, vmax=15000, vmin=0, cmap=cmap)
ax1.set_title('cubehelix map')
ax1.set_xlabel('')
ax1.set_xticklabels([]) #设置x轴图例为空值
ax1.set_ylabel('kind')
# matplotlib colormap
sns.heatmap(pt, linewidths = 0.05, ax = ax2, vmax=15000, vmin=0, cmap='rainbow') 
# rainbow为 matplotlib 的colormap名称
ax2.set_title('matplotlib colormap')
ax2.set_xlabel('region')
ax2.set_ylabel('kind')
f.savefig('sns_heatmap_cmap.jpg', bbox_inches='tight')

# 加数值标注
np.random.seed(0)
x = np.random.randn(10, 10)
f, (ax1, ax2) = plt.subplots(figsize=(8,8),nrows=2)
sns.heatmap(x, annot=True, ax=ax1)
sns.heatmap(x, annot=True, fmt='.1f', ax=ax2)
f.savefig('sns_heatmap_fmt.jpg')

pyecharts

简介

Echarts是一个由百度开源的数据可视化工具,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可。pyecharts是一个全新的可视化绘图工具,因此它的绘图逻辑完全不同于前面说到的matplotlib、seaborn、plotly。

版本

  • 【2020-12-08】pyecharts分为v0.5和v1两个大版本,v0.5和v1两个版本不兼容,风格迥异,v1是一个全新的版本。旧版基本放弃。
  • 查看版本:print(pyecharts.version)
  • 旧版是过程式调用,新版是链式调用

安装

命令:

pip install pyecharts
# 如果需要绘制地图,下列地图数据包需要安装
pip install echarts-countries-pypkg
pip install echarts-china-provinces-pypkg
pip install echarts-china-cities-pypkg
pip install echarts-china-counties-pypkg
pip install echarts-china-misc-pypkg

注意:

  • 在使用 Pandas&Numpy 时,请确保将数值类型转换为 python 原生的 int/float。比如整数类型请确保为 int,而不是 numpy.int32

效果展示

echarts效果大全

基础知识

【干货分享】pyecharts的绘图原理详解

pyecharts的绘图逻辑分为以下几步。

  • ① 选择图表类型;散点、折线、饼图以及地图等
    • from pyecharts.charts import Scatter
    • 常见图表类型
  • ② 声明图形类并添加数据;每一个图形库都是被pyecharts作者封装成为了一个,即面向对象,用类时,需要实例化这个类。声明类之后,相当于初始化了一个画布,之后的绘图就是在这个画布上进行。接下来要做的就是添加数据,pyecharts中添加数据共有2种方式,一种是普通的过程式添加数据,一种是链式调用(观察下面代码)来添加数据
    • 散点图、折线图等二维数据图形,它既有X轴,又有Y轴,两个轴都要添加
      • .add_xaxis(xaxis_data=x)为X轴添加数据;
      • .add_yaxis(series_name=’’, y_axis=y)为Y轴添加数据;series_name参数必须有,添加的数据标题
    • 饼图、地图没有X轴、Y轴区分的图形,直接使用add()方法添加即可
      • .add(series_name=’’, data_pair=[(i,j)for i,j in zip(lab,num)]);
  • ③ 选择全局变量;调节各种各样的参数,把图形变得更好看. 常用的有: 图片总结
    • 标题配置项: TitleOpts
    • 图例配置项: LegendOpts
    • 工具配置项: ToolboxOpts
    • 视觉映射配置项: VisualMapOpts
    • 提示框配置项: TooltipOpts
    • 区域缩放配置项: DataZoomOpts
    • 还有初始化画布大小:InitOpts,示例:
      • import pyecharts.options as opts
      • pie = Pie(init_opts=opts.InitOpts(width=”700px”,height=”300px”))
  • 显示及保存图表;
    • render(‘a.html’) # html格式展示,链接分享
    • render_notebook() # 渲染到jupyter notebook
# 1.选择图表类型:我们使用的是散点图,就直接从charts模块中导入Scatter这个图形。  
from pyecharts.charts import Scatter  
import numpy as np  

x = np.linspace(0,2 * np.pi,100)  
y = np.sin(x)  

(  
    # 注意:使用什么图形,就要实例化该图形的类;  
    # 2.我们绘制的是Scatter散点图,就需要实例化散点图类,直接Scatter() 即可;  
    Scatter()   
    # 实例化类后,接着就是添加数据,下面这种方式就是使用“链式调用”的方式绘图;  
    # 注意:散点图有X、Y轴,因此需要分别给X轴、Y轴添加数据;  
    # 3.我们先给X轴添加数据;  
    .add_xaxis(xaxis_data=x)  
    # 4.我们再给Y轴添加数据;  
    .add_yaxis(series_name="这个图是干嘛的",y_axis=y)  
).render_notebook()  

画布型号——版面

代码

from pyecharts.charts import Bar
from pyecharts import options as opts

bar = (
    Bar(init_opts=opts.InitOpts(width="1700px",
                                height="750px",
                                page_title="画布大小设置"))
    .add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
    .add_yaxis("商家B", [15, 6, 45, 20, 35, 66])
    .set_global_opts(title_opts=opts.TitleOpts(title="商家销售汇总",subtitle="分类汇总"))
    #.set_global_opts(title_opts=opts.TitleOpts(title="主标题", subtitle="副标题"))
)
bar.render("123.html")

画布主题——版面/标题

代码: 主题效果大全

  • Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
from pyecharts.charts import Bar
from pyecharts import options as opts
# 内置主题类型可查看 pyecharts.globals.ThemeType
from pyecharts.globals import ThemeType


bar = (
    Bar(init_opts=opts.InitOpts(width="1700px",
                                height="750px",
                                page_title="画布设置",
                                theme=ThemeType.DARK))
    .add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
    .add_yaxis("商家B", [15, 6, 45, 20, 35, 66])
    .set_global_opts(title_opts=opts.TitleOpts(title="商家销售汇总",subtitle="分类汇总"))
    #.set_global_opts(title_opts=opts.TitleOpts(title="主标题", subtitle="副标题"))
)
bar.render("123.html")

坐标轴设置

pyecharts1.7 坐标轴设置:X轴、Y轴通用

type_ :坐标轴类型, 可选:

  • ‘value’ 数值轴,适用于连续数据。
  • ‘category’ 类目轴,适用于离散的类目数据
  • ‘time’ 时间轴,适用于连续的时序数据,与数值轴相比时间轴带有时间的格式化,在刻度计算上也有所不同,例如会根据跨度的范围来决定使用月,星期,日还是小时范围的刻度。
  • ‘log’ 对数轴。适用于对数数据。
from random import randint

from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.commons.utils import JsCode

x_data = ['分类1','分类2','分类3','分类4','分类5',]
y1_data = [0.72,0.61,0.98,0.92,0.67,]
y2_data = [d * randint(1, 10) for d in y1_data]

instance_bar = (
    Bar()
        .add_xaxis(xaxis_data=x_data)
        .add_yaxis(series_name='系列1', yaxis_data=y1_data)
        .add_yaxis(series_name='系列2', yaxis_data=y2_data)
        .set_global_opts( # 全局设置
        xaxis_opts=opts.AxisOpts( # (1)x轴设置
            type_='category',  # value数值轴,category类目轴,time时间轴,log对数轴
            name='x名称',  # Optional[str]
            is_show=True,  # bool, 是否显示坐标轴
            is_scale=False,  # bool,坐标刻度是否包含零刻度,只在数值轴中(type: ‘value’)有效。设置成 true 后坐标刻度不会强制包含零刻度。在双数值轴的散点图中比较有用。在设置 min 和 max 之后该配置项无效
            is_inverse=True,  # bool,是否是反向坐标轴
            name_location='start',  # str,坐标轴名称显示位置,'start','middle'/'center','end'
            name_gap=15,  # Numeric,坐标轴名称与轴线之间的距离
            name_rotate=20,  # Optional[Numeric],坐标轴名字旋转,角度值
            name_textstyle_opts=opts.TextStyleOpts( # (2)坐标轴名称的文字样式
                color='blue',  # 颜色
                font_style=None,  # 字体,可选:‘normal’,‘italic’,‘oblique’
                font_weight=None,  # 粗细,可选:‘normal’,‘bold’,‘bolder’,‘lighter’
                font_family=None,  # 字体, ‘serif’ , ‘monospace’, ‘Arial’, ‘Courier New’, ‘Microsoft YaHei’, …
                font_size=None,  # 字体大小
                align=None,  # 水平对齐方式,默认自动
                vertical_align=None,  # 垂直对齐方式,默认自动
                line_height=None,  # 行高
                background_color='yellow',  # 文字块背景色。可以是直接的颜色值,例如:’#123234’, ‘red’, ‘rgba(0,23,11,0.3)’
                border_color=None,  # 文字块边框颜色
                border_width=None,  # 文字块边框高度
                border_radius=None,  # 文字块的圆角
                padding=None,  # Union[Numeric, Sequence, None],文字块的内边距。例:padding: [3, 4, 5, 6]:表示 [上, 右, 下, 左] 的边距,padding: 4:表示 padding: [4, 4, 4, 4],padding: [3, 4]:表示 padding: [3, 4, 3, 4]
                shadow_color=None,  # 文字块的背景阴影颜色
                shadow_blur=None,  # 文字块的背景阴影长度
                width=None,  # 文字块的宽度
                height=None,  # 文字块的高度
                rich=None,  # Optional[dict],自定义富文本样式
            ),
            interval=30,  # Optional[Numeric],坐标轴间隔,强制设置坐标轴分割间隔。无法在类目轴中使用。在时间轴(type: ‘time’)中需要传时间戳,在对数轴(type: ‘log’)中需要传指数值
            grid_index=0,  # Numeric,坐标轴所在的 grid 的索引,默认位于第一个 grid
            position='',  # Optional[str],坐标轴位置可选:'top','bottom',默认 grid 中的第一个 x 轴在 grid 的下方('bottom'),第二个 x 轴视第一个 x 轴的位置放在另一侧
            offset=0,  # Numeric,坐标轴偏移,X 轴相对于默认位置的偏移,在相同的 position 上有多个 X 轴的时候有用
            split_number=5,  # Numeric,坐标轴的分割段数,需要注意的是这个分割段数只是个预估值,最后实际显示的段数会在这个基础上根据分割后坐标轴刻度显示的易读程度作调整。在类目轴中无效。
            boundary_gap='',  # Union[str, bool, None],坐标轴两边留白策略。类目轴和非类目轴的设置和表现不一样。类目轴中 boundaryGap 可以配置为 true 和 false。默认为 true,这时候刻度只是作为分隔线,标签和数据点都会在两个刻度之间的带(band)中间。非类目轴,包括时间,数值,对数轴,boundaryGap是一个两个值的数组,分别表示数据最小值和最大值的延伸范围,可以直接设置数值或者相对的百分比,在设置 min 和 max 后无效。boundaryGap: [‘20%’, ‘20%’]
            min_='',  # Union[Numeric, str, None],坐标轴最小值
            max_='',  # Union[Numeric, str, None],坐标轴最大值
            min_interval=0,  # Numeric,坐标轴最小间隔,自动计算的坐标轴最小间隔大小。例如可以设置成1保证坐标轴分割刻度显示成整数。只在数值轴或时间轴中(type: ‘value’ 或 ‘time’)有效。
            max_interval=0,  # Optional[Numeric] ,坐标轴最大间隔,自动计算的坐标轴最大间隔大小。例如,在时间轴((type: ‘time’))可以设置成 3600 * 24 * 1000 保证坐标轴分割刻度最大为一天。只在数值轴或时间轴中(type: ‘value’ 或 ‘time’)有效。
            axisline_opts=opts.AxisLineOpts( # (3)坐标轴轴线相关设置
                is_show=True, # 是否显示坐标轴轴线。
                is_on_zero=True, # X 轴或Y 轴的轴线是否在另一个轴的 0 刻度上,只有在另一个轴为数值轴且包含 0 刻度时有效。
                on_zero_axis_index=0,
                symbol=None,
                linestyle_opts=opts.LineStyleOpts( # 坐标轴线风格配置项
                    is_show=True,
                    width=1,
                    opacity=1,
                    curve=0,
                    type_="solid",
                    color=None,
                )
            ),
            axistick_opts=opts.AxisTickOpts( # (4)坐标轴刻度相关设置
                is_show=True,
                is_align_with_label=True,
                is_inside=True,
                length=20,
                linestyle_opts=opts.LineStyleOpts(
                    is_show=True,
                    width=1,
                    opacity=1,
                    curve=0,
                    type_="solid",
                    color=None,
                )
            ),
            axislabel_opts=opts.LabelOpts(
                is_show=True,  # bool
                position="top",  # Union[str, Sequence]
                color='pink',  # Optional[str]
                font_size=None,  # Optional[Numeric]
                font_style=None,  # Optional[str]
                font_weight=None,  # Optional[str]
                font_family=None,  # Optional[str]
                rotate=10,  # Optional[Numeric]
                margin=8,  # Optional[Numeric]\,
                interval=None,  # Union[Numeric, str, None]
                horizontal_align=None,  # Optional[str]
                vertical_align=None,  # Optional[str]
                formatter=JsCode("""
                function(value,index) {
                  if (index === 2) {
                    return 'formatter';
                  } else {
                    return value;
                  }
                }
                """),  # Optional[JSFunc] 回调函数
                # 字符串模板 formatter='-{value}-',
                background_color=None,  # Optional[str]
                border_color=None,  # Optional[str]
                border_width=None,  # Optional[Numeric]
                border_radius=None,  # Optional[Numeric]
                rich=None,  # Optional[dict]
            ),
            axispointer_opts=opts.AxisPointerOpts( # 坐标轴指示器设置
                is_show=True,
                link=None,
                type_="line",
                label=None,
                linestyle_opts=opts.LineStyleOpts(
                    is_show=True,
                    width=10,
                    opacity=0.5,
                    curve=0,
                    type_="solid",
                    color='green',
                ),
            ),
            splitarea_opts=opts.SplitAreaOpts( # 坐标轴在 grid 区域中的分隔区域设置
                is_show=True,
                areastyle_opts=opts.AreaStyleOpts(
                    opacity=0.05,
                    color={
                        'type': 'linear',
                        'x': 0,
                        'y': 0,
                        'x2': 0,
                        'y2': 1,
                        'colorStops': [{
                            'offset': 0, 'color': 'red'  # 0% 处的颜色
                        }, {
                            'offset': 1, 'color': 'blue'  # 100% 处的颜色
                        }],
                        'global': False  # 缺省为 false
                    }
                )

            ),
            splitline_opts=opts.SplitLineOpts( # 坐标轴在 grid 区域中的分隔线设置
                is_show=True,
                linestyle_opts=opts.LineStyleOpts(
                    is_show=True,
                    width=1,
                    opacity=1,
                    curve=0,
                    type_="solid",
                    color='#0099ff',
                )
            )

        )
    )
)

视觉映射

class pyecharts.options.VisualMapOpts

class VisualMapOpts(
    is_show: bool = True,# 是否显示视觉映射配置
    type_: str = "color",# 映射过渡类型,可选,"color", "size"
    min_: Union[int, float] = 0,# 指定 visualMapPiecewise 组件的最小值
    max_: Union[int, float] = 100, # 指定 visualMapPiecewise 组件的最大值
    range_text: Union[list, tuple] = None,# 两端的文本,如['High', 'Low']
    range_color: Union[Sequence[str]] = None,# visualMap 组件过渡颜色
    range_size: Union[Sequence[int]] = None,# visualMap 组件过渡 symbol 大小
    orient: str = "vertical",# 如何放置 visualMap 组件,水平('horizontal')或者竖直('vertical')
 
    # visualMap 组件离容器左侧的距离
    # left 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比,
    # 也可以是 'left', 'center', 'right'。
    # 如果 left 的值为'left', 'center', 'right',组件会根据相应的位置自动对齐
    pos_left: Optional[str] = None,
 
    # visualMap 组件离容器右侧的距离
    # right 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比
    pos_right: Optional[str] = None,
 
    # visualMap 组件离容器上侧的距离
    # top 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比
    # 也可以是 'top', 'middle', 'bottom'
    # 如果 top 的值为'top', 'middle', 'bottom',组件会根据相应的位置自动对齐
    pos_top: Optional[str] = None,
 
    # visualMap 组件离容器下侧的距离。
    # bottom 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比。
    pos_bottom: Optional[str] = None,
 
   
    split_number: int = 5, # 对于连续型数据,自动平均切分成几段。默认为5段。连续数据的范围需要 max 和 min 来指定
    series_index: Union[Numeric, Sequence, None] = None,# 指定取哪个系列的数据,默认取所有系列
    dimension: Optional[Numeric] = None,# 组件映射维度
    is_calculable: bool = True, # 是否显示拖拽用的手柄(手柄能拖拽调整选中范围)
    is_piecewise: bool = False,# 是否为分段型
 
    # 自定义的每一段的范围,以及每一段的文字,以及每一段的特别的样式。例如:
    # pieces: [
    #   {"min": 1500}, // 不指定 max,表示 max 为无限大(Infinity)
    #   {"min": 900, "max": 1500},
    #   {"min": 310, "max": 1000},
    #   {"min": 200, "max": 300},
    #   {"min": 10, "max": 200, "label": '10 到 200(自定义label)'},
    #   {"value": 123, "label": '123(自定义特殊颜色)', "color": 'grey'}, //表示 value 等于 123 的情况
    #   {"max": 5}     // 不指定 min,表示 min 为无限大(-Infinity)
    # ]
    pieces: Optional[Sequence] = None,
 
    # 定义 在选中范围外 的视觉元素(用户可以和 visualMap 组件交互,用鼠标或触摸选择范围)
    #  可选的视觉元素有:
    #  symbol: 图元的图形类别
    #  symbolSize: 图元的大小
    #  color: 图元的颜色
    #  colorAlpha: 图元的颜色的透明度
    #  opacity: 图元以及其附属物(如文字标签)的透明度
    #  colorLightness: 颜色的明暗度,参见 HSL
    #  colorSaturation: 颜色的饱和度,参见 HSL
    #  colorHue: 颜色的色调,参见 HSL
    out_of_range: Optional[Sequence] = None,
    item_width: int = 0, # 图形的宽度,即长条的宽度
    item_height: int = 0, # 图形的高度,即长条的高度
    textstyle_opts: Union[TextStyleOpts, dict, None] = None,# 文字样式配置项,参考 `series_options.TextStyleOpts`
)
   .set_global_opts(visualmap_opts=opts.VisualMapOpts())#调用方法

基础设置示例

以bar图为例,展示各种属性的用法

from pyecharts.charts import Bar
#===========过程式调用==========
bar = Bar()
bar.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
bar.add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
# render 会生成本地 HTML 文件,默认会在当前目录生成 render.html 文件
# 也可以传入路径参数,如 bar.render("mycharts.html")
bar.render()

#============链式调用==========
from pyecharts.charts import Bar

bar = (
    Bar()
    .add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
)
bar.render()

  • 使用 options 配置项,在 pyecharts 中,一切皆 Options。
from pyecharts.charts import Bar
from pyecharts import options as opts

# V1 版本开始支持链式调用
# 你所看到的格式其实是 `black` 格式化以后的效果
# 可以执行 `pip install black` 下载使用
bar = (
    Bar()
    .add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
    .set_global_opts(title_opts=opts.TitleOpts(title="主标题", subtitle="副标题"))
    # 或者直接使用字典参数
    # .set_global_opts(title_opts={"text": "主标题", "subtext": "副标题"})
)
bar.render()

# 不习惯链式调用的开发者依旧可以单独调用方法
bar = Bar()
bar.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
bar.add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
bar.set_global_opts(title_opts=opts.TitleOpts(title="主标题", subtitle="副标题"))
bar.render()

# 设置主题
from pyecharts.globals import ThemeType

bar = (
    Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
    .add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
    .add_yaxis("商家B", [15, 6, 45, 20, 35, 66])
    .set_global_opts(title_opts=opts.TitleOpts(title="主标题", subtitle="副标题"))
)

# 更完整的示例
from pyecharts.charts import Bar
from pyecharts import options as opts

# V1 版本开始支持链式调用
bar = (
    Bar()
    # Bar({"theme": ThemeType.MACARONS}) # 设置主题
    .add_xaxis(["衬衫", "毛衣", "领带", "裤子", "风衣", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [114, 55, 27, 101, 125, 27, 105])
    .add_yaxis("商家B", Faker.values(), 
        is_selected=False, # 该列默认不选中!legend中无显示
        stack="stack1", # 数值堆叠
        category_gap="50%", # 设置间隔,与柱形宽度一样
        color="", # 设置柱条颜色, 可传列表
    )
    #.add_yaxis("商家B", Faker.values(), stack="stack1", category_gap=0, color=Faker.rand_color()) 
    .add_yaxis("商家B", [57, 134, 137, 129, 145, 60, 49])
    #.reversal_axis() # X/Y轴转置显示
    # .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) # 关闭数值显示
    # 自定义数值展示内容
    .set_series_opts(
        label_opts=opts.LabelOpts(
            position="right", # 靠右
            formatter=JsCode( # 自定义计算数值, 原始数据格式:[{"value":3, "percent":0.23},{"value":5, "percent":0.43}], x.data指向每个元素
                "function(x){return Number(x.data.percent * 100).toFixed() + '%';}"
            ),
        ),
        # 标记每组数据的特殊值(x轴气泡显示):最小、最大、平均
        markpoint_opts=opts.MarkPointOpts(
            data=[
                opts.MarkPointItem(type_="max", name="最大值"),
                opts.MarkPointItem(type_="min", name="最小值"),
                opts.MarkPointItem(type_="average", name="平均值"),
            ]
        ),
        # 标记每组数据的特殊值:y轴用虚横线显示, https://gallery.pyecharts.org/#/Bar/bar_markline_type
        markline_opts=opts.MarkLineOpts(
            data=[
                opts.MarkLineItem(type_="min", name="最小值"),
                opts.MarkLineItem(type_="max", name="最大值"),
                opts.MarkLineItem(type_="average", name="平均值"),
                opts.MarkLineItem(y=50, name="yAxis=50") # 自定义取值
            ]
        ),
        # 柱条形状变更:长方形 → 渐变椭圆圆柱
        itemstyle_opts={
            "normal": {
                "color": JsCode(
                    """new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
                offset: 0,
                color: 'rgba(0, 244, 255, 1)'
            }, {
                offset: 1,
                color: 'rgba(0, 77, 167, 1)'
            }], false)"""
                ),
                "barBorderRadius": [30, 30, 30, 30],
                "shadowColor": "rgb(0, 160, 221)",
            }
        }
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(title="某商场销售情况",
            subtitle='副标题\n第二行', # 支持换行
            title_textstyle_opts=opts.TextStyleOpts(color="white"), # 设置文本颜色
        ),
        # title_opts={"text": "Bar-通过 dict 进行配置", "subtext": "我也是通过 dict 进行配置的"} # 通过字典一次性设置
        yaxis_opts=opts.AxisOpts(name="我是Y轴"),
        xaxis_opts=opts.AxisOpts(name="我是X轴"),
        # xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)), # 向右旋转坐标轴文本15度
        # yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} /月")), # 自定义y轴取值
        #legend_opts=opts.LegendOpts(is_show=False), # 关闭图例
        toolbox_opts=opts.ToolboxOpts(), # 显示工具箱
        brush_opts=opts.BrushOpts(), # 刷子工具箱,框选范围(以上工具箱的子集)
        datazoom_opts=opts.DataZoomOpts(), # 支持自由缩放(X轴)
        #datazoom_opts=opts.DataZoomOpts(orient="vertical"), # 自由缩放(Y轴)
        datazoom_opts=opts.DataZoomOpts(type_="inside"), # 隐性缩放,x轴没有缩放框,直接拖拽
        datazoom_opts=[opts.DataZoomOpts(), opts.DataZoomOpts(type_="inside")], # 同时支持隐性+显性缩放
    )
)
bar.render()

效果示例

注意事项

【2022-8-20】经验教训

#!pip install pyecharts
from pyecharts.charts import Line, Bar, Page
from pyecharts import options as opts
import pandas as pd

df = pd.DataFrame({"name":["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"], "num":[114, 55, 27, 101, 125, 27] })
raw_data = df['num'].value_counts().to_dict()
new_data = sorted(raw_data.items(), key=lambda x:x[0], reverse=False)
print(new_data)
bar = (
    Bar()
    .add_xaxis(list(df["name"])) # 使用pandas数据时,一定要注意转换成list!
    .add_yaxis('pandas列数据', list(df['num'])) # 使用pandas数据时,一定要注意转换成list!
    .set_global_opts(title_opts=opts.TitleOpts(title='pandas数据测试'))
)
line = (
    Line()
    .add_xaxis(raw_data.keys())
    .add_yaxis('value_counts数据', [int(i) for i in raw_data.values()]) # 一定要转换数值类型:int64 → int
    .set_global_opts(title_opts=opts.TitleOpts(title='pandas数据测试'))
)
bar1 = (
    Bar() # 离散值用柱状图,否则line图空白
    .add_xaxis([i[0] for i in new_data])
    .add_yaxis('dict values', [i[1] for i in new_data])
    .set_global_opts(title_opts=opts.TitleOpts(title='pandas数据测试'))
)
#bar.render_notebook()
page = Page(layout=Page.SimplePageLayout)
page.add(bar, line, bar1)
page.render_notebook()
#type(tmp_data[27])

图表详解

  • 官方最全的代码+效果示例

表格展示

扩展组件:表格形式展示数据

from pyecharts.components import Table
from pyecharts.options import ComponentTitleOpts

table = Table()

headers = ["City name", "Area", "Population", "Annual Rainfall"]
rows = [
    ["Brisbane", 5905, 1857594, 1146.4],
    ["Adelaide", 1295, 1158259, 600.5],
    ["Darwin", 112, 120900, 1714.7],
    ["Hobart", 1357, 205556, 619.5],
    ["Sydney", 2058, 4336374, 1214.8],
    ["Melbourne", 1566, 3806092, 646.9],
    ["Perth", 5386, 1554769, 869.4],
]
# 排序
# sorted(rows, key=lambda x:x[1], reverse=True)

table.add(headers, rows)
table.set_global_opts(
    title_opts=ComponentTitleOpts(title="Table-基本示例", subtitle="我是副标题支持换行哦")
)
table.render("table_base.html")

交互式表格

【2022-10-9】 streamlit 工具实现的交互式表格

import pandas as pd
import streamlit as st
from st_aggrid import AgGrid, GridOptionsBuilder
from st_aggrid.shared import GridUpdateMode

iris = pd.read_csv(
    "https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv"
)

def aggrid_interactive_table(df: pd.DataFrame):
    """Creates an st-aggrid interactive table based on a dataframe.

    Args:
        df (pd.DataFrame]): Source dataframe

    Returns:
        dict: The selected row
    """
    options = GridOptionsBuilder.from_dataframe(
        df, enableRowGroup=True, enableValue=True, enablePivot=True
    )

    options.configure_side_bar()

    options.configure_selection("single")
    selection = AgGrid(
        df,
        enable_enterprise_modules=True,
        gridOptions=options.build(),
        theme="light",
        update_mode=GridUpdateMode.MODEL_CHANGED,
        allow_unsafe_jscode=True,
    )

    return selection


iris = pd.read_csv(
    "https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv"
)

selection = aggrid_interactive_table(df=iris)

if selection:
    st.write("You selected:")
    st.json(selection["selected_rows"])

饼图

代码:

from pyecharts.charts import Pie
from pyecharts import options as opts

data = [['交易定金', 2],
 ['交易服务费', 3],
 ['交易流程-全款', 5],
 ['交易流程-公积金', 6],
 ['交易流程-商贷', 33],
 ['交易流程-组合贷', 2],
 ['征信与贷款', 2],
 ['户口保证金', 1],
 ['物业保证金', 3],
 ['税费政策', 14],
 ['解抵押流程', 7],
 ['贝壳服务内容', 15],
 ['资金监管', 18],
 ['限购限售政策', 1]]

pie = (Pie(init_opts=opts.InitOpts(width="1440px", height="720px"))
    .add("交互成功的签约意图分布", data,
            radius=["30%", "75%"], # radius=[40,75],radius:半径
            center=["25%", "50%"],
            rosetype="radius",
            label_opts=opts.LabelOpts(is_show=True))
     .set_global_opts(
        title_opts=opts.TitleOpts(title="签约意图占比分布"),   # TitleOpts:标题设置项
         toolbox_opts=opts.ToolboxOpts(is_show=True), # 工具箱
        legend_opts=opts.LegendOpts(pos_top="5%",pos_right="15%", orient='vertical')) #LegendOpts:图例配置项
) 
pie.render_notebook()

柱形图

from pyecharts.charts import Bar
from pyecharts import options as opts

# V1 版本开始支持链式调用
bar = (
    Bar()
    # Bar({"theme": ThemeType.MACARONS}) # 设置主题
    .add_xaxis(["衬衫", "毛衣", "领带", "裤子", "风衣", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [114, 55, 27, 101, 125, 27, 105])
    .add_yaxis("商家B", Faker.values(), stack="stack1") # 数值堆叠
    .add_yaxis("商家B", [57, 134, 137, 129, 145, 60, 49])
    .set_global_opts(title_opts=opts.TitleOpts(title="某商场销售情况"),
        subtitle='副标题',
        yaxis_opts=opts.AxisOpts(name="我是Y轴"),
        xaxis_opts=opts.AxisOpts(name="我是X轴"),
        #legend_opts=opts.LegendOpts(is_show=False), # 关闭图例
        toolbox_opts=opts.ToolboxOpts(), # 显示工具箱
        datazoom_opts=opts.DataZoomOpts(), # 支持自由缩放
    )
)
bar.render()

# 不习惯链式调用的开发者依旧可以单独调用方法
bar = Bar()
bar.add_xaxis(["衬衫", "毛衣", "领带", "裤子", "风衣", "高跟鞋", "袜子"])
bar.add_yaxis("商家A", [114, 55, 27, 101, 125, 27, 105]
    # label_opts=opts.LabelOpts(is_show=False), # 不显示数值label
    )
bar.add_yaxis("商家B", [57, 134, 137, 129, 145, 60, 49])
bar.set_global_opts(title_opts=opts.TitleOpts(title="某商场销售情况"),
    subtitle='副标题',
    legend_opts=opts.LegendOpts(is_show=False), # 关闭图例
    toolbox_opts=opts.ToolboxOpts(), # 显示工具箱
    datazoom_opts=opts.DataZoomOpts(), # 支持自由缩放
    )
#bar.render()
bar.render_notebook()

折线图

简版

from pyecharts.charts import Line
from pyecharts import options as opts

# V1 版本开始支持链式调用
bar = (
    Line()
    .add_xaxis(["衬衫", "毛衣", "领带", "裤子", "风衣", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [114, 55, 27, 101, 125, 27, 105])
    .add_yaxis("商家B", [57, 134, 137, 129, 145, 60, 49])
    .set_global_opts(title_opts=opts.TitleOpts(title="某商场销售情况"))
)
bar.render_notebook()

精细版

import pyecharts.options as opts
from pyecharts.charts import Line

"""
Gallery 使用 pyecharts 1.1.0
参考地址: https://echarts.apache.org/examples/editor.html?c=area-basic
目前无法实现的功能:
暂无
"""

x_data = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
y_data = [820, 932, 901, 934, 1290, 1330, 1320]


(
    Line()
    .add_xaxis(xaxis_data=x_data)
    .add_yaxis(
        series_name="",
        y_axis=y_data,
        symbol="emptyCircle",
        is_symbol_show=True,
        label_opts=opts.LabelOpts(is_show=False),
        areastyle_opts=opts.AreaStyleOpts(opacity=1, color="#C67570"),
    )
    .set_global_opts(
        tooltip_opts=opts.TooltipOpts(is_show=False),
        yaxis_opts=opts.AxisOpts(
            type_="value",
            axistick_opts=opts.AxisTickOpts(is_show=True),
            splitline_opts=opts.SplitLineOpts(is_show=True),
        ),
        xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),
    )
    # 设置 boundary_gap 的时候一定要放在最后一个配置项里, 不然会被覆盖
    #.render("basic_area_chart.html")
    .render_notebook()
)

树形图

多种效果

import json

from pyecharts import options as opts
from pyecharts.charts import Tree

with open("flare.json", "r", encoding="utf-8") as f:
    j = json.load(f)
# 左右方向
c = (
    Tree()
    .add("", [j], collapse_interval=2)
    .set_global_opts(title_opts=opts.TitleOpts(title="Tree-左右方向"))
    .render("tree_left_right.html")
)
# 上下方向
c = (
    Tree()
    .add(
        "",
        [j],
        collapse_interval=2,
        orient="BT",
        label_opts=opts.LabelOpts(
            position="top",
            horizontal_align="right",
            vertical_align="middle",
            rotate=-90,
        ),
    )
    .set_global_opts(title_opts=opts.TitleOpts(title="Tree-下上方向"))
    .render("tree_bottom_top.html")
)
# 平铺
c = (
    Tree()
    .add("", [j], collapse_interval=2, layout="radial")
    .set_global_opts(title_opts=opts.TitleOpts(title="Tree-Layout"))
    .render("tree_layout.html")
)

数据格式

from pyecharts import options as opts
from pyecharts.charts import Tree


data = [
    {
        "children": [
            {"name": "B"},
            {
                "children": [{"children": [{"name": "I"}], "name": "E"}, {"name": "F"}],
                "name": "C",
            },
            {
                "children": [
                    {"children": [{"name": "J"}, {"name": "K"}], "name": "G"},
                    {"name": "H"},
                ],
                "name": "D",
            },
        ],
        "name": "A",
    }
]
c = (
    Tree()
    .add("", data)
    .set_global_opts(title_opts=opts.TitleOpts(title="Tree-基本示例"))
    .render("tree_base.html")
)

桑基图 Sankey

  • 桑基图:展现数据流动
  • 桑基图主要由流量支点组成,其中
  • 代表了流动的数据.边的宽度与流量成比例地显示,边越宽,数值越大。
  • 流量代表了流动数据的具体数值
  • 节点代表了不同分类

桑基图自被命名的那一刻起,就注定和能量分不开了。

  • 桑基图通常用于可视化能源或成本转移,也帮助确定各部分流量在总体中的大概占比情况。无论数据怎么流动,桑基图的总数值保持不变,坚持数据的“能量守恒”。
  • 无论数据怎样流动,数据的总量从开始到结束都不能有任何的变化,不能在中间过程创造出数据,流失(损耗)的数据应该流向表示损耗的支点。
  • 弦图不同,桑基图的每条边的宽度是保持不变的。即使有时候出于设计需要,边的宽度看上去不一样,但所代表的数据是不变的。如果需要展示数据在流动过程中初始的权重变化,就应该使用弦图
  • 横向桑基图

桑基图在pyecharts中通过Sankey方法实现,它接受两个外部输入。

  • 一个是所有类别的集合-nodes
  • 一个是子类、父类、数据的三方集合-links。

这两个都是以json数据格式传入,最后以html形式输出图表。

# 导入相关库
import pandas as pd
from pyecharts.charts import Page, Sankey
from pyecharts import options as opts

# 读取csv文件
data = pd.read_csv(r'sample.csv',encoding='gbk',header=None)

# 生成nodes
nodes = []
nodes.append({'name':'总支出'})
for i in data[0].unique():
    dic = {}
    dic['name'] = i
    nodes.append(dic)

# 生成links
links = []
for i in data.values:
    dic = {}
    dic['source'] = i[0]
    dic['target'] = i[1]
    dic['value'] = i[2]
    links.append(dic)

# pyecharts 所有方法均支持链式调用。
c = (
        Sankey()
        .add(
"费用/元",
            nodes,
            links,
            linestyle_opt=opts.LineStyleOpts(opacity=0.2, curve=0.5, color="source",type_="dotted"),
            label_opts=opts.LabelOpts(position="right",),
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="我的生活支出一览"))
    )
# 输出html可视化结果
c.render('result.html')

动画

【2021-6-14】按照时间线轮播,kaggle代码地址

# -*- coding: UTF-8 -*-
import copy
import random

NUM = 10
wealth_list = [100]*NUM
person_id = [ '编号{}'.format(i) for i in range(NUM)]
print("迭代前的财富分配:{}".format(wealth_list))
wealth_process = {}
MAX = 1000000
stop = [1, 1000, 10000, 100000, MAX]
for iter in range(MAX):
	for i,v in enumerate(wealth_list):
		send_person = random.randint(0,NUM-1)
		#print('第{}轮: {} -> {}'.format(iter, i, send_person))
		#if wealth_list[i] > 0:
		#	wealth_list[i] -= 1
		wealth_list[i] -= 1
		wealth_list[send_person] += 1
	if iter+1 in stop:
		wealth_process[iter+1] = {'data': [], 'range':[]}
		wealth_process[iter+1]['range'] = [min(wealth_list), max(wealth_list), max(wealth_list)/min(wealth_list),sum(wealth_list)/NUM]
		wealth_process[iter+1]['data'] = copy.deepcopy(wealth_list)
        
		print("迭代{}轮后的财富分配:[{},{}], 极差:{}, 均值:{}, 详情:{}".format(iter+1, 
                       *wealth_process[iter+1]['range'], wealth_process[iter+1]['data']))
print("迭代{}轮后的财富分配:{}".format(iter+1, wealth_list))


from pyecharts import options as opts
from pyecharts.charts import Bar, Timeline
from pyecharts.commons.utils import JsCode
#from pyecharts.faker import Faker

#x = Faker.choose()
x = person_id
tl = Timeline()
for i in wealth_process:
    bar = (
        Bar()
        .add_xaxis(x)
        .add_yaxis("财富值", wealth_process[i]['data'])
        #.add_yaxis("商家B", Faker.values())
        .set_global_opts(
            #title_opts=opts.TitleOpts("幂律分布:财富随机分配实验,第{}轮".format(i)),
            title_opts=opts.TitleOpts(title="幂律分布:财富随机分配实验",
                    subtitle="{}人,每人底钱100元,每轮随机给别人1元,迭代{}轮后,[{},{}], 均值{:.2f}, 极差{}".format(NUM, MAX,
                                                                             *wealth_process[i]['range'])),
            graphic_opts=[
                opts.GraphicGroup(
                    graphic_item=opts.GraphicItem(
                        rotation=JsCode("Math.PI / 4"),
                        bounding="raw",
                        right=100,
                        bottom=110,
                        z=100,
                    ),
                    children=[
                        opts.GraphicRect(
                            graphic_item=opts.GraphicItem(
                                left="center", top="center", z=100
                            ),
                            graphic_shape_opts=opts.GraphicShapeOpts(
                                width=400, height=50
                            ),
                            graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                fill="rgba(0,0,0,0.3)"
                            ),
                        ),
                        opts.GraphicText(
                            graphic_item=opts.GraphicItem(
                                left="center", top="center", z=100
                            ),
                            graphic_textstyle_opts=opts.GraphicTextStyleOpts(
                                text="第{}轮→马太效应".format(i),
                                font="bold 26px Microsoft YaHei",
                                graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                    fill="#fff"
                                ),
                            ),
                        ),
                    ],
                )
            ],
        )
    )
    tl.add(bar, "第{}轮".format(i))
tl.render("timeline_bar_with_graphic.html")
tl.render_notebook()

热力图

示例

import random
from pyecharts import HeatMap
from pyecharts import options as opts

x_axis = [
    "12a", "1a", "2a", "3a", "4a", "5a", "6a", "7a", "8a", "9a", "10a", "11a",
    "12p", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "10p", "11p"]
y_axis = [
    "Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday", "Sunday"]
data = [[i, j, random.randint(0, 50)] for i in range(24) for j in range(7)]
# ==== 旧版过程调用 =====
heatmap = HeatMap()
heatmap.add(
    "热力图直角坐标系",
    x_axis,
    y_axis,
    data,
    is_visualmap=True,
    visual_range=[0, 1], # 取值范围
    visual_range_color=["#CDC5BF","#FF69B4", "#FF0000"], # 颜色设置
    visual_text_color="#000",
    visual_orient="horizontal",
)
heatmap.render('heatmap.html')
heatmap.render_notebook()

# === 新版链式调用 ===
from pyecharts.charts import HeatMap

heatmap = (HeatMap()
            .add_xaxis(x_axis)
            .add_yaxis("发博数", y_axis, data)
            .set_global_opts(
                title_opts=opts.TitleOpts(title="用户发博时间热力图"),
                visualmap_opts=opts.VisualMapOpts(max_=600)
            )
    )

【2024-8-26】热力图实践

  • 数据格式 [i,j,val], 其中 val 必须 int 类型
import numpy as np
from pyecharts.charts import HeatMap
from pyecharts import options as opts

class_list = [2,3,4,20,30,41,42,51,52,53]

str = """[[1219    0    0   12   74   31    0    0    0    0]
 [   6    0    0    0    3    1    0    0    0    0]
 [  14    0    0    9    8    0    0    0    0    0]
 [  12    0    0   97   19    0    0    0    0    0]
 [ 119    0    0   14   91   16    0    0    0    0]
 [  22    0    0    4   21   77    0    0    0    0]
 [   0    0    0    0    0    1    0    0    0    0]
 [   9    0    0    1    3    1    0    0    0    0]
 [   1    0    0    0    1    0    0    0    0    0]
 [   2    0    0    2    0    0    0    0    0    0]]"""
# print(str.replace('\n', ';'))
confusion = np.matrix(str.replace('\n', ';'))
print(confusion)

# 数据格式: [i,j, val] -> [[0,0, 10], [0,1, 11]]
data_list = [[i,j, int(confusion[i,j])] for i in range(confusion.shape[0]) for j in range(confusion.shape[1])]

heatmap = (HeatMap()
            .add_xaxis(class_list)
            .add_yaxis("预测数目", class_list, data_list)
            .set_global_opts(
                title_opts=opts.TitleOpts(title="换query多分类混淆矩阵图"),
                visualmap_opts=opts.VisualMapOpts(max_=confusion.max())
            )
    )
heatmap.render('换query多分类.html')
heatmap.render_notebook()

意图槽位图

【2021-8-22】实践,参考官方教程

# y轴标签 intent_list,x轴便签slot_list,数据矩阵data
data = [[x,y,intent_slot_list[y][x]] for x in range(len(slot_list)) for y in range(len(intent_list))]
heat_map = (
    HeatMap(init_opts=opts.InitOpts(width="1440px", height="720px"))
    .add_xaxis(xaxis_data=slot_list)
    .add_yaxis(
        series_name="频次",
        yaxis_data=intent_list,
        value=data,
        label_opts=opts.LabelOpts(
            is_show=True, color="#fff", position="bottom", horizontal_align="50%"
        ),
    )
    .set_series_opts()
    .set_global_opts(
        title_opts=opts.TitleOpts(title="意图槽位分布图"),
        toolbox_opts=opts.ToolboxOpts(is_show=True), # 工具箱
        legend_opts=opts.LegendOpts(is_show=False),
        xaxis_opts=opts.AxisOpts(
            type_="category",
            splitarea_opts=opts.SplitAreaOpts(
                is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
            ),
        ),
        yaxis_opts=opts.AxisOpts(
            type_="category",
            splitarea_opts=opts.SplitAreaOpts(
                is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
            ),
        ),
        visualmap_opts=opts.VisualMapOpts(
            min_=1, max_=1000, is_calculable=True, orient="horizontal", pos_left="center"
        ),
    )
)

多轮对话转化

import random
import pyecharts as pe
# 为了避免显示空白,加入以下代码执行后,重新刷新当前jupyter页面即可
pe.configure(
    jshost="https://pyecharts.github.io/assets/js",
    echarts_template_dir=None,
    force_js_embed=None,
    output_image=None,
    global_theme=None
)
# 代码参考:http://pyecharts.org/#/zh-cn/charts_base?id=heatmap%EF%BC%88%E7%83%AD%E5%8A%9B%E5%9B%BE%EF%BC%89
# x_axis = ["12a", "1a", "2a", "3a", "4a", "5a", "6a", "7a", "8a", "9a", "10a", "11a",
#     "12p", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "10p", "11p"]
# y_axis = ["Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday", "Sunday"]
# data = [[i, j, random.randint(0, 50)] for i in range(24) for j in range(7)]
page = pe.Page('多轮对话场景分析')
title = '投诉进度查询状态转化'
# (1) 节点状态转化图
x_axis = y_axis = attr_list
item_len = len(x_axis)
data = [[x_axis[i], y_axis[j], val_list[i][j]] for i in range(item_len) for j in range(item_len)]
heatmap = pe.HeatMap()
heatmap.add(
    '%s(x -> y)'%(title),
    x_axis,
    y_axis,
    data,
    is_visualmap=True,
    visual_range=[dh.get_values().min(), dh.get_values().max()],
    visual_text_color="#000",
    visual_orient="horizontal",
)
#heatmap.render()
page.add(heatmap)

水球图

代码

from pyecharts import options as opts
from pyecharts.charts import Liquid, Grid
from pyecharts.globals import SymbolType

c1 = (
    Liquid()
    .add("有效交互成功率", [0.75], 
    center=["15%", "50%"], # 多个图时,各自位置范围
    is_outline_show=False, # 边框不显示
    shape=SymbolType.RECT) # 水球形状(默认圆形,此处设置为矩形)
    #.add("有效交互成功率", [his_data[-1][-2]*0.01], center=["15%", "50%"])
    .set_global_opts(title_opts=opts.TitleOpts(title="比例值"))
    #.render("liquid_base.html")
)

graph 图谱

参数说明

参数设置:

# 节点方法
class GraphNode(
    # 数据项名称。
    name: Optional[str] = None,
    # 节点的初始 x 值。在不指定的时候需要指明layout属性选择布局方式。
    x: Optional[Numeric] = None,
    # 节点的初始 y 值。在不指定的时候需要指明layout属性选择布局方式。
    y: Optional[Numeric] = None,
    # 节点在力引导布局中是否固定。
    is_fixed: bool = False,
    # 数据项值。
    value: Union[str, Sequence, None] = None,
    # 数据项所在类目的 index。
    category: Optional[int] = None,
    # 该类目节点标记的图形。
    # ECharts 提供的标记类型包括 'circle', 'rect', 'roundRect', 'triangle', 
    # 'diamond', 'pin', 'arrow', 'none'
    # 可以通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI。
    symbol: Optional[str] = None,
    # 该类目节点标记的大小,可以设置成诸如 10 这样单一的数字,也可以用数组分开表示宽和高,
    # 例如 [20, 10] 表示标记宽为 20,高为 10。
    symbol_size: Union[Numeric, Sequence, None] = None,
    # 标签配置项,参考 `series_options.LabelOpts`
    label_opts: Optional[LabelOpts] = None,
)
# 节点分类
class GraphCategory(
    # 类目名称,用于和 legend 对应以及格式化 tooltip 的内容。
    name: Optional[str] = None,
    # 该类目节点标记的图形。
    # ECharts 提供的标记类型包括 'circle', 'rect', 'roundRect', 'triangle', 
    # 'diamond', 'pin', 'arrow', 'none'
    # 可以通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI。
    symbol: Optional[str] = None,
    # 该类目节点标记的大小,可以设置成诸如 10 这样单一的数字,也可以用数组分开表示宽和高,
    # 例如 [20, 10] 表示标记宽为 20,高为 10。
    symbol_size: Union[Numeric, Sequence, None] = None,
    # # 标签样式,参考 `series_options.LabelOpts`
    label_opts: Optional[LabelOpts] = None,
)

# 边方法
class GraphLink(
    # 边的源节点名称的字符串,也支持使用数字表示源节点的索引。
    source: Union[str, int, None] = None,
    # 边的目标节点名称的字符串,也支持使用数字表示源节点的索引。
    target: Union[str, int, None] = None,
    # 边的数值,可以在力引导布局中用于映射到边的长度。
    value: Optional[Numeric] = None,
    # 边两端的标记类型,可以是一个数组分别指定两端,也可以是单个统一指定。
    symbol: Union[str, Sequence, None] = None,
    # 边两端的标记大小,可以是一个数组分别指定两端,也可以是单个统一指定。
    symbol_size: Union[Numeric, Sequence, None] = None,
    # 关系边的线条样式,参考 `series_options.LineStyleOpts`
    linestyle_opts: Optional[LineStyleOpts] = None,
    # 标签样式,参考 `series_options.LabelOpts`
    label_opts: Optional[LabelOpts] = None,
)

# add方法
def add(
    # 系列名称,用于 tooltip 的显示,legend 的图例筛选。
    series_name: str,
    # 关系图节点数据项列表,参考 `opts.GraphNode`
    nodes: Sequence[Union[opts.GraphNode, dict]],
    # 关系图节点间关系数据项列表,参考 `opts.GraphLink`
    links: Sequence[Union[opts.GraphLink, dict]],
    # 关系图节点分类的类目列表,参考 `opts.GraphCategory`
    categories: Union[Sequence[Union[opts.GraphCategory, dict]], None] = None,
    # 是否选中图例。
    is_selected: bool = True,
    # 是否在鼠标移到节点上的时候突出显示节点以及节点的边和邻接节点。
    is_focusnode: bool = True,
    # 是否开启鼠标缩放和平移漫游。
    is_roam: bool = True,
    # 节点是否可拖拽,只在使用力引导布局的时候有用。
    is_draggable: bool = False,
    # 是否旋转标签,默认不旋转。
    is_rotate_label: bool = False,
    # ==== 图的布局 ====== 可选:
    # 'none' 不采用任何布局,使用节点中提供的 x, y 作为节点的位置。
    # 'circular' 采用环形布局。
    # 'force' 采用力引导布局。
    layout: str = "force",
    # 关系图节点标记的图形。
    # ECharts 提供的标记类型包括 'circle', 'rect', 'roundRect', 'triangle', 
    # 'diamond', 'pin', 'arrow', 'none'
    # 可以通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI。
    symbol: Optional[str] = None,
    # 关系图节点标记的大小
    # 可以设置成诸如 10 这样单一的数字
    # 也可以用数组分开表示宽和高,例如 [20, 10] 表示标记宽为20,高为10。
    symbol_size: types.Numeric = 10,
    # 边的两个节点之间的距离,这个距离也会受 repulsion。
    # 支持设置成数组表达边长的范围,此时不同大小的值会线性映射到不同的长度。值越小则长度越长。
    edge_length: Numeric = 50,
    # 节点受到的向中心的引力因子。该值越大节点越往中心点靠拢。
    gravity: Numeric = 0.2,
    # 节点之间的斥力因子。
    # 支持设置成数组表达斥力的范围,此时不同大小的值会线性映射到不同的斥力。值越大则斥力越大
    repulsion: Numeric = 50,
     # Graph 图节点边的 Label 配置(即在边上显示数据或标注的配置)
    edge_label: types.Label = None,
    # 边两端的标记类型,可以是一个数组分别指定两端,也可以是单个统一指定。
    # 默认不显示标记,常见的可以设置为箭头,如下:edgeSymbol: ['circle', 'arrow']
    edge_symbol: Optional[str] = None,
    # 边两端的标记大小,可以是一个数组分别指定两端,也可以是单个统一指定。
    edge_symbol_size: Numeric = 10,
    # 标签配置项,参考 `series_options.LabelOpts`
    label_opts: Union[opts.LabelOpts, dict] = opts.LabelOpts(),
    # 关系边的公用线条样式。
    linestyle_opts: Union[opts.LineStyleOpts, dict] = opts.LineStyleOpts(),
    # 提示框组件配置项,参考 `series_options.TooltipOpts`
    tooltip_opts: Union[opts.TooltipOpts, dict, None] = None,
    # 图元样式配置项,参考 `series_options.ItemStyleOpts`
    itemstyle_opts: Union[opts.ItemStyleOpts, dict, None] = None,
)

(1) Graph 绘制

【2024-7-6】设置节点、边,绘图即可,实测通过

  • pyecharts 2.0.6
#!pip install pyecharts
from pyecharts import options as opts
from pyecharts.charts import Graph

# 边信息(附加数值)
# 注意: 起点终点一样的节点,边无法绘制
data_info = [
 ('甲', '乙', '1', 'Blue'),
 ('甲', '丙', '2', 'Green'),
 ('甲', '丁', '3', 'Yellow'),
 ('乙', '丁', '1', 'Blue'),
 ('乙', '乙', '2', 'Green'),
 ('乙', '庚', '3', 'Yellow'),
 ('丙', '庚', '5', 'Red'),
 ('丙', '壬', '1', 'Blue')]

# 提取全部节点
node_list = set([i[0] for i in data_info]) | set([i[1] for i in data_info])

# 设置节点信息
nodes = []
for i in node_list:
    nodes.append(opts.GraphNode(
        name=i, 
        symbol_size=50, 
        label_opts=opts.LabelOpts(is_show=True, color='white'))
        # label_opts=opts.LabelOpts(is_show=True, font_size='20', color='white'))
    )
# 设置边信息
links = []
for i in data_info:
    links.append(
        opts.GraphLink(
            source=i[0], 
            target=i[1], 
            value=int(i[2]), 
            linestyle_opts=opts.LineStyleOpts(
                color=i[3].lower(),
                width=2*int(i[2]), 
                opacity=0.5)
        )
    )
# 开始绘图
c = (
    Graph(init_opts=opts.InitOpts(width="1440px", height="720px", bg_color="#000000"))
    .add("", nodes, links, repulsion=400,
            symbol_size= [0, 20],edge_symbol =['circle', 'arrow'], is_draggable=True,
            is_rotate_label=True, # 标签旋转
            linestyle_opts=opts.LineStyleOpts(color="source", type_= 'dashed'),#'solid', 'dashed', 'dotted'
            label_opts=opts.LabelOpts(is_show=True, font_size='18', color='green'), # 节点label
            edge_label=opts.LabelOpts(is_show=True, position="middle", # 边label
                font_size='15', formatter="{c}") # {b} 是默认值:a>b
        )
    .set_global_opts(title_opts=opts.TitleOpts(title="状态图"),
        legend_opts=opts.LegendOpts(pos_top="5%",pos_right="15%", orient='vertical')
    )
)

c.render('可视化.html')
c.render_notebook()

(2) Graph 图谱

【2023-12-4】 notebook 6.1.5 上实现通过,高版本会出现白屏,详见jupyter问题

配置数据类型

data:[
    {
        name:'节点名称',
        value:'节点值'
        x:节点坐标,	在不指定的时候需要指明layout属性选择布局方式。
        y:节点坐标,
        symbolSize: 80,
        draggable: true, 	节点是否可拖拽,只在使用力引导布局的时候有用。
        itemStyle: {},
        categrory:'在categories中设置的名称,用于图例等分类'	或者数值索引
    }
pip install notebook==6.1.5

【2020-11-27】多轮转化图

【2024-7-6】实测通过

  • pyecharts 2.0.6

代码

# (2) Graph图谱
from pyecharts import Graph

# 定义节点
categories=[{}, {'name': '类目1'},{'name': '类目2'}] # 节点类型
nodes = [{"name": "A", "symbolSize": 10, "category":2},
         {"name": "B", "symbolSize": 20, "category":2},
         {"name": "C", "symbolSize": 30, "category":1},
         {"name": "D", "symbolSize": 40, "category":2},
         {"name": "E", "symbolSize": 50, "category":1},
         {"name": "F", "symbolSize": 40, "category":2},
        # opts.GraphNode(name="所有交互", symbol_size=50, x=500, y=200), # 节点位置固定,与add里的layout='none'配合使用才生效
         { "name": "所有交互", "symbol_size": 50, "x":500, "y":200, "category":2}, # 节点位置固定,与add里的layout='none'配合使用才生效
         {"name": "G", "symbolSize": 30, "category":1},
         {"name": "H", "symbolSize": 20, "category":2}]
# 定义边/链接
links = []
for i in nodes:
    for j in nodes:
        links.append({"source": i.get('name'), "target": j.get('name')})
nodes = json.loads(json.dumps(nodes))
# 图表
graph = Graph("%s-状态图"%(title))
# 添加节点/边
graph.add("", nodes, links, repulsion=80000, symbol='roundRect', 
    layout='force', # layout=none固定节点位置
    # edgeSymbolSize= [0, 20], categories=categories,
    is_rotate_label=True, # 标签旋转
    # formatter="{b},数值为{c} ", # js显示数据格式,可用参数{a},{b},...,{e}
    linestyle_opts=opts.LineStyleOpts(color="source", curve=0.3), # 线型设置,curve=0.3表示弯曲程度
    #edgeSymbol =['circle', 'arrow']
)
# 集中渲染到html文件
graph.render('muti_turn_vis.html')

(3) 自定义

签约大屏转化漏斗

# (3) 自定义绘图 【2021-10-23】
from pyecharts import options as opts
from pyecharts.charts import Page, Tab
from pyecharts.charts import Graph

dt_info = '2021-10-23'
# 节点类型
categories=[{}, {'name': '所有交互'},{'name': '无效交互'},{'name': '有效交互'},{'name': '成功'},{'name': '失败'}]
# 边信息
trans_info = {'所有交互->有效交互': 120,
 '所有交互->无效交互': 189,
 '无效交互->环境杂音': 186,
 '无效交互->教学': 3,
 '有效交互->成功': 115,
 '有效交互->失败': 1,
 '失败->ASR错误': 1,
 '失败->新意图': 3,
 '失败->重复唤醒': 1,
 '失败->NLU泛化': 0,
 '成功->退出': 77,
 '成功->签约意图': 33,
 '成功->闲聊': 3,
 '成功->其它': 2}
# 节点信息
nodes = [
    #opts.GraphNode(name="所有交互", symbol_size=50), # 节点位置不定
    opts.GraphNode(name=f"所有交互\n{1000}", symbol_size=50, x=500, y=220, category=1, value=1000,
        label_opts=opts.LabelOpts(is_show=True, font_size='20', color='green') # 可以单独设置label格式
        ), # 节点位置固定,与add里的layout='none'配合使用才生效
    opts.GraphNode(name="无效交互", symbol_size=50, x=450, y=250, category=2, value=trans_info["所有交互->无效交互"]),
    opts.GraphNode(name="有效交互", symbol_size=50, x=550, y=250, category=3, value=trans_info["所有交互->有效交互"]),
    opts.GraphNode(name="失败", symbol_size=50, x=520, y=280, category=5, value=trans_info["有效交互->失败"]),
    opts.GraphNode(name="成功", symbol_size=50, x=580, y=280, category=4, value=trans_info["有效交互->成功"]),
    opts.GraphNode(name="环境杂音", symbol_size=30, x=380, y=310, category=2, value=trans_info["无效交互->环境杂音"]),
    opts.GraphNode(name="教学", symbol_size=30, x=400, y=310, category=2, value=trans_info["无效交互->教学"]),
    opts.GraphNode(name="退出", symbol_size=30, x=550, y=310, category=4, value=trans_info["成功->退出"]),
    opts.GraphNode(name="闲聊", symbol_size=30, x=570, y=310, category=4, value=trans_info["成功->闲聊"]),
    opts.GraphNode(name="签约意图", symbol_size=30, x=590, y=310, category=4, value=trans_info["成功->签约意图"]),
    opts.GraphNode(name="其它", symbol_size=30, x=610, y=310, category=4, value=trans_info["成功->其它"]),
    opts.GraphNode(name="重复唤醒", symbol_size=30, x=480, y=310, category=5, value=trans_info["失败->重复唤醒"]),
    opts.GraphNode(name="ASR错误", symbol_size=30, x=500, y=310, category=5, value=trans_info["失败->ASR错误"]),
    opts.GraphNode(name="NLU泛化", symbol_size=30, x=520, y=310, category=5, value=trans_info["失败->NLU泛化"]),
    opts.GraphNode(name="新意图", symbol_size=30, x=540, y=310, category=5, value=trans_info["失败->新意图"]),
]
# 【2021-11-2】 由于节点无法显示数值,只好在节点名中包含数值,这会影响边关联,所以需要单独获取node对象的名称
#      node.get('name') 获取节点名
nodes_name_dict = dict([[i.get('name').split('\n')[0], i.get('name')] for i in nodes])

# 逐个添加边(可忽略)
links = [
    opts.GraphLink(source="所有交互", target="无效交互", linestyle_opts=opts.LineStyleOpts(width=20, opacity=0.5)),
    opts.GraphLink(source="所有交互", target="有效交互", linestyle_opts=opts.LineStyleOpts(width=4, opacity=0.5)),
    opts.GraphLink(source="无效交互", target="环境杂音"),
    opts.GraphLink(source="无效交互", target="教学"),
    opts.GraphLink(source="有效交互", target="失败"),
    opts.GraphLink(source="有效交互", target="成功"),
    opts.GraphLink(source="失败", target="重复唤醒"),
    opts.GraphLink(source="失败", target="ASR错误"),
    opts.GraphLink(source="失败", target="NLU泛化"),
    opts.GraphLink(source="失败", target="新意图"),
    opts.GraphLink(source="成功", target="退出"),
    opts.GraphLink(source="成功", target="闲聊"),
    opts.GraphLink(source="成功", target="签约意图"),
    opts.GraphLink(source="成功", target="其它"),
]
# 或批量添加(提前准备trans_info字典)
links = []
for item in trans_info:
    s, d = item.split('->')
    width = max(int(trans_info[item]*30/200), 1)
    links.append(opts.GraphLink(source=s, target=d, 
        # source=nodes_name_dict.get(s, f'异常-{s}'), 
        # target=nodes_name_dict.get(d, f'异常-{d}'), 
        value=round(trans_info[item]*100/1000,2),
        linestyle_opts=opts.LineStyleOpts(width=width, opacity=0.3)))
# 绘图
c = (
    Graph(init_opts=opts.InitOpts(width="1440px", height="720px"))
    .add("", nodes, links, repulsion=400, symbol='roundRect', layout='none',  # force
             symbol_size= [0, 20],edge_symbol =['circle', 'arrow'], is_draggable=True, categories=categories,
            is_rotate_label=True, # 标签旋转
            linestyle_opts=opts.LineStyleOpts(color="source", type_= 'dashed'),#'solid', 'dashed', 'dotted'
            label_opts=opts.LabelOpts(is_show=True, font_size='18', color='blue'), # 节点label
            edge_label=opts.LabelOpts(is_show=True, position="middle", # 边label
                font_size='15', formatter="{c}%") # {b} 是默认值:a>b
        )
    .set_global_opts(title_opts=opts.TitleOpts(title="签约大屏漏斗数据"),
        legend_opts=opts.LegendOpts(pos_top="5%",pos_right="15%", orient='vertical')
    )
    #.render("graph_with_options.html")
)
# make_snapshot(driver,g.render("gauge.html"),"gauge.png")

tab = Tab()
tab.add(c, '交互漏斗图')

tab.render(f'可视化-签约大屏城市流量分布{dt_info}.html')
tab.render_notebook()

(4)Mathematica

【2024-7-6】 wolfram 推出的数学软件 Mathematica 直接绘制3D可视化图

散点图

2D散点图

带动画效果:Effectscatter

from pyecharts import options as opts
from pyecharts.charts import EffectScatter
from pyecharts.faker import Faker

c = (
    EffectScatter()
    .add_xaxis(Faker.choose())
    .add_yaxis("", Faker.values())
    .set_global_opts(title_opts=opts.TitleOpts(title="EffectScatter-基本示例"))
    .render("effectscatter_base.html")
)

3D散点图

散点图维度绘制时,注意数轴类型,默认只把Z轴当数值,其余轴当做离散类目处理,因此会出现x、y轴数值失效的情形,此时需要单独设置x和y轴的类型。

代码:适用于1.*以上版本

import random
from pyecharts import options as  opts
#from pyecharts.charts import Scatter # 2D散点图
from pyecharts.charts import Scatter3D
from pyecharts.faker import Faker

N = 50
label = range(N)
# 数据点格式:[x,y,z,label],默认取前面数据当坐标,后面作为其他信息
Scatter_data = [(random.randint(0,N),random.randint(0,N),random.randint(0,N)) for i in range(N)]

c = (
    Scatter3D(init_opts = opts.InitOpts(width='900px',height='600px'))  #初始化
    .add("",Scatter_data,
        xaxis3d_opts=opts.Axis3DOpts(type_='value'), # 3D散点图x轴类型设置
        yaxis3d_opts=opts.Axis3DOpts(type_='value'), # 3D散点图y轴类型设置
        #grid3d_opts=opts.Grid3DOpts(width=100, depth=100, rotate_speed=100, is_rotate=True) # 自动旋转
    )
    #设置全局配置项
    .set_global_opts(
        title_opts=opts.TitleOpts(title="3D散点图"),  #添加标题
        visualmap_opts=opts.VisualMapOpts(
            #type_ = 'color', # 或 'size', 映射维度:颜色或大小
            is_show = True, # 是否显示视觉映射配置
            item_width = 0,# 图形的宽度,即长条的宽度。
            item_height = 0,# 图形的高度,即长条的高度。
            background_color = '#CCCC33',# visualMap 组件的背景色。
            border_color = '#EE1111',# visualMap 组件的边框颜色。
            is_calculable = True,# 是否显示拖拽用的手柄(手柄能拖拽调整选中范围)。
            pos_left = 'center', # 如果 left 的值为'left', 'center', 'right',组件会根据相应的位置自动对齐。
            pos_right = None,
            pos_top = None,
            pos_bottom = None,
            border_width = 2,# visualMap 边框线宽,单位px。
            orient = 'horizontal',# 如何放置 visualMap 组件,水平('horizontal')或者竖直('vertical')。
            min_=0, # visualMapPiecewise 组件的最小值
            max_=50, # visualMapPiecewise 组件的最大值
            pos_top=50, # visualMap 组件离容器上侧的距离
            range_opacity = None,# visualMap 图元以及其附属物(如文字标签)的透明度。range_opacity: Optional[Numeric] = None,
            dimension=2, # 组件映射维度, 如2表示按第三(2+1)个维度取值范围来标颜色
            range_text = ['高', '低'], # 两端的文本,如['High', 'Low'],(自定义) range_text: Union[list, tuple] = None,
            range_size=[10, 40], # 数据点大小
            range_color=Faker.visual_color,  #颜色映射     
            #range_color=["#0b9df0","#00fea8","#00ff0d","#f5f811","#f09a09","#fe0300","#1710c0",]  #颜色映射 
           
            split_number = 5,  # 对于连续型数据,自动平均切分成几段。默认为5段。连续数据的范围需要 max 和 min 来指定
            # 图例区间、数值范围自定义, is_piecewise和pieces配合使用
            #is_piecewise=True,
            pieces=[
                {"max": 1499, "min": 1200, "label": ">=1200", "color": "#B40404"},
                {"max": 1199, "min": 900, "label": "900-1199", "color": "#DF0101"},
                {"max": 899, "min": 600, "label": "600-899", "color": "#F78181"},
                {"max": 599, "min": 300, "label": "300-599", "color": "#F5A9A9"},
                {"max": 299, "min": 0, "label": "0-299", "color": "#FFFFCC"},
            ],
            # 文字样式配置项,参考 `series_options.TextStyleOpts`
            textstyle_opts = None,                                   
        ),
        #xaxis_opts=opts.AxisOpts(type_='value'), # 2D散点图设置数值
        #yaxis_opts=opts.AxisOpts(type_='value'),# 2D散点图设置数值
        #zaxis_opts=opts.AxisOpts(type_='value') # category
    )
)
c.render("3D散点图.html") # 保存到文件
c.render_notebook() # 输出到jupyter notebook页面

效果示例:

【2021-11-11】3D散点图可视化问题:颜色设置,echarts散点图标注颜色设置不起作用?

  • 原因:visualMap 组件控制了 series 中的数据,进行了『视觉编码』,也就是将数据映射到视觉元素(视觉通道)。所以,data中value的值不同,映射后的颜色会改变。
  • 解决:想哪个数据不被控制,就要设置它的visualMap:false
visualMap: {
    show:false,
    min: 0,
    max: 100,
    splitNumber: 5,
    inRange: {
        color: ['#d94e5d','#eac736','#50a3ba'].reverse()
    },
    textStyle: {
        color: '#fff'
    }
},
series: [
{},//地图,这里省略
  {
     type:'effectScatter',
     coordinateSystem: 'geo',
     symbol:'pin',
     symbolSize:15,
     rippleEffect: {
         brushType: 'stroke'
     }, 
     itemStyle:{
        color:'red'
     },                
     // data:[[113.65, 35.76,0]] 颜色是浅蓝色
     // data:[{value:[113.65, 35.76,0],itemStyle : {normal : {color :'red'}}}] 不起作用
     //data:[[113.65, 35.76,100]] //这么写颜色虽然变红了,但不是正宗的红色
     data:[{value:[113.65, 35.76,0],visualMap: false}] //这样写对了
 }]

【2021-11-11】使用pyecharts绘制三维散点图,根据类别使用不同颜色区分数据

自定义点的颜色:聚类结果显示中,需要用颜色区分不同类别

  • 以下代码适用于最新的pyecharts版本,但是生成的效果却无法达到预期目标。具体情况是三个类别的点不在同一个坐标系中!(可以通过坐标轴的数值来判断)
  • pyecharts==0.5的版本最符合我的要求, visualmap的文字没有显示是因为颜色问题,可以加上限制
    • visual_text_color=”#000”
def plot_scatter(X, Y, save_dir): #version 1.5-1.9 
    from pyecharts.charts import Scatter3D, Page
    from pyecharts import options as opts
    from pyecharts.globals import ThemeType
    from pyecharts.render import make_snapshot
    from snapshot_selenium import snapshot
 
    Y = np.expand_dims(Y, 1)
    data = np.concatenate((X,Y),axis=1)
    
    piece=[
      {'value': 0,'label': 'class A','color':'#e57c27'}, 
      {'value': 1, 'label': 'class B','color':'#72a93f'},
      {'value': 2, 'label': 'class C','color':'#368dc4'}
    ]
 
    sc1 = Scatter3D() 
    sc1.add("", data.tolist()) 
    sc1.set_global_opts(title_opts=opts.TitleOpts(title="3D scatter"),
        visualmap_opts=opts.VisualMapOpts(dimension=3,is_piecewise=True, pieces=piece))
    sc1.render(save_dir+'/test.html')
    make_snapshot(snapshot, sc1.render(), save_dir+'/test.png')

数学函数图

Surface_wave

import math
from typing import Union

import pyecharts.options as opts
from pyecharts.charts import Surface3D

"""
Gallery 使用 pyecharts 1.1.0
参考地址: https://echarts.apache.org/examples/editor.html?c=surface-wave&gl=1

目前无法实现的功能:

1、暂时无法设置光滑表面 wireframe
2、暂时无法把 visualmap 进行隐藏
"""


def float_range(start: int, end: int, step: Union[int, float], round_number: int = 2):
    """
    浮点数 range
    :param start: 起始值
    :param end: 结束值
    :param step: 步长
    :param round_number: 精度
    :return: 返回一个 list
    """
    temp = []
    while True:
        if start < end:
            temp.append(round(start, round_number))
            start += step
        else:
            break
    return temp


def surface3d_data():
    for t0 in float_range(-3, 3, 0.05):
        y = t0
        for t1 in float_range(-3, 3, 0.05):
            x = t1
            z = math.sin(x ** 2 + y ** 2) * x / 3.14
            yield [x, y, z]


(
    Surface3D(init_opts=opts.InitOpts(width="1600px", height="800px"))
    .add(
        series_name="",
        shading="color",
        data=list(surface3d_data()),
        xaxis3d_opts=opts.Axis3DOpts(type_="value"),
        yaxis3d_opts=opts.Axis3DOpts(type_="value"),
        grid3d_opts=opts.Grid3DOpts(width=100, height=40, depth=100),
    )
    .set_global_opts(
        visualmap_opts=opts.VisualMapOpts(
            dimension=2,
            max_=1,
            min_=-1,
            range_color=[
                "#313695",
                "#4575b4",
                "#74add1",
                "#abd9e9",
                "#e0f3f8",
                "#ffffbf",
                "#fee090",
                "#fdae61",
                "#f46d43",
                "#d73027",
                "#a50026",
            ],
        )
    )
    .render("surface_wave.html")
)

雷达图

雷达图(Radar Chart),或称为戴布拉图蜘蛛网图参考

  • 图形以一点为中心,每一变量维度为一极坐标轴,n个维度即形成n轴的由内向外放射状图形,形似蜘蛛网。

图形的基本构成如下:

  • 数据点
  • 雷达链
  • 特征标签
  • 半径轴
  • 覆盖域

雷达图的应用特点:

  • ① 同样是属于比较与分布类型,雷达图与柱状图最明显的差异
    • 柱状图在实际场景中通常被用于进行单(多)维度定性数据的可视化,比如一次期中考试,绘制柱状图来对比八个班级的语文平均分;
    • 雷达图常常用于单(多)个体的多维度数据对比,进而呈现并帮助分析对象的优劣处,比如在这次考试中,绘制雷达图来观察二班的语文、数学、英语、生物、化学、物理科目平均分的优良分布。
  • ② 如果遇到多总体,可以使用多幅雷达图,或者单幅雷达图中多层数据线的形式进行总体间对比。
  • ③ 无论是变量特征还是对象总体都不要太多,前者(>10)会使得图像的轴过多,包含信息量过大而弱化了可读性,一眼看去让人感觉很复杂。后者(>5)要么会使得线条交叉密集,要么就是多重覆盖域因附着不同填充色而导致的信息覆盖问题,当然,如果每个总体都是单维突出类型,信息突出效果还是很好的。
  • ④ 雷达图使用的数据是多特征的,会出现一种很常见的情况,比如年龄和收入的量纲或者说取值范围是不一致的。因为雷达图是维度内的粗略对比,我们并不会去根据图形计算一班和二班的数学平均分差究竟是多少,只需要得到二班在这次期中考试中数学比一班考得好的结论就可以,所以为了将各维度数据在一个取值范围内,我们在绘图前会考虑将数据归一化或者标准化。
  • ⑤ 在应用场景上,通常有财务状况综合评价、用户画像、员工评分、医疗症状自评等等

add_schema 负责雷达图的设置:图解

  • schema :指定雷达图的特征标签,每个轴的最大最小取值(方便画点),此前我们已经生成了取值范围的scope【{}】型,直接赋值就行。
  • ② shape、center、radius :
    • shape即雷达图的外轮廓形状,circle圆形为默认值。
    • center为中心的位置,[50%,50%]指的是画布宽50%和高50%的位置,默认画布的宽高数据是900px*500px。。
    • radius是雷达图外圆的半径长度,60%指的是当前画布的宽度和高度中较小者的60%。
  • ③ AngleAxisOpts :角度坐标选项设置
    • min_,max_ 指定角度范围。
    • is_clockwise=False 角度递增的方向是否按照时钟转动(顺时针)的方向。
    • interval 径向轴显示的间隔区间大小值,interval=10表示每隔10°划分径向轴角度。
  • ④ RadiusAxisOpts :径向轴选项设置
  • min_,max_ 同理,设置径向轴的取值范围。
  • interval 用于径向轴上的划分,interval = 5 表示每隔 5 划分径向轴长度。
  • SplitAreaOpts 用来设置我们的间隔区域,is_show=True才会有灰白相间的效果,opacity指的是不透明度,可以取[0,1] , 数值越大颜色越深。
  • ⑤ PolarOpts : 极坐标的设置,我们选择默认值。
  • ⑥ splitline_opt :如果设置为True,增加分割线,变化如下图所示(不显示雷达链,免得遮挡)

绘制雷达链

add()用于一条一条自定义绘制总体的雷达链。

  • series_name :数据序列的名称,即总体名称。在静态图中它不会显示,交互过程中可以看到(如上上图)。
  • data :对应总体的数据list,格式为[{'name':'XX','value':[num,num,num]}],具体参考数据结构。这里需要注意的是,value的长度要和特征维度数一致。
  • areastyle_opts :覆盖域的透明度设置,因为我们这里是五总体,必须要调整填充色的透明度。
  • linestyle_opts : 雷达链的线条宽度设置
  • color :指定不同总体雷达图的颜色,这里可以保证边界和内部填充色一致,而饱和度不同。
  • symbol :设置数据点的形状,默认是空心圆。如果我们以许一的雷达链举例,数据点的形状改为三角形,即在color后面增加symbol = SymbolType.TRIANGLE,得到的结果如下

set_series_opts

  • 用于设置数据序列的显示,只提LabelOpts,对数据序列数值标签的设置,默认is_show是True,多总体情况下数字标签多容易显得很混乱,影响视觉观感

打分信息可视化

from pyecharts import options as opts
from pyecharts.charts import Radar
# [2023-6-5] 注意:每组数据不是简单的list,而是一个元素(数据向量)的数组!
v1 = [(4300, 10000, 28000, 35000, 50000, 19000)]
v2 = [(5000, 14000, 28000, 31000, 42000, 21000)]

p = Radar().add_schema(
            schema=[
                opts.RadarIndicatorItem(name="销售", max_=6500),
                opts.RadarIndicatorItem(name="管理", max_=16000),
                opts.RadarIndicatorItem(name="信息技术", max_=30000),
                opts.RadarIndicatorItem(name="客服", max_=38000),
                opts.RadarIndicatorItem(name="研发", max_=52000),
                opts.RadarIndicatorItem(name="市场", max_=25000),
            ]
        ) \
        .add("预算分配", v1)\
        .add("实际开销", v2)\
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
p.render('radar.html')
p.render_notebook()

应用

  • 效果图:img
# ------- 数据准备 -------
import pandas as pd
data = pd.DataFrame(pd.read_excel('案例数据.xlsx'))
 
# 生成绘图series
data_radar = []
for row in range(data.shape[0]):
    dic = {}
    value = []
    for col in range(1,data.shape[1]):
        value.append(int(data.iloc[row,col]))
    dic['name'],dic['value'] = data['员工'][row],value
    data_radar.append([dic])
 
# 各特征维度取值范围
scope = []
for col in range(1,data.shape[1]):
    dic = {}
    dic['name'] = data.columns[col]
    dic['max'],dic['min'] = max(data.iloc[:,col]),0
    scope.append(dic)

data_radar = [
    [{'name':'许一','value':[22,3,3,7,3,5]}],
    [{'name':'刘二','value':[27,2,4,10,4,3]}],
    [{'name':'张三','value':[30,3,2,5,3,4]}],
    [{'name':'李四','value':[24,5,2,7,3,3]}],
    [{'name':'王五','value':[26,4,5,8,4,1]}]
     ]
# --------------------
from pyecharts import options as opts
from pyecharts.charts import Radar
from pyecharts.commons.utils import JsCode
c = (
      # Radar()
    Radar(init_opts=opts.InitOpts(bg_color={"type": "pattern", "image": JsCode("img"), "repeat": "no-repeat"})) # 加背景图
        .add_js_funcs(    """    var img = new Image();
                          img.src = '背景.jpg';    """)
        .add_schema(
        schema=scope,
        shape="circle",
        center=["50%", "50%"],#宽高:900px*500px
        radius="60%",
        angleaxis_opts=opts.AngleAxisOpts(
            min_=0,
            max_=360,
            is_clockwise=False,
            interval=10,
            axistick_opts=opts.AxisTickOpts(is_show=True),
            axislabel_opts=opts.LabelOpts(is_show=True),
            axisline_opts=opts.AxisLineOpts(is_show=True),
            splitline_opts=opts.SplitLineOpts(is_show=True)
        ),
        radiusaxis_opts=opts.RadiusAxisOpts(
            min_=0,
            max_=30,
            interval=5,
            splitarea_opts=opts.SplitAreaOpts(
                is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
            ),
        ),
        polar_opts=opts.PolarOpts(),
        splitline_opt=opts.SplitLineOpts(is_show=False)
    )
        .add(
        series_name="许一",
        data=data_radar[0],
        areastyle_opts=opts.AreaStyleOpts(opacity=0.2),
        linestyle_opts=opts.LineStyleOpts(width=2),
        color='#fc5a50'
    )
        .add(
        series_name="刘二",
        data=data_radar[1],
        areastyle_opts=opts.AreaStyleOpts(opacity=0.2),
        linestyle_opts=opts.LineStyleOpts(width=2),
        color='#35ad6b'
    )
        .add(
        series_name="张三",
        data=data_radar[2],
        areastyle_opts=opts.AreaStyleOpts(opacity=0.2),
        linestyle_opts=opts.LineStyleOpts(width=2),
        color='#3d7afd'
    )
        .add(
        series_name="李四",
        data=data_radar[3],
        areastyle_opts=opts.AreaStyleOpts(opacity=0.2),
        linestyle_opts=opts.LineStyleOpts(width=2),
        color='#aa23ff'
    )
        .add(
        series_name="王五",
        data=data_radar[4],
        areastyle_opts=opts.AreaStyleOpts(opacity=0.2),
        linestyle_opts=opts.LineStyleOpts(width=2),
        color='#fcb001'
    )
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        .set_global_opts(title_opts=opts.TitleOpts(title = '员工评价',subtitle = '林老头ss',pos_left='left'))
        .render("雷达图示例.html")
)

import pyecharts as pe
# score分值是嵌套数组!
s = {'score':[[]], 'name_cn':[], 'full_score':[]}
for i in data['factor_score']:
    s['score'][0].append(i['score'])
    s['name_cn'].append(i['name_cn'])
    s['full_score'].append(i['ref_score']['full_score'])
print(s)
print(data['total_score']['score'])
print([(s['name_cn'][i],s['full_score'][i],s['score'][i]) for i in range(len(s['score']))])

c = pe.charts.Radar()
opt = pe.options

c.add_schema(
        #schema= [ opt.RadarIndicatorItem(name=s['name_cn'][i], max_=s['full_score'][i]) for i in range(len(s['score']))]
        schema = [
            opt.RadarIndicatorItem(name=s['name_cn'][0], max_=s['full_score'][0]),
            opt.RadarIndicatorItem(name=s['name_cn'][1], max_=s['full_score'][1]),
            opt.RadarIndicatorItem(name=s['name_cn'][2], max_=s['full_score'][2]),
            opt.RadarIndicatorItem(name=s['name_cn'][3], max_=s['full_score'][3]),
            opt.RadarIndicatorItem(name=s['name_cn'][4], max_=s['full_score'][4]),
            opt.RadarIndicatorItem(name=s['name_cn'][5], max_=s['full_score'][5]),
            opt.RadarIndicatorItem(name=s['name_cn'][6], max_=s['full_score'][6]),
            opt.RadarIndicatorItem(name=s['name_cn'][7], max_=s['full_score'][7]),
        ]
    ).add("评分你好", s['score']) \
    .set_series_opts(label_opts=pe.options.LabelOpts(is_show=True))
#.add("预算分配", v1).add("实际开销", v2) \
c.render('radar.html')
c.render_notebook() 

地图数据

pyecharts有地理有几类:

  • (1)Geo:地理坐标可视化,点形式
  • (2)Map:矢量图形式,分成2D和3D
  • (3)BMap:百度地图形式

基础数据:

  • 全球国家地图: echarts-countries-pypkg :世界地图和 213 个国家,包括中国地图
  • 中国省级地图: echarts-china-provinces-pypkg :23 个省,5 个自治区
  • 中国市级地图: echarts-china-cities-pypkg :370 个中国城市
  • 中国县区级地图: echarts-china-counties-pypkg :2882 个中国县、区
  • 中国区域地图: echarts-china-misc-pypkg :11 个中国区域地图,比如华南、华北。

安装:

pip install echarts-countries-pypkg
pip install echarts-china-provinces-pypkg
pip install echarts-china-cities-pypkg
pip install echarts-china-counties-pypkg
pip install echarts-china-misc-pypkg

【2021-8-31】中国地理行政区划数据:省份、城市、区划数据,json格式:

!wget https://github.com/nixing87/area/blob/main/json/all_province_with_adcode_key.json
!wget https://github.com/nixing87/area/blob/main/json/all_city_with_adcode_key.json
  • 各省份信息
省份 简称 省会 东经 北纬
安徽  合肥 117.194778,31.86577
北京    116.403694,39.949459
重庆      116.403694,39.949459
福建    福州 119.292069,26.144144
甘肃    兰州 103.856737,36.094212
广东    广州 113.239359,23.185545
广西    南宁 108.345678,22.861984
贵州    贵阳 106.616332,26.707352
海南    海口 110.350983,19.968035
河北    石家庄 114.508772,38.083783
河南    郑州 113.644099,34.769161
黑龙江  哈尔滨 126.522207,45.801617
湖北    武汉 114.361594,30.601078
湖南    长沙 112.926605,28.217167
吉林    长春 125.326383,43.797768
江苏    南京 118.832137,32.038322
江西    南昌 115.851775,28.672488
辽宁    沈阳 123.486653,41.682522
内蒙古  呼和浩特 111.785972,40.849642
宁夏    银川 106.257585,38.482579
青海    西宁 101.851432,36.622494
山东    济南 117.194778,36.652148
山西    太原 112.595453,37.858034
陕西    西安 109.026378,34.350591
上海      121.518142,31.211845
四川    成都 104.132697,30.561282
天津      117.286764,39.001295
西藏    拉萨 91.144205,29.649484
新疆    乌鲁木齐 87.667116,43.817754
云南    昆明 102.881681,24.866897
浙江    杭州 120.211934,30.274265
香港      114.242011,22.272474
澳门      113.579709,22.169692
台湾    台北 121.591732,25.034634

省份数据抽取

【2021-10-21】cpca库用于提取简体中文字符串中省/市/区信息并能够进行映射,检验和简单绘图的python模块。简单来说就是文本出现的市区名称转换为省份名称。

  • pip install cpca
#!pip install cpca
# cpca是chinese province city area的缩写
# https://github.com/DQinYuan/chinese_province_city_area_mapper
location_str = ["徐汇区虹漕路461号58号楼5楼", "泉州市洛江区万安塘西工业区", "北京朝阳区北苑华贸城"]
import cpca
df = cpca.transform(location_str)
# 显示提取位置,大于-1的部分就代表提取的位置。-1则表明这个字段是靠程序推断出来的,或者没能提取出来。
#df = cpca.transform(location_str, pos_sensitive=True)
df
#   省     市    区          地址              adcode
# 0 上海市 上海市  徐汇区     虹漕路461号58号楼5楼  310104
# 1 福建省 泉州市  洛江区     万安塘西工业区        350504
# 2 北京市 市辖区  朝阳区     北苑华贸城           110105
# ------ 消歧 -------
cpca.transform(["朝阳区汉庭酒店大山子店"])
#     省    市    区        地址  adcode
#0  吉林省  长春市  朝阳区  汉庭酒店大山子店  220104
cpca.transform(["朝阳区汉庭酒店大山子店"],umap={"朝阳区":"110105"})
#     省    市    区        地址  adcode
#0  北京市  市辖区  朝阳区  汉庭酒店大山子店  110105
# ------- 长文本提取 --------
df = cpca.transform_text_with_addrs("分店位于徐汇区虹漕路461号58号楼5楼和泉州市洛江区万安塘西工业区以及南京鼓楼区")

# 自带的绘图工具 folium(速度慢),热力图显示
#pip install folium
from cpca import drawer
#df为上一段代码输出的df
drawer.draw_locations(df, "df.html")
# 改用echarts
#pip install pyecharts==0.5.11
#pip install echarts-countries-pypkg
#pip install pyecharts-snapshot
from cpca import drawer
drawer.echarts_draw(processed[cpca._ADCODE], "echarts.html")
drawer.echarts_cate_draw(processed[cpca._ADCODE], processed["省"], "echarts_cate.html")

平面地图

热力图形式, maptype

  • 国家名:世界各国地图,如:瑞士
  • china: 省
  • china

官方示例

# ---------- 世界地图(瑞士)--------
from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.datasets import register_url

try:
    register_url("https://echarts-maps.github.io/echarts-countries-js/")
except Exception:
    import ssl

    ssl._create_default_https_context = ssl._create_unverified_context
    register_url("https://echarts-maps.github.io/echarts-countries-js/")

geo = (
    Geo()
    .add_schema(maptype="瑞士")
    .set_global_opts(title_opts=opts.TitleOpts(title="瑞士"))
    .render("geo_chart_countries_js.html")
)

# ---------- 中国各省份 --------
from pyecharts import options as opts
from pyecharts.charts import Geo # 地理坐标信息
from pyecharts.faker import Faker
from pyecharts.globals import ChartType # 图表类型

c = (
    Geo()
    .add_schema(maptype="china") # maptype=china(省),maptype="广东",maptype="海淀区"
    .add(
        "geo",
        [list(z) for z in zip(Faker.provinces, Faker.values())],
         # 图表类型,默认静态点
        type_=ChartType.HEATMAP, # 这里设置为热力图
        # type_=ChartType.EFFECT_SCATTER # 波纹点
        label_opts=opts.LabelOpts(), # 显示省份名称
    )
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        visualmap_opts=opts.VisualMapOpts(),
        #visualmap_opts=opts.VisualMapOpts(is_piecewise=True), # 图例自动分段
        title_opts=opts.TitleOpts(title="Geo-HeatMap"),
    )
)
# ---------- 城市地图 --------
from pyecharts import options as opts
from pyecharts.charts import Map
from pyecharts.faker import Faker

table_data = [['北京市',10],['上海市',20]]
# table_data = [[k+'市', v] for (k,v) in city_info.items()]
tmp_data = [[i[0],i[1]] for i in table_data] # [[北京市,10],[上海市,20]]
m = (
    Map(init_opts=opts.InitOpts(width="1440px", height="720px"))
    .add("各城市热度", tmp_data, "china-cities",
        label_opts=opts.LabelOpts(is_show=False),
    )
    .set_global_opts(
        title_opts=opts.TitleOpts(title="各城市PV分布({dt_info})"),
        visualmap_opts=opts.VisualMapOpts(max_=max([i[1] for i in tmp_data]), is_piecewise=True),
        toolbox_opts=opts.ToolboxOpts(is_show=True), # 工具箱
    )
    #.render("map_china_cities.html")
)
# ---------- 区地图 --------
from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.datasets import register_url

try:
    register_url("https://echarts-maps.github.io/echarts-china-counties-js/")
except Exception:
    import ssl

    ssl._create_default_https_context = ssl._create_unverified_context
    register_url("https://echarts-maps.github.io/echarts-china-counties-js/")

geo = (
    Geo()
    .add_schema(maptype="海淀区")
    .set_global_opts(title_opts=opts.TitleOpts(title="海淀区"))
    .render("geo_echart_china_js.html")
)
# ---------- 动态迁移图 --------
from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.globals import ChartType, SymbolType

c = (
    Geo()
    .add_schema(maptype="china")
    .add( # 城市数据
        "",
        [("广州", 55), ("北京", 66), ("杭州", 77), ("重庆", 88)],
        type_=ChartType.EFFECT_SCATTER, # 点展示形式
        color="white",
    )
    .add( # 迁移数据
        "geo",
        [("广州", "上海"), ("广州", "北京"), ("广州", "杭州"), ("广州", "重庆")],
        type_=ChartType.LINES, # 箭头形式展示
        effect_opts=opts.EffectOpts(
            symbol=SymbolType.ARROW, symbol_size=6, color="blue"
        ),
        linestyle_opts=opts.LineStyleOpts(curve=0.2),
    )
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(title_opts=opts.TitleOpts(title="Geo-Lines"))
    .render("geo_lines.html")
)

可视化案例

url_basic = 'https://m.douban.com/rexxar/api/v2/gallery/topic/18306/items?from_web=1&sort=hot&start={}&count=20&status_full_text=1&guest_only=0&ck=GStY'
headers = { 
    'Accept': 'application/json, text/javascript, */*; q=0.01',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Cookie': 'bid=n7vzKfXLoUA; douban-fav-remind=1; ll="108296"; __utmc=30149280; __utmz=30149280.1624276858.2.2.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); ap_v=0,6.0; gr_user_id=ca8b9156-1926-4c82-9dda-27fc7f7ad51b; __utma=30149280.66080894.1623848440.1624276858.1624282580.3; __utmt=1; dbcl2="157316158:e4ojS8paSUc"; ck=GStY; push_doumail_num=0; __utmv=30149280.15731; frodotk="a187943e3a17e8bbe496bcbaae47ba31"; push_noty_num=0; __utmb=30149280.11.10.1624282580',
    'Host': 'm.douban.com',
    'Origin': 'https://www.douban.com',
    'Referer': 'https://www.douban.com/gallery/topic/18306/',
    'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
    'sec-ch-ua-mobile': '?0',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36'
}
# 获取地理位置信息
for i in range(1,35):
  res = requests.get(url=url_basic.format(i * 20), headers=headers)
  res_json = json.loads(res.text)
  index = 0
  for item in res_json.get('items'):
    target = item.get('target')
    status = target.get('status')
    print("这里是第 {} 个".format((i - 1) * 20 + index));
    index = index + 1
    with open('douban.txt', 'a+') as f:
      f.write(json.dumps(status) + '\n');  
  sleeptime=random.randint(1, 10)
  time.sleep(sleeptime)
# ---------- 下载图片信息 -----------
for line in file_object:
    item = json.loads(line)
    if item == None:
        continue
    images = item['images']
    id = item['id']

    index = 0
    for i in images:
        index = index + 1
        url = i.get('large').get('url')
        r = requests.get(url);
        with open('./image/{}-{}.jpg'.format(id, index), 'wb') as f:
            f.write(r.content) 

# --------- 地图可视化 --------------
from pyecharts.charts import Geo
from pyecharts.globals import ChartType

addr_dic = {}
file_object = open('douban.txt','r')
try:
    for line in file_object:
        item = json.loads(line)
        if item == None:
            continue
        author = item['author']
        text = item['text']
        addr_transform = cpca.transform([text])
        addr = None

        if addr_transform['省'].str.split(' ')[0] != None:
            addr = addr_transform['省'].str.split(' ')[0][0].rstrip('省')
        #这里提取创作者里面的地址
        if addr is None and author['loc'] is not None:
            cpca.transform([author['loc']['name']])

            if addr_transform['省'].str.split(' ')[0] != None:
                addr = addr_transform['省'].str.split(' ')[0][0].rstrip('省')
        #这个地址要转换一下,不然 echarts 不认
        if addr is not None:
            if addr == '广西壮族自治区':
                addr = '广西'
            if addr == '香港特别行政区':
                addr = '香港'
            if addr == '澳门特别行政区':
                addr = '澳门'
        addr_dic[addr] = addr_dic.get(addr, 0) + 1

finally:
    file_object.close()

# 小姐姐热力图
(
    Geo()
    .add_schema(maptype="china")
    .add(
        "",
        [list(z) for z in zip(list(addr_dic.keys()), list(addr_dic.values()))],
        type_=ChartType.HEATMAP,
    )
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        visualmap_opts=opts.VisualMapOpts(),
    ).render("热力图.html")
  )

二维显示

  • 平面显示

【2023-1-4】数据加工: 直接根据字符串转城市数据

city_str = '''
上海	3449
苏州	1127
南京	1353
镇江	220
无锡	571
常州	447
徐州	166
盐城	186
南通	309
扬州	176
连云港	131
淮安	173
宿迁	64
泰州	122
大连	231
北京	642
石家庄	321
保定	251
邢台	39
邯郸	23
衡水	39
沈阳	580
通辽	47
天津	1629
唐山	193
秦皇岛	44
廊坊	185
沧州	35
哈尔滨	413
长春	525
深圳	720
广州	553
佛山	574
南宁	436
北海	86
桂林	124
贵港	38
柳州	114
海口	112
三亚	49
昆明	651
大理	33
贵阳	375
遵义	45
厦门	452
泉州	471
漳州	155
三明	41
南平	33
清远	139
惠州	453
东莞	435
河源	43
汕头	44
珠海	307
中山	258
肇庆	112
湛江	283
茂名	128
江门	97
阳江	21
烟台	184
青岛	965
威海	204
潍坊	162
临沂	159
济南	796
济宁	114
聊城	70
泰安	116
德州	71
菏泽	65
淄博	258
滨州	51
郑州	291
洛阳	129
许昌	69
南阳	152
信阳	66
濮阳	54
焦作	58
新乡	90
合肥	814
六安	114
蚌埠	82
淮北	63
宿州	104
阜阳	114
杭州	902
武汉	621
襄阳	138
荆门	18
荆州	81
十堰	168
宜昌	76
南昌	287
九江	69
赣州	111
上饶	64
长沙	617
岳阳	61
株洲	49
衡阳	102
湘潭	78
湖州	102
嘉兴	274
绍兴	98
宁波	415
金华	239
台州	177
温州	245
重庆	899
张家口	66
呼和浩特	116
太原	306
包头	68
大同	16
运城	102
西安	643
咸阳	50
渭南	70
宝鸡	90
乌鲁木齐	96
银川	141
西宁	44
成都	1810
资阳	71
眉山	61
宜宾	48
乐山	70
绵阳	123
南充	105
自贡	109
德阳	103
'''
city_info = {}
city_info = {}
for line in city_str.split('\n'):
    tmp = line.split('\t')
    if len(tmp) < 2:
        print('异常数据:', line)
        continue
    # 加“市”字,注意,少数市不以市结尾
    city_info[tmp[0]+'市'] = int(tmp[1])
city_info
全国地图——省份
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.charts import Map#主题

# 省会及直辖市
data = [['江苏', 492], ['安徽', 830], ['湖南', 879], ['河南', 1073], ['浙江', 1092], ['广东', 1151], ['天津', 94], ['内蒙古', 58],
    ['北京', 337], ['陕西', 213], ['广西', 210], ['宁夏', 49], ['贵州', 109], ['上海', 295], ['江西', 771], ['福建', 261],
    ['新疆', 49], ['四川', 405], ['云南', 141], ['海南', 136], ['山东', 459], ['吉林', 80], ['黑龙江', 331], ['河北', 218],
    ['香港', 36], ['重庆', 468], ['山西', 119], ['甘肃', 83], ['湖北', 29631], ['辽宁', 107], ['台湾', 18], ['澳门', 10],
    ['青海', 18], ['西藏', 1]]

# 方法一 设置地图参数
map = (
    Map(init_opts=opts.InitOpts(bg_color="#FFFAFA", theme=ThemeType.ESSOS,width=1000))
        .add("确诊人数", data)
        .set_global_opts(
        title_opts=opts.TitleOpts(title="fungis-基于丁香园数据的疫情图"),
        # visualmap_opts=opts.VisualMapOpts(max_=2000),#使用系统默认label,最大区间值,因图而异
        visualmap_opts=opts.VisualMapOpts( # 定制label区间、名称
            is_piecewise=True,  # 设置是否为分段显示
            # 自定义的每一段的范围,以及每一段的文字,以及每一段的特别的样式。例如:
            pieces=[
                {"min": 2000, "label": '>2000人', "color": "#eb2f06"},
                {"min": 1000, "max": 2000, "label": '1001-2000人', "color": "#FF3030"},  # 不指定 max,表示 max 为无限大(Infinity)。
                {"min": 500, "max": 1000, "label": '500-1000人', "color": "#FF4500"},
                {"min": 100, "max": 499, "label": '100-499人', "color": "#FF7F50"},
                {"min": 10, "max": 99, "label": '10-99人', "color": "#FFA500"},
                {"min": 1, "max": 9, "label": '1-9人', "color": "#FFDEAD"},
            ],
            # 两端的文本,如['High', 'Low']。
            range_text=['高', '低'],
        )
    )
)
map.render(path="./html/中国疫情人数区间地图1.html")
城市区县地图

全国一共372个城市

from pyecharts.charts import Map
from pyecharts import options as opts
from pyecharts.globals import ThemeType  # 主题

# 各个城市相关数据
data = [['信阳市', 220], ['南阳市', 134], ['郑州市', 130], ['驻马店市', 123], ['商丘市', 83], ['周口市', 65], ['平顶山市', 52], ['新乡市', 46],
        ['安阳市', 45], ['许昌市', 31], ['漯河市', 30], ['洛阳市', 27], ['焦作市', 25], ['开封市', 24], ['鹤壁市', 17], ['濮阳市', 10],
        ['三门峡市', 7], ['济源市', 4]]
cityName = ['信阳市', '南阳市', '郑州市', '驻马店市', '商丘市', '周口市', '平顶山市', '新乡市', '安阳市', '许昌市', '漯河市', '洛阳市', '焦作市', '开封市', '鹤壁市',
            '濮阳市', '三门峡市', '济源市']
confirmedCount = [220, 134, 130, 123, 83, 65, 52, 46, 45, 31, 30, 27, 25, 24, 17, 10, 7, 4]
curedCount = [28, 28, 34, 14, 9, 11, 12, 6, 10, 2, 6, 2, 1, 1, 3, 0, 3, 0]
deadCount = [0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

map = (
    # 初始化配置项中可以设置画布宽高,背景色和主题
    Map(init_opts=opts.InitOpts(bg_color="#FFFAFA", theme=ThemeType.ROMANTIC, width=1000))
        .add("确诊人数", data, "河南", is_map_symbol_show=False, 
            # 【2021-9-1】地图上显示数值
            label_opts=opts.LabelOpts(
                is_show=True,
                formatter=JsCode("function(data){return data.value;}"),
            ),
        )  # 设置是否显示地图上的小红点
        .set_global_opts(
        # 标题配置项,pos_left可取值center、left、right、5%等等
        title_opts=opts.TitleOpts(title="河南疫情确诊人数分布图-fungis", pos_left="left"),
        visualmap_opts=opts.VisualMapOpts(
            is_piecewise=True,  # 设置是否为分段显示
            # 自定义的每一段的范围,以及每一段的文字,以及每一段的特别的样式。例如:
            pieces=[
                {"min": 201, "label": '>200人', "color": "#e55039"},  # 不指定 max,表示 max 为无限大(Infinity)。
                {"min": 101, "max": 200, "label": '101-200人', "color": "#FF4500"},
                {"min": 51, "max": 100, "label": '51-100人', "color": "#FF7F50"},
                {"min": 10, "max": 50, "label": '10-50人', "color": "#FFA500"},
                {"min": 1, "max": 9, "label": '1-9人', "color": "#FFDEAD"},
            ],
            # 两端的文本,如['High', 'Low']。
            range_text=['高', '低'],
        ),
    )
)
map.render(path="./河南疫情确诊人数分布图1.html")
世界地图

世界地图

  • 国家名用英文
from pyecharts import options as opts
from pyecharts.charts import Map
from pyecharts.faker import Faker

c = (
    Map(init_opts=opts.InitOpts(width="1400px", height="1000px"))
    .add("商家A", [list(z) for z in zip(Faker.country, Faker.values())], "world")
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title="Map-世界地图"),
        visualmap_opts=opts.VisualMapOpts(max_=200),
    )
    .render("map_world.html")
)

提供sql,csv,json格式的世界位置信息数据下载,包含洲,国家,省份(州),区(市),县,美国又分了几大区域,提供中文,英文,编码等相关信息,各级关系链式存储。

# 世界国家中英文对照表
country_map = {
"Afghanistan":"阿富汗",
"Aland Islands":"奥兰群岛",
"Albania":"阿尔巴尼亚",
"Algeria":"阿尔及利亚",
"American Samoa":"美属萨摩亚",
"Andorra":"安道尔",
"Angola":"安哥拉",
"Anguilla":"安圭拉",
"Antigua and Barbuda":"安提瓜和巴布达",
"Argentina":"阿根廷",
"Armenia":"亚美尼亚",
"Aruba":"阿鲁巴",
"Australia":"澳大利亚",
"Austria":"奥地利",
"Azerbaijan":"阿塞拜疆",
"Bangladesh":"孟加拉",
"Bahrain":"巴林",
"Bahamas":"巴哈马",
"Barbados":"巴巴多斯",
"Belarus":"白俄罗斯",
"Belgium":"比利时",
"Belize":"伯利兹",
"Benin":"贝宁",
"Bermuda":"百慕大",
"Bhutan":"不丹",
"Bolivia":"玻利维亚",
"Bosnia and Herzegovina":"波斯尼亚和黑塞哥维那",
"Botswana":"博茨瓦纳",
"Bouvet Island":"布维岛",
"Brazil":"巴西",
"Brunei":"文莱",
"Bulgaria":"保加利亚",
"Burkina Faso":"布基纳法索",
"Burundi":"布隆迪",
"Cambodia":"柬埔寨",
"Cameroon":"喀麦隆",
"Canada":"加拿大",
"Cape Verde":"佛得角",
"Central African Republic":"中非",
"Chad":"乍得",
"Chile":"智利",
"Christmas Islands":"圣诞岛",
"Cocos (keeling) Islands":"科科斯(基林)群岛",
"Colombia":"哥伦比亚",
"Comoros":"科摩罗",
"Congo (Congo-Kinshasa)":"刚果(金)",
"Congo":"刚果",
"Cook Islands":"库克群岛",
"Costa Rica":"哥斯达黎加",
"Cote D’Ivoire":"科特迪瓦",
"China":"中国",
"Croatia":"克罗地亚",
"Cuba":"古巴",
"Czech":"捷克",
"Cyprus":"塞浦路斯",
"Denmark":"丹麦",
"Djibouti":"吉布提",
"Dominica":"多米尼加",
"East Timor":"东帝汶",
"Ecuador":"厄瓜多尔",
"Egypt":"埃及",
"Equatorial Guinea":"赤道几内亚",
"Eritrea":"厄立特里亚",
"Estonia":"爱沙尼亚",
"Ethiopia":"埃塞俄比亚",
"Faroe Islands":"法罗群岛",
"Fiji":"斐济",
"Finland":"Finland",
"France":"法国",
"Franch Metropolitan":"法国大都会",
"Franch Guiana":"法属圭亚那",
"French Polynesia":"法属波利尼西亚",
"Gabon":"加蓬",
"Gambia":"冈比亚",
"Georgia":"格鲁吉亚",
"Germany":"德国",
"Ghana":"加纳",
"Gibraltar":"直布罗陀",
"Greece":"希腊",
"Grenada":"格林纳达",
"Guadeloupe":"瓜德罗普岛",
"Guam":"关岛",
"Guatemala":"危地马拉",
"Guernsey":"根西岛",
"Guinea-Bissau":"几内亚比绍",
"Guinea":"几内亚",
"Guyana":"圭亚那",
"Hong Kong":"香港 (中国)",
"Haiti":"海地",
"Honduras":"洪都拉斯",
"Hungary":"匈牙利",
"Iceland":"冰岛",
"India":"印度",
"Indonesia":"印度尼西亚",
"Iran":"伊朗",
"Iraq":"伊拉克",
"Ireland":"爱尔兰",
"Isle of Man":"马恩岛",
"Israel":"以色列",
"Italy":"意大利",
"Jamaica":"牙买加",
"Japan":"日本",
"Jersey":"泽西岛",
"Jordan":"约旦",
"Kazakhstan":"哈萨克斯坦",
"Kenya":"肯尼亚",
"Kiribati":"基里巴斯",
"Korea (South)":"韩国",
"Korea (North)":"朝鲜",
"Kuwait":"科威特",
"Kyrgyzstan":"吉尔吉斯斯坦",
"Laos":"老挝",
"Latvia":"拉脱维亚",
"Lebanon":"黎巴嫩",
"Lesotho":"莱索托",
"Liberia":"利比里亚",
"Libya":"利比亚",
"Liechtenstein":"列支敦士登",
"Lithuania":"立陶宛",
"Luxembourg":"卢森堡",
"Macau":"澳门(中国)",
"Macedonia":"马其顿",
"Malawi":"马拉维",
"Malaysia":"马来西亚",
"Madagascar":"马达加斯加",
"Maldives":"马尔代夫",
"Mali":"马里",
"Malta":"马耳他",
"Marshall Islands":"马绍尔群岛",
"Martinique":"马提尼克岛",
"Mauritania":"毛里塔尼亚",
"Mauritius":"毛里求斯",
"Mayotte":"马约特",
"Mexico":"墨西哥",
"Micronesia":"密克罗尼西亚",
"Moldova":"摩尔多瓦",
"Monaco":"摩纳哥",
"Mongolia":"蒙古",
"Montenegro":"黑山",
"Montserrat":"蒙特塞拉特",
"Morocco":"摩洛哥",
"Mozambique":"莫桑比克",
"Myanmar":"缅甸",
"Namibia":"纳米比亚",
"Nauru":"瑙鲁",
"Nepal":"尼泊尔",
"Netherlands":"荷兰",
"New Caledonia":"新喀里多尼亚",
"New Zealand":"新西兰",
"Nicaragua":"尼加拉瓜",
"Niger":"尼日尔",
"Nigeria":"尼日利亚",
"Niue":"纽埃",
"Norfolk Island":"诺福克岛",
"Norway":"挪威",
"Oman":"阿曼",
"Pakistan":"巴基斯坦",
"Palau":"帕劳",
"Palestine":"巴勒斯坦",
"Panama":"巴拿马",
"Papua New Guinea":"巴布亚新几内亚",
"Paraguay":"巴拉圭",
"Peru":"秘鲁",
"Philippines":"菲律宾",
"Pitcairn Islands":"皮特凯恩群岛",
"Poland":"波兰",
"Portugal":"葡萄牙",
"Puerto Rico":"波多黎各",
"Qatar":"卡塔尔",
"Reunion":"留尼汪岛",
"Romania":"罗马尼亚",
"Rwanda":"卢旺达",
"Russian Federation":"俄罗斯联邦",
"Saint Helena":"圣赫勒拿",
"Saint Kitts-Nevis":"圣基茨和尼维斯",
"Saint Lucia":"圣卢西亚",
"Saint Vincent and the Grenadines":"圣文森特和格林纳丁斯",
"El Salvador":"萨尔瓦多",
"Samoa":"萨摩亚",
"San Marino":"圣马力诺",
"Sao Tome and Principe":"圣多美和普林西比",
"Saudi Arabia":"沙特阿拉伯",
"Senegal":"塞内加尔",
"Seychelles":"塞舌尔",
"Sierra Leone":"塞拉利昂",
"Singapore":"新加坡",
"Serbia":"塞尔维亚",
"Slovakia":"斯洛伐克",
"Slovenia":"斯洛文尼亚",
"Solomon Islands":"所罗门群岛",
"Somalia":"索马里",
"South Africa":"南非",
"Spain":"西班牙",
"Sri Lanka":"斯里兰卡",
"Sudan":"苏丹",
"Suriname":"苏里南",
"Swaziland":"斯威士兰",
"Sweden":"瑞典",
"Switzerland":"瑞士",
"Syria":"叙利亚",
"Tajikistan":"塔吉克斯坦",
"Tanzania":"坦桑尼亚",
"Taiwan":"台湾 (中国)",
"Thailand":"泰国",
"Trinidad and Tobago":"特立尼达和多巴哥",
"Timor-Leste":"东帝汶",
"Togo":"多哥",
"Tokelau":"托克劳",
"Tonga":"汤加",
"Tunisia":"突尼斯",
"Turkey":"土耳其",
"Turkmenistan":"土库曼斯坦",
"Tuvalu":"图瓦卢",
"Uganda":"乌干达",
"Ukraine":"乌克兰",
"United Arab Emirates":"阿拉伯联合酋长国",
"United Kingdom":"英国",
"United States":"美国",
"Uruguay":"乌拉圭",
"Uzbekistan":"乌兹别克斯坦",
"Vanuatu":"瓦努阿图",
"Vatican City":"梵蒂冈",
"Venezuela":"委内瑞拉",
"Vietnam":"越南",
"Wallis and Futuna":"瓦利斯群岛和富图纳群岛",
"Western Sahara":"西撒哈拉",
"Yemen":"也门",
"Yugoslavia":"南斯拉夫",
"Zambia":"赞比亚",
"Zimbabwe":"津巴布韦"
}

country_map_ch2en = dict(zip(country_map.values(), country_map.keys()))

bot_pv_sample_str = """
牙买加	104	1	104
基里巴斯	23	1	23
利比亚	19	1	19
肯尼亚	15	1	15
印度	45	3	15
马来西亚	17,685	1,420	12.4500
美国	556	58	9.5900
摩洛哥	19	2	9.5000
菲律宾	60,353	6,708	9
厄瓜多尔	345	40	8.6300
沙特阿拉伯	1,526	183	8.3400
西班牙	8	1	8
日本	946	121	7.8200
危地马拉	23	3	7.6700
印度尼西亚	91,182	12,038	7.5700
孟加拉国	68	9	7.5600
巴西	4,441	589	7.5400
文莱	22	3	7.3300
伊拉克	7	1	7
NULL	1,437	222	6.4700
玻利维亚	211	33	6.3900
韩国	341	55	6.2000
墨西哥	14,912	2,434	6.1300
智利	1,805	297	6.08000
以色列	6	1	6
巴基斯坦	6	1	6
加纳	12	2	6
新加坡	523	88	5.9400
阿根廷	13,816	2,359	5.8600
洪都拉斯	11	2	5.5000
泰国	1,217	227	5.3600
秘鲁	18,537	3,541	5.2300
英国	3	2	1.5000
尼加拉瓜	1	1	1
阿尔及利亚	1	1	1
意大利	1	1	1
"""
# [国家, 会话轮数, 会话个数, 平均会话轮数]
bot_pv_sample = [ i.split('\t') for i in bot_pv_sample_str.replace(',', '').split('\n') if i!='']
bot_pv_sample

from pyecharts import options as opts
from pyecharts.charts import Map
#from pyecharts.faker import Faker

# 世界地图数据
country = [country_map_ch2en[i[0]] for i in bot_pv_sample if i[0] in country_map_ch2en]
value = [int(i[1]) for i in bot_pv_sample if i[0] in country_map_ch2en]

c = (
    Map(init_opts=opts.InitOpts(width="1400px", height="1000px"))
    #.add("会话轮数", [i[:2] for i in bot_pv_sample if i[0] in country_map_ch2en], "world")
    .add("会话轮数", [list(z) for z in zip(country, value)], "world")
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title="Map-世界地图"),
        visualmap_opts=opts.VisualMapOpts(max_=max(value)),
    )
    .render("map_world.html")
)

三维显示

利用Python绘制酷炫的3D地图

坐标点数据
from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.faker import Faker

c = (
    Geo()
    .add_schema(maptype="china")
    .add("geo", [list(z) for z in zip(Faker.provinces, Faker.values())])
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        visualmap_opts=opts.VisualMapOpts(), title_opts=opts.TitleOpts(title="Geo-基本示例")
    )
    #.render("geo_base.html")
)
c.render_notebook()
3D全国地图

包含34个省市自治区数据

from pyecharts import options as opts
from pyecharts.charts import Map3D
from pyecharts.globals import ChartType
from pyecharts.commons.utils import JsCode
 
example_data = [
    ("北京", [116.4036, 39.9494, 100]),
    ("黑龙江", [127.9688, 45.368, 100]),
    ("内蒙古", [110.3467, 41.4899, 300]),
    ("吉林", [125.8154, 44.2584, 300]),
    ("辽宁", [123.1238, 42.1216, 300]),
    ("河北", [114.4995, 38.1006, 300]),
    ("天津", [117.4219, 39.4189, 300]),
    ("山西", [112.3352, 37.9413, 300]),
    ("陕西", [109.1162, 34.2004, 300]),
    ("甘肃", [103.5901, 36.3043, 300]),
    ("宁夏", [106.3586, 38.1775, 300]),
    ("青海", [101.4038, 36.8207, 300]),
    ("新疆", [87.9236, 43.5883, 300]),
    ("西藏", [91.11, 29.97, 300]),
    ("四川", [103.9526, 30.7617, 300]),
    ("重庆", [108.384366, 30.439702, 300]),
    ("山东", [117.1582, 36.8701, 300]),
    ("河南", [113.4668, 34.6234, 300]),
    ("江苏", [118.8062, 31.9208, 300]),
    ("安徽", [117.29, 32.0581, 300]),
    ("湖北", [114.3896, 30.6628, 300]),
    ("浙江", [119.5313, 29.8773, 300]),
    ("福建", [119.4543, 25.9222, 300]),
    ("江西", [116.0046, 28.6633, 300]),
    ("湖南", [113.0823, 28.2568, 300]),
    ("贵州", [106.6992, 26.7682, 300]),
    ("广西", [108.479, 23.1152, 300]),
    ("海南", [110.3893, 19.8516, 300]),
    ("上海", [121.4648, 31.2891, 300]),
    ("云南", [102.8816, 24.8668, 100]), # 昆明
    ("广东", [121.4648, 31.2891, 100]), # 广州
    ("香港", [114.2420, 22.2724, 100]),
    ("澳门", [113.5797, 22.1696, 100]),
    ("台湾", [121.5917, 25.0346, 100]), # 台北
]
 
c = (
    Map3D(init_opts=opts.InitOpts(width="1400px", height="700px"))
    .add_schema(
        itemstyle_opts=opts.ItemStyleOpts(
            color="rgb(5,101,123)",
            opacity=1,
            border_width=0.8,
            border_color="rgb(62,215,213)",
        ),
        map3d_label=opts.Map3DLabelOpts(
            is_show=False,
            formatter=JsCode("function(data){return data.name + " " + data.value[2];}"),
        ),
        emphasis_label_opts=opts.LabelOpts(
            is_show=False,
            color="#fff",
            font_size=10,
            background_color="rgba(0,23,11,0)",
        ),
        light_opts=opts.Map3DLightOpts(
            main_color="#fff",
            main_intensity=1.2,
            main_shadow_quality="high",
            is_main_shadow=False,
            main_beta=10,
            ambient_intensity=0.3,
        ),
    )
    .add(
        series_name="柱形图数据",
        data_pair=example_data,
        type_=ChartType.BAR3D, # 柱形图显示
        # type_=ChartType.SCATTER3D, # 散点图显示
        bar_size=1,
        shading="lambert",
        label_opts=opts.LabelOpts(
            is_show=False,
            formatter=JsCode("function(data){return data.name + ' ' + data.value[2];}"),
        ),
    )
    .set_global_opts(title_opts=opts.TitleOpts(title="城市数据"))
)
c.render("带有数据展示地图.html")
c.render_notebook()
世界地图-3D
import pyecharts.options as opts
from pyecharts.charts import MapGlobe
from pyecharts.faker import POPULATION
 
data = [x for _, x in POPULATION[1:]]
low, high = min(data), max(data)
 
c = (
    MapGlobe(init_opts=opts.InitOpts(width="1400px", height="700px"))
    .add_schema()
    .add(
        maptype="world",
        series_name="World Population",
        data_pair=POPULATION[1:],
        is_map_symbol_show=False,
        label_opts=opts.LabelOpts(is_show=False),
    )
    .set_global_opts(
        visualmap_opts=opts.VisualMapOpts(
            min_=low,
            max_=high,
            range_text=["max", "min"],
            is_calculable=True,
            range_color=["lightskyblue", "yellow", "orangered"],
        )
    )
)
c.render("地球.html")
#c.render_notebook()

三维数据函数可视化

示例:

import math
from typing import Union

import pyecharts.options as opts
from pyecharts.charts import Surface3D

"""
Gallery 使用 pyecharts 1.1.0
参考地址: https://echarts.apache.org/examples/editor.html?c=surface-wave&gl=1

目前无法实现的功能:

1、暂时无法设置光滑表面 wireframe
2、暂时无法把 visualmap 进行隐藏
"""


def float_range(start: int, end: int, step: Union[int, float], round_number: int = 2):
    """
    浮点数 range
    :param start: 起始值
    :param end: 结束值
    :param step: 步长
    :param round_number: 精度
    :return: 返回一个 list
    """
    temp = []
    while True:
        if start < end:
            temp.append(round(start, round_number))
            start += step
        else:
            break
    return temp


def surface3d_data():
    for t0 in float_range(-3, 3, 0.05):
        y = t0
        for t1 in float_range(-3, 3, 0.05):
            x = t1
            z = math.sin(x ** 2 + y ** 2) * x / 3.14
            yield [x, y, z]


(
    Surface3D(init_opts=opts.InitOpts(width="1600px", height="800px"))
    .add(
        series_name="",
        shading="color",
        data=list(surface3d_data()),
        xaxis3d_opts=opts.Axis3DOpts(type_="value"),
        yaxis3d_opts=opts.Axis3DOpts(type_="value"),
        grid3d_opts=opts.Grid3DOpts(width=100, height=40, depth=100),
    )
    .set_global_opts(
        visualmap_opts=opts.VisualMapOpts(
            dimension=2,
            max_=1,
            min_=-1,
            range_color=[
                "#313695",
                "#4575b4",
                "#74add1",
                "#abd9e9",
                "#e0f3f8",
                "#ffffbf",
                "#fee090",
                "#fdae61",
                "#f46d43",
                "#d73027",
                "#a50026",
            ],
        )
    )
    .render("surface_wave.html")
)

词云

【2022-1-21】词云可视化效果展示,包含静态、动态三维词云

WordCloud.add() 方法简介

add(name,attr,value,
shape="circle",
word_gap=20,
word_size_range=None,
rotate_step=45)
# -----------
name str # 图例名称
attr list # 属性名称
value list # 属性所对应的值
shape # 词云图轮廓 对应属性可选'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
word_gap int # 单词间隔, 字符间隔默认为20
word_size_range # 单词字体大小范围, 字符范围默认为[12,60]
rotate_step int # 旋转角度默认为45

pyecharts绘制词云图

关键词可视化

直接根据关键词信息绘制词云

# import pyecharts as pe
from pyecharts.charts import Tab
from pyecharts.charts import WordCloud

all_info = {'tag':{'美国生活': 2, '移民': 2}, 'to':{'三源英华郡': 2, '十堰广润锦绣华府': 1}}

tab = Tab()

w1 = WordCloud()
test_data = list(all_info['tag'].items())
#test_data = [['a',3],['b',10]]
w1.add(series_name="房源测评-话题分布", data_pair=test_data)
# 【2023-5-11】注意:上界不能只是+1,需要留一定空间
tab.add(w1, "话题分布")

w2 = WordCloud()
test_data = list(all_info['tag'].items())
#test_data = [['a',3],['b',10]]
w2.add(series_name="房源测评-提醒人分布", data_pair=test_data)
tab.add(w2, "提醒人分布")

tab.render('词云.html')
tab.render_notebook()

文本关键词可视化

# -------- 词云可视化 ----------
import jieba
from collections import Counter
from pyecharts.charts import WordCloud

for line in file_object:
    item = json.loads(line)
    if item == None:
        continue
    text = item['text']

    seg_list = jieba.cut(text, cut_all=False)
    text_list.extend(seg_list)

# 词频统计,使用Count计数方法
words_counter = Counter(text_list)
# 将Counter类型转换为列表
words_list = words_counter.most_common(500)
(
    WordCloud()
    .add(series_name="", data_pair=words, word_size_range=[20, 66])
    .render("词云.html")
)

分页混合

overlap 重叠

  • 方法:
    • 旧版的import overlap
    • 新版直接调用overlap方法即可
  • 代码: overlap_bar_line.py
  • 示例:折线图于散点图重叠
from pyecharts import options as opts
from pyecharts.charts import Bar, Line
from pyecharts.faker import Faker

v1 = [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
v2 = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
v3 = [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]

bar = (
    Bar()
    .add_xaxis(Faker.months)
    .add_yaxis("蒸发量", v1)
    .add_yaxis("降水量", v2)
    .extend_axis(
        yaxis=opts.AxisOpts(
            axislabel_opts=opts.LabelOpts(formatter="{value} °C"), interval=5
        )
    )
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title="Overlap-bar+line"),
        yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} ml")),
    )
)

line = Line().add_xaxis(Faker.months).add_yaxis("平均温度", v3, yaxis_index=1)
bar.overlap(line) # 表格重叠
#bar.render("overlap_bar_line.html")
bar.render_notebook()

折线图于散点图重叠

from pyecharts import options as opts
from pyecharts.charts import Line, Scatter
from pyecharts.faker import Faker

x = Faker.choose()
line = (
    Line()
    .add_xaxis(x)
    .add_yaxis("商家A", Faker.values())
    .add_yaxis("商家B", Faker.values())
    .set_global_opts(title_opts=opts.TitleOpts(title="Overlap-line+scatter"))
)
scatter = (
    Scatter()
    .add_xaxis(x)
    .add_yaxis("商家A", Faker.values())
    .add_yaxis("商家B", Faker.values())
)
line.overlap(scatter)
line.render("overlap_line_scatter.html")

Grid 网格组装

定义一个Grid示例,依次加入子图,设置位置(opts.GridOpts)

水平/垂直组装

Grid_vertical

from pyecharts import options as opts
from pyecharts.charts import Bar, Grid, Line
from pyecharts.faker import Faker

bar = (
    Bar()
    .add_xaxis(Faker.choose())
    .add_yaxis("商家A", Faker.values())
    .add_yaxis("商家B", Faker.values())
    .set_global_opts(title_opts=opts.TitleOpts(title="Grid-Bar"))
)
line = (
    Line()
    .add_xaxis(Faker.choose())
    .add_yaxis("商家A", Faker.values())
    .add_yaxis("商家B", Faker.values())
    .set_global_opts(
        title_opts=opts.TitleOpts(title="Grid-Line", pos_top="48%"),
        legend_opts=opts.LegendOpts(pos_top="48%"),
    )
)

grid = (
    Grid()
    # ----- 垂直组装 ------
    .add(bar, grid_opts=opts.GridOpts(pos_bottom="60%"))
    .add(line, grid_opts=opts.GridOpts(pos_top="60%"))
    # ----- 水平组装 -------
    #.add(scatter, grid_opts=opts.GridOpts(pos_left="55%")) 
    #.add(line, grid_opts=opts.GridOpts(pos_right="55%"))
    .render("grid_vertical.html")
)

多Y轴

Grid_multi_yaxis

Tab页

  • 【2021-8-21】多种图类型分布在一个页面的多个tab页
import pyecharts.options as opts
from pyecharts.charts import Bar, Pie, Page, Tab
from pyecharts.components import Table

# 示例数据
train_list = [['NLU00000',
  '还有双鸭山到淮阴的汽车票吗13号的',
  'Travel-Query',
  'destination:淮阴+departure:双鸭山+datetime_date:13号+query_type:汽车票'],
 ['NLU00001', '从这里怎么回家', 'Travel-Query', 'destination:家+query_type:导航'],
 ['NLU00002', '随便播放一首专辑阁楼里的佛里的歌', 'Music-Play', 'album:阁楼+play_mode:随机播放'],
 ['NLU00003', '给看一下墓王之王嘛', 'FilmTele-Play', 'name:墓王之王'],
 ['NLU00004',
  '我想看挑战两把s686打突变团竞的游戏视频',
  'Video-Play',
  'name:挑战两把s686打突变团竞的游戏视频'],
 ['NLU00005', '我想看和平精英上战神必备技巧的游戏视频', 'Video-Play', 'name:和平精英上战神必备技巧的游戏视频'],
 ['NLU00006',
  '2019年古装爱情电视剧小女花不弃的花絮播放一下',
  'Video-Play',
  'name:小女花不弃的花絮+datetime_date:2019年'],
 ['NLU00007', '找一个2004年的推理剧给我看一会呢', 'FilmTele-Play', 'tag:推理+age:2004年'],
 ['NLU00008',
  '自驾游去深圳都经过那些地方啊',
  'Travel-Query',
  'destination:深圳+query_type:导航'],
 ['NLU00009',
  '给我转播今天的女子双打乒乓球比赛现场',
  'Video-Play',
  'datetime_date:今天+name:女子双打乒乓球比赛现场']]

stat_info = {'intent': {'Travel-Query': 1000,
  'Music-Play': 1000,
  'FilmTele-Play': 1000,
  'Video-Play': 1000,
  'Radio-Listen': 1000,
  'HomeAppliance-Control': 1000,
  'Weather-Query': 1000,
  'Alarm-Update': 1000,
  'Calendar-Query': 1000,
  'TVProgram-Play': 50,
  'Audio-Play': 50},
 'slot': {'destination': 917,
  'departure': 384,
  'datetime_date': 3244,
  'query_type': 945,
  'album': 158,
  'play_mode': 396,
  'name': 2236,
  'tag': 384,
  'age': 367,
'artist': 1150,
  'channel': 622,
  'song': 424,
  'instrument': 109,
  'appliance': 963,
  'command': 994,
  'details': 652,
  'index': 503,
  'city': 840,
  'datetime_time': 1143,
  'notes': 696,
  'play_setting': 233,
  'language': 152,
  'type': 419,
  'region': 458,
  'frequency': 331}}

all_num = {}
table_data = {}
for name in ('intent', 'slot'):
    all_num[name] = sum(stat_info[name].values())
    table_data[name] = [[k,v,'{:.2f}'.format(v*100/all_num[name])] for k,v in stat_info[name].items()]
# ============== 表格 =============
table_sample = Table()
headers = ['id', 'text', 'intent', 'slot_info']
rows = train_list
table_sample.add(headers, rows).set_global_opts(
    title_opts=opts.ComponentTitleOpts(title="训练集数据示例")
)

table_intent = Table()
headers = ["意图名", "频次", "占比(%)"]
rows = table_data['intent']
table_intent.add(headers, rows).set_global_opts(
    title_opts=opts.ComponentTitleOpts(title="意图分布")
)
table_slot = Table()
headers = ["槽位名", "频次", "占比(%)"]
rows = table_data['slot']
table_slot.add(headers, rows).set_global_opts(
    title_opts=opts.ComponentTitleOpts(title="槽位分布")
)
# ============== 柱形图 =============
bar_intent = (Bar()
        .add_xaxis(list(stat_info['intent'].keys()))
        .add_yaxis("意图", list(stat_info['intent'].values()))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="意图频次"),
            #datazoom_opts=[opts.DataZoomOpts()], # 拖拽功能
            toolbox_opts=opts.ToolboxOpts(is_show=True), # 工具箱
        )
)
bar_slot = (Bar()
        .add_xaxis(list(stat_info['slot'].keys()))
        .add_yaxis("槽位", list(stat_info['slot'].values()))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="槽位频次"),
            #datazoom_opts=[opts.DataZoomOpts()],
            toolbox_opts=opts.ToolboxOpts(is_show=True), # 工具箱
        )
)
# ============== 饼图 =============
pie_intent = (Pie()
    .add("意图分布", list(stat_info['intent'].items()),
            radius=["30%", "75%"], # radius=[40,75],radiius:半径
            center=["25%", "50%"],
            rosetype="radius",
            label_opts=opts.LabelOpts(is_show=True))
     .set_global_opts(
        title_opts=opts.TitleOpts(title="意图占比分布"),   # TitleOpts:标题设置项
         toolbox_opts=opts.ToolboxOpts(is_show=True), # 工具箱
        legend_opts=opts.LegendOpts(pos_top="5%",pos_right="15%", orient='vertical')) #LegendOpts:图例配置项
) 
pie_slot = (Pie()
    .add("槽位分布", list(stat_info['slot'].items()),
            radius=["30%", "75%"], # radius=[40,75],radiius:半径
            center=["25%", "50%"],
            rosetype="radius",
            label_opts=opts.LabelOpts(is_show=True))
     .set_global_opts(
        title_opts=opts.TitleOpts(title="槽位占比分布"),   # TitleOpts:标题设置项
        toolbox_opts=opts.ToolboxOpts(is_show=True), # 工具箱
        legend_opts=opts.LegendOpts(pos_top="5%",pos_right="15%", orient='vertical')) #LegendOpts:图例配置项
)
#pie.render("环形图.html")
#pie.render_notebook()
# ============== 汇总 =============
# 绘制在一张图里
# page = Page(layout=Page.SimplePageLayout)
# page.add(table_sample, table_intent, table_slot, bar_intent, bar_slot, pie_intent, pie_slot)
# page.render("ccf.html")
# page.render_notebook()

tab = Tab()
tab.add(table_sample, "训练数据样例")
tab.add(table_intent, "意图分布-表")
tab.add(table_slot, "槽位分布-表")
tab.add(bar_intent, "意图分布-柱形图")
tab.add(bar_slot, "槽位分布-柱形图")
tab.add(pie_intent, "意图分布-饼图")
tab.add(pie_slot, "槽位分布-饼图")
tab.render("ccf.html")
tab.render_notebook()

smartchart

#安装SmartChart
pip3 install smartchart
pip3 install smartchart -U #(升级)
# 如果安装过程慢,建意使用
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple smartchart
#如果你是第一次安装SmartChart(注意,非第一次不要执行,会覆盖原有DB)
pip3 install smartdb # (初始化DB)

PyGraphviz

Graphviz 入门指南, 官方图示

Graphviz 是一个开源的图可视化工具,非常适合绘制结构化的图标和网络。Graphviz 使用一种叫 DOT 的语言来表示图形。

介绍

  • 【2020-8-4】PyGraphviz (几何图形可视化工具) 简单入门
  • Graphviz 是一个几何图形可视化软件,能够将数据的结构信息表示为抽象图形和网络图的方式。
  • PyGraphviz 主要对数据量大、可任意定制的图形上具有强大优势。
  • 建议:由于 PyGraphviz 暂时无法对同源节点合并线段。在流程图、小型结构图方面,Visio 可以作为 Graphviz 的直接替代软件。

工具

【2024-7-5】dot文件在线可视化

DOT 语言

DOT语言是一种图形描述语言。能够以简单的方式描述图形,并且为人和计算机所理解。

digraph graphname{ 
    a -> {b c};
    c -> e;
    b -> d; // 有向图

    subgraph cluster_bc {
        bgcolor=red;
        b;
        c;
    }

    subgraph cluster_de {
        label="Block"
        d;
        e;
    }

dot 文件解析

【2024-7-6】使用正则表达式抽取 dot 文件中的节点边信息,转化成 pandas 表格

dot 文件示例

digraph g {
	"000" -> "000" [ label="0", color="Red" ];
	"000" -> "001" [ label="1", color="Blue" ];
	"000" -> "002" [ label="2", color="Green" ];
	"000" -> "003" [ label="3", color="Yellow" ];
}

解析代码

import pandas as pd
import re

# 	"223" -> "231" [ label="1", color="Blue" ];
pattern = re.compile(r'.*\"(.*?)\".*\"(.*?)\".*\[\s+label=\"(.*?)\".*color=\"(.*?)\".*\]')

data_file = 'test.dot'

data_list = []
with open(data_file, 'r') as f:
    for line in f.readlines():
        res = pattern.findall(line)
        if not res:
            continue
        # [('000', '000', '0', 'Red')]
        data_list.append(res[0])
        #print(res)
print(data_list)
#!cat test.dot
df = pd.DataFrame(data_list, columns=['source', 'target', 'edge_name', 'edge_color'])
df

安装

  • 各操作系统下的安装
brew install graphviz # mac
pip install graphviz # linux
conda install graphviz # conda

使用

import pygraphviz as pgv
# 创建图形
G = pgv.AGraph(directed=True, strict=False, nodesep=0, ranksep=1.2, rankdir="TB",
               splines="none", concentrate=True, bgcolor="write",
               compound=True, normalize=False, encoding='UTF-8')
# 添加节点
G.add_node(name, label=None, fontname="Times-Roman", fontsize=14,
           shape="ellipse", style="rounded", color="black", fontcolor="black",
           pos="x,y(!)", fixedsize=False, width=1, height=1)

G.add_nodes_from(names, **attr) # 批量添加点,参数同上 
# 添加边
G.add_edge(origin, target, color="black", style="solid", penwidth=1,
           label="", fontname="Times-Roman", fontsize=14, fontcolor="black",
           arrowsize=1, arrowhead="normal", arrowtail="normal", dir="forward")
# label -> str:边标签,未指定时不显示
# penwidth:线条粗细
# arrowsize:箭头大小
# arrowhead:箭头类型,可选 normal, vee
# dir:箭头方向,可选 both, forward, back, none。只有在无向图中才起作用!
G.add_nodes_from([[origin_1, target_1],
                  [origin_2, target_2],...], **attr)  # 批量添加线,参数同上
# 导出图形
G.layout()
G.draw(file_name, prog="neato")
# prog:布局算法,可选 neato, dot (推荐), twopi, circo, fdp

  • 创建图:
    • directed -> False | True:有向图
    • strict -> True | False:简单图
    • nodesep:同级节点最小间距
    • ranksep:不同级节点最小间距
    • rankdir:绘图方向,可选 TB (从上到下), LR (从左到右), BT (从下到上), RL (从右到左)
    • splines:线条类型,可选 ortho (直角), polyline (折线), spline (曲线), line (线条), none (无)
    • concentrate -> True | False:合并线条 (双向箭头)
    • bgcolor:背景颜色
    • compound -> True | False:多子图时,不允许子图相互覆盖
    • normalize -> False | True:以第一个节点作为顶节点
  • 添加节点
    • name -> str:节点名。label 为节点标签,未指定时显示 name
    • fontname:字体名称,常用:Microsoft YaHei, SimHei, KaiTi, SimSun, FangSong, Times-Roman, Helvetica, Courier。可以使用 “times bold italic” 表示字体类型、粗细、倾斜
    • fixedsize -> Flase | True | “shape”`:固定大小,默认随文本长度变化。设置为 True 时,width 和 height 参数共同控制点大小。设置为 “shape” 时,将取标签文本和设置值的较大者
    • pos -> str:点的初始位置。使用 “x,y!” 时,可以强制固定点的位置。
    • style:节点线样式,使用 color 设置线条颜色 (style=”filled” 时,设置填充颜色)
    • shape: 节点形状

案例

networkx 绘制社交网络图

networkx模块以及pyvis模块

import networkx as nx

g = nx.Graph()
# 点
g.add_node(0, label = "root") # intialize yourself as central node
g.add_node(1, label = "Company 1", size=10, title="info1")
g.add_node(2, label = "Company 2", size=40, title="info2")
g.add_node(3, label = "Company 3", size=60, title="info3")
# 边
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(0, 3)

# -----------
g = nx.Graph()
g.add_node('myself') # 将自己放置在网络的中心

for _, row in df_position_reduced.iterrows():
    g.add_node(position, size=count*2, title=hover_info, color='#3449eb')
    g.add_edge('root', position, color='grey')
# 生成网络图表
nt = net.Network(height='700px', width='700px', bgcolor="black", font_color='white')
nt.from_nx(g)
nt.hrepulsion()

nt.show('company_graph.html')

因果关系图

  • 效果:
  • 代码:
import pygraphviz as pgv

G = pgv.AGraph(directed=True, strict=False, ranksep=0.2, splines="spline", concentrate=True)

# 设置节点标签
nodeA = "Police\nIntelligence"
nodeB = "Police Station"
nodeC = "Criminal Action"
nodeD = "Incidents"
nodeE = "Police Dockets"
nodeF = "Control Room\nAwareness"
nodeG = "Patroller Information"
nodeH = "Patroller Awareness"

# 添加节点
G.add_nodes_from([nodeA, nodeB, nodeC, nodeD, nodeE, nodeF, nodeG, nodeH],
                 color="#ffffff", fontname="times bold italic")

# 添加边
G.add_edges_from([[nodeA, nodeB], [nodeA, nodeF], [nodeB, nodeC], [nodeC, nodeD],
                  [nodeC, nodeG], [nodeD, nodeE], [nodeD, nodeG], [nodeE, nodeA],
                  [nodeF, nodeA], [nodeF, nodeG], [nodeF, nodeH], [nodeG, nodeF],
                  [nodeH, nodeG]], color="#7F01FF", arrowsize=0.8)

# 导出图形
G.layout()
G.draw("因果关系图.png", prog="dot")

因子相关性图

  • 效果:
  • 代码:
import pygraphviz as pgv

G = pgv.AGraph(directed=True, rankdir="TB")

# 设置节点标签
Root = "道路交通流畅"
negative_1 = "平均延误时间"
negative_2 = "负荷度"
negative_3 = "小区位置"
negative_4 = "相对延误率"
negative_5 = "房屋密度"
negative_6 = "人口密度"
negative_7 = "总延误率"
negative_8 = "排队率"
negative_9 = "行驶时间"
positive_1 = "通行能力"
positive_2 = "公路层级"
positive_3 = "路网结构"
positive_4 = "行驶速度"
positive_5 = "路网长度"
positive_6 = "小区面积"
positive_7 = "内部道路密度"
positive_8 = "路网密度"

# 添加节点
G.add_node(Root, style="filled", shape="box3d", color="#feb64d")
for negative in [eval(_) for _ in dir() if _.startswith("negative")]:
    G.add_node(negative, style="filled", shape="ellipse", color="#CFDBF6")

for positive in [eval(_) for _ in dir() if _.startswith("positive")]:
    G.add_node(positive, style="filled", shape="ellipse", color="#B4E7B7")

# 添加边
G.add_edges_from([[Root, negative_1], [Root, negative_6], [Root, negative_8], [Root, negative_9],
                  [negative_1, negative_2], [negative_1, negative_7], [negative_2, negative_3],
                  [negative_2, negative_7], [negative_3, negative_4], [negative_8, negative_9],
                  [positive_2, negative_5], [positive_3, negative_4], [positive_4, negative_5]],
                 color="#B4DBFF", style="dashed", penwidth=1.5)

G.add_edges_from([[Root, positive_1], [Root, positive_8], [negative_5, negative_4],
                  [negative_6, positive_4], [negative_5, positive_4], [negative_9, positive_5],
                  [positive_1, positive_2], [positive_2, positive_3], [positive_6, positive_5],
                  [positive_7, positive_6], [positive_8, positive_7]],
                 color="#B4E7B7", style="dashed", penwidth=1.5)

# 导出图形
G.layout()
G.draw("因子相关性图.png", prog="dot")

神经网络图

  • 效果
  • 代码:
import pygraphviz as pgv

G = pgv.AGraph(directed=True, rankdir="LR")

# 设置层数、每层节点数
network_structure = input("输入神经网络每层节点数,如:[10, 7, 5, 4, 2, 1]\n")
all_nodes = [[f"layer{layer_index}node{node_index}" for node_index in range(layer_nodes_num)] for
             layer_index, layer_nodes_num in enumerate(eval(network_structure))]

# 添加输入层节点
for node_index, node in enumerate(all_nodes[0]):
    G.add_node(node, label="", shape="circle", style="bold", color="#60acfc", pos=f"0,{0.6 * node_index}!")

# 添加输入层文本
G.add_node(f"Input_Layer", shape="none", label=f"Input_Layer({len(all_nodes[0])})",
           pos=f"{0},{(node_index + 1) * 0.6}!")

# 添加中间层、输出层节点
for layer_index, layer in enumerate(all_nodes[1:]):
    color = "#5bc49f" if layer_index == len(all_nodes[1:]) - 1 else "#ff7c7c"

    for node_index, node in enumerate(layer):
        x = 1.5 * (layer_index + 1)
        y = - 0.3 * (len(all_nodes[layer_index + 1]) - len(all_nodes[0])) + 0.6 * node_index
        G.add_node(node, label="", shape="circle", style="bold", color=color, pos=f"{x},{y}!")

    # 添加中间层、输出层文本
    text = f"Output_Layer({len(all_nodes[-1])})" if layer_index == len(all_nodes[1:]) - 1 else f"Layer_{layer_index + 1}({len(layer)})"
    G.add_node(f"Layer_{layer_index + 1})", shape="none", label=text,
               pos=f"{x},{y + 0.4}!")

# 添加线
for layer_index in range(all_nodes.__len__() - 1):
    for start in all_nodes[layer_index]:
        for end in all_nodes[layer_index + 1]:
            G.add_edge(start, end)

# 导出图形
G.layout()
G.draw("神经网络.png")
# 运行代码,输入 [5, 10, 15, 15, 15, 10, 5, 1]

有限状态机FSM的可视化

  • 有限状态机(Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。FSM是一种算法思想,简单而言,有限状态机由一组状态、一个初始状态、输入和根据输入及现有状态转换为下一个状态的转换函数组成。
  • Transitions
  • Python的Transitions库实现有限状态机(FSM)
from transitions.extensions import GraphMachine

states = ['first', 'second']
transitions = [
    ['any_trigger', 'first', 'first'],
    ['anything', '*', 'second'],
]

machine = GraphMachine(states=states, transitions=transitions, initial='first', auto_transitions=False, show_conditions=True)

machine.get_graph().draw('fsm.png', prog='dot')
from IPython.display import Image
Image('fsm.png')

决策树可视化

【2023-1-31】决策树可视化,dtreeviz工具, XGBoost Examples

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier

import dtreeviz

iris = load_iris()
X = iris.data
y = iris.target

clf = DecisionTreeClassifier(max_depth=4)
clf.fit(X, y)

viz_model = dtreeviz.model(clf,
                           X_train=X, y_train=y,
                           feature_names=iris.feature_names,
                           target_name='iris',
                           class_names=iris.target_names)

v = viz_model.view()     # render as SVG into internal object 
v.show()                 # pop up window
v.save("/tmp/iris.svg")  # optionally save as svg

turtle工具

python中的画图神器——turtle模块

turtle库的基础命令介绍

画布

画布cancas是绘图区域,可以设置它的大小和初始位置

turtle.screensize(1000,600,'red')    # 大小的设置
turtle.setup(width=0.5,height=0.75)  # 初始位置

画笔

(1)画笔运动的命令

turtle.forward(a)   # 向当前画笔方向移动a像素长度
turtle.backward(a)  # 向当前画笔相反方向移动a像素长度
turtle.right(a)     # 顺时针移动
aturtle.left(a)     # 逆时针移动
aturtle.pendown()   # 移动时绘制图形
turtle.goto(x,y)    # 将画笔移动到坐标为x,y的位置
turtle.penup()      # 移动时不绘制图形,提起笔
turtle.speed(a)     # 画笔绘制的速度范围
turtle.circle()     # 画图,半径为正,表示圆心在画笔的左边画圈

(2)画笔控制命令

turtle.pensize(width)   # 绘制图形的宽度
turtle.pencolor()       # 画笔的颜色
turtle.fillcolor(a)     # 绘制图形的填充颜色
turtle.color(a1,a2)     # 同时设置pencolor=a1,fillcolor=a2
turtle.filling()        # 返回当前是否在填充状态
turtle.begin_fill()     # 准备开始填充图形
turtle.end_fill()       # 填充完成
turtle.hideturtle()     # 隐藏箭头显示
turtle.showturtle()     # 显示箭头

(3)全局控制命令

turtle.clear()   # 清空turtle窗口,但是turtle的位置和状态不会改变
turtle.reset()   # 清空窗口,重置turtle状态为起始位置
turtle.undo()    # 撤销上一个turtle动作

实战

原文涉及案例:樱花、玫瑰花、皮卡丘、星空、小黄人、单身狗等

爱心

img

from turtle import *

color('red', 'pink')  # 画笔色red,背景色pink
begin_fill()
left(135)  # 左转135°
fd(100)  # 前进100像素
right(180)  # 画笔掉头

circle(30, -180)

backward(35)  # 由于此时画笔方向约为绝对方向的135°,需倒退画线
right(90)
forward(35)
circle(-30, 180)
fd(100)
end_fill()
hideturtle()
done()

动画

manim

【2023-6-14】manim中文教程

manim 简介

manim 是视频博主 3Blue1Brown 开发的动画引擎,他使用 manim 创作出了许多直观、美丽的数学科普内容。

  • 效果图

manim 安装

安装方法

# mac 终端里分别输入
brew install py3cairo ffmpeg
brew install cmake pango scipy
pip3 install manim
#pip install manimgl
manimgl # 进入交互模式

hello world

manim 是运行在 python 下的,首先创建一个 python 文件 test.py

from manim import * # 导入 manim

class Test(Scene): # 定义一个场景
    def construct(self):
        #code here
        circle = Circle() # 画圆
        self.play(Write(circle)) # 动画
        # 图片变化特效
        cardi = SVGMobject("./images/cardiB.svg").shift(LEFT*3).scale(3)
        iggy = SVGMobject("./images/iggy.svg").shift(RIGHT*3).scale(3)
        self.play(Write(cardi), rate_func = smooth, run_time = 3) # 播放特效
        self.wait(0.5) # 停顿 0.5 秒
        self.play(ReplacementTransform(cardi, iggy), 
                rate_func = smooth,  # 动画插值方式为贝塞尔曲线
                run_time = 3 # 动画持续实践为 3 秒
        )
        self.wait(0.5)

# manim test.py Test

运行

manimgl test.py Test

屏幕上会弹出一个窗口,这时可以:

  • 滚动鼠标中键来上下移动画面
  • 按住键盘上 z 键的同时滚动鼠标中键来缩放画面
  • 按住键盘上 f 键的同时移动鼠标来平移画面
  • 按住键盘上 d 键的同时移动鼠标来改变三维视角
  • 按下键盘上 r 键恢复到最初的视角
  • 最后,按 q 来关闭窗口并退出程序.

manim 运行过程

manim 类继承的 pdf

运行过程

应用

transformer 结构动画

xinyu提供的脚本:flash-attn

  • 【2023-6-16】调用 latex 报错: issue

No such file or directory … Tex/42c962cc458aefe6.svg’

结束


支付宝打赏 微信打赏

~ 海内存知已,天涯若比邻 ~

Share

Related Posts

标题:已然两年,恍如隔世

摘要:工作两年的纪要、反思

标题:数据库及SQL-database&sql-note

摘要:数据挖掘知识点、经验总结

站内可视化导航

文章可视化导读:鼠标划过图形块时,如果出现蓝色光环, 点击即可跳转到对应主题

Comments

--disqus--

    Content
    My Moment ( 微信公众号 )
    欢迎关注鹤啸九天