Matplotlib真的不能绘制「交互图表」?

小数志

共 8115字,需浏览 17分钟

 ·

2021-08-16 02:59

👆星标关注pythonic生物人,前排阅读以下干货!


Python/R/数据科学/生物信息!

前景提要:本篇分享Matplotlib的两个扩展mpl_interactionsmpldatacursor,弥补Matplotlib交互能力的缺陷。

「文末有彩蛋」

mpl_interactions

支持窗口界面和jupyter notebook中渲染,以折线图mpl_interactions.ipyplot.plot为例

交互后端qt中渲染图形

魔法命令%matplotlib qt调用qt后端,此时可点击界面按钮修改图形的线型、marker、颜色、坐标轴等等属性。

# 魔法命令调用qt后端
%matplotlib qt
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Slider
import mpl_interactions.ipyplot as iplt

plt.style.use('fivethirtyeight')
fig, ax = plt.subplots(dpi=80)
plt.subplots_adjust(bottom=.25)
x = np.linspace(02 * np.pi, 200)


def f(x, freq):
    return np.sin(x * freq)


axfreq = plt.axes([0.250.10.650.03])
slider = Slider(axfreq, label='freq', valmin=.05, valmax=10)
controls = iplt.plot(x, f, freq=slider, ax=ax)

交互后端ipympl中渲染图形

#魔法命令调用ipympl backend(后端)
%matplotlib ipympl
import numpy as np
import pandas as pd
import mpl_interactions.ipyplot as iplt
import matplotlib.pyplot as plt

plt.style.use('fivethirtyeight')

#准备数据
x = np.linspace(0, np.pi, 100)
tau = np.linspace(0.510100)


def f1(x, tau, beta):
    return np.sin(x * tau) * x * beta


def f2(x, tau, beta):
    return np.sin(x * beta) * x * tau


fig, ax = plt.subplots(dpi=80)

#iplt.plot
controls = iplt.plot(x, f1, tau=tau, beta=(110100), label="f1")
iplt.plot(x, f2, controls=controls, label="f2")#定义滑动条(sliders)

#图例(legend)
_ = plt.legend()
iplt.title("iplt.plot: tau is {tau:.2f}", controls=controls['tau'])
plt.show()

散点图mpl_interactions.ipyplot.scatter

%matplotlib ipympl
import matplotlib.pyplot as plt
import numpy as np
import mpl_interactions.ipyplot as iplt
import ipywidgets as widgets
import pandas as pd
from matplotlib.colors import to_rgba_array, TABLEAU_COLORS, XKCD_COLORS

# 数据准备
data = pd.read_json('nations.json')


def clean_data(data):
    for column in ['income''lifeExpectancy''population']:
        data = data.drop(data[data[column].apply(len) <= 4].index)
    return data


def extrap_interp(data):
    data = np.array(data)
    x_range = np.arange(180020091.)
    y_range = np.interp(x_range, data[:, 0], data[:, 1])
    return y_range


def extrap_data(data):
    for column in ['income''lifeExpectancy''population']:
        data[column] = data[column].apply(extrap_interp)
    return data


data = clean_data(data)
data = extrap_data(data)
income_min, income_max = np.min(data['income'].apply(np.min)), np.max(
    data['income'].apply(np.max))
life_exp_min, life_exp_max = np.min(data['lifeExpectancy'].apply(
    np.min)), np.max(data['lifeExpectancy'].apply(np.max))
pop_min, pop_max = np.min(data['population'].apply(np.min)), np.max(
    data['population'].apply(np.max))


def x(year):
    return data["income"].apply(lambda x: x[year - 1800])


def y(x, year):
    return data["lifeExpectancy"].apply(lambda x: x[year - 1800])


def s(x, y, year):
    pop = data["population"].apply(lambda x: x[year - 1800])
    return 6000 * pop.values / pop_max


regions = data["region"].unique().tolist()
c = data["region"].apply(
    lambda x: list(TABLEAU_COLORS)[regions.index(x)]).values

#画图
fig, ax = plt.subplots(dpi=80,figsize=(104.8))
controls = iplt.scatter(
    x,
    y,
    s=s,
    year=np.arange(18002009),
    c=c,
    edgecolors="k",
    slider_formats="{:d}",
    play_buttons=True,
    play_button_pos="left",
)
fs = 15
iplt.title("iplt.scatter: year is {year} ", controls=controls['year'])
ax.set_xscale("log")
ax.set_ylim([0100])
ax.set_xlim([200, income_max * 1.05])
ax.set_xlabel("Income", fontsize=fs)
_ = ax.set_ylabel("Life Expectancy", fontsize=fs)

图像mpl_interactions.ipyplot.t.imshow

img = plt.imread("https://matplotlib.org/3.3.1/_images/stinkbug.png")


fig4, ax4 = plt.subplots(dpi=80)
controls4 = iplt.imshow(img, vmin_vmax=("r", img.min(), img.max()))

直方图mpl_interactions.interactive_hist

%matplotlib ipympl
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np

from mpl_interactions import interactive_hist


def f(loc, scale):
    return np.random.randn(10000) * scale + loc


fig, ax = plt.subplots(dpi=80)
controls = interactive_hist(f, loc=(010100), scale=(0.55))
iplt.title("iplt.interactive_hist: loc is {loc:.2f} ", controls=controls['loc'])

热图mpl_interactions.heatmap_slicer

%matplotlib widget
import matplotlib.pyplot as plt
import numpy as np

from mpl_interactions import heatmap_slicer

x = np.linspace(0, np.pi, 100)
y = np.linspace(010200)
X, Y = np.meshgrid(x, y)
data1 = np.sin(X) + np.exp(np.cos(Y))
data2 = np.cos(X) + np.exp(np.sin(Y))
fig, axes = heatmap_slicer(
    x,
    y,
    (data1, data2),
    slices="both",
    heatmap_names=("dataset 1""dataset 2"),
    labels=("Some wild X variable""Y axis"),
    interaction_type="move",
)

mpl_interactions缺陷

功能有限,仅仅支持以下几个方向,前面大部分已经列出。下面介绍另外一个扩展mpldatacursor。

mpldatacursor

主要使用data cursors方法,为matplotlib生成一个交互注视文本,简单举几个例子.

import numpy as np
import matplotlib.pyplot as plt
from mpldatacursor import datacursor

x = np.linspace(010100)

fig, ax = plt.subplots(dpi=80)
ax.set_title('Click to display its label')

for i in range(120):
    ax.plot(x, i * x, label='$y = {}x.format(i))

#formatter展示每个点详细数据、方程
datacursor(formatter="{label}\nx:{x:.2f}\ny:{y:.2f}".format)

plt.show()

mpldatacursor 缺陷

同第一个扩展,能力有限。

精进两工具

https://github.com/joferkington/mpldatacursor
https://github.com/ianhi/mpl-interactions

彩蛋彩蛋👇👇

mpl_interactions结合mpldatacursor能满足简单的交互需求,需要更多交互还是寻求更专业的交互软件




相关阅读:


浏览 63
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报