python+matplotlib实现在图中鼠标指向标注点处显示标注信息(标注信息动态显示)

说明

此篇为 一次python画图经历——涉及 matplotlib 的折线图,散点图,图中标注文字信息,设置横坐标密度,调整横坐标旋转角度,文字大小、各部分颜色、保存形式、美化调整 的延续,当时自以为很好地处理了标注信息的问题,结果发现,当需要标注的点很多很密集的时候,画出来的图会很糟糕:

在这里插入图片描述
因此重新想了一个办法,加入鼠标交互功能,当鼠标指针指向标注点时,将标注信息显示出来,不指向时不显示标注信息,以下为实现过程。

标注信息动态显示

数据

在这里插入图片描述

代码

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

# ---------- 数据预处理 ----------
file_path = './example_csdn_processed.csv'
df_all = pd.DataFrame(pd.read_csv(file_path, encoding='gbk'))
df_all = df_all.set_index(pd.DatetimeIndex(pd.to_datetime(df_all.time)))

x = df_all['time']
y1 = df_all['data']

y2 = df_all["buy"]
y3 = df_all["sell"]
y_condition = list(df_all["操作"])

text1 = []
for i in range(len(x)):
    if (df_all['操作'][i] != 0) and (df_all['操作'][i] == "买"):
        str_info = '价格: ' + str(df_all['价格'][i]) + '\n' + '数量: ' + str(df_all['数量'][i]) + '\n' + '操作: ' + str(df_all['操作'][i])
        text1.append(str_info)
    else:
        text1.append(" ")
text2 = []
for i in range(len(x)):
    if (df_all['操作'][i] != 0) and (df_all['操作'][i] == "卖"):
        str_info = '价格: ' + str(df_all['价格'][i]) + '\n' + '数量: ' + str(df_all['数量'][i]) + '\n' + '操作: ' + str(df_all['操作'][i])
        text2.append(str_info)
    else:
        text2.append(" ")


# ---------- 画图 ----------
fig, ax = plt.subplots()

# 折线图
ax.plot(x, y1, color='royalblue', lw=2.5, label='data')
# 折线图上的散点
ax.scatter(x, y2, marker='o', c='darkgreen', label='买')
ax.scatter(x, y3, marker='o', c='firebrick', label='卖')

# 一些小设置
# 设置 x 轴显示密度
tick_spacing = 8
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
# 设置 x 坐标轴标签的显示内容和大小
plt.xlabel('时间', fontsize=16)
# 设置 x 坐标轴刻度的旋转方向和大小
plt.xticks(rotation=90, fontsize=16)
# 设置 y 坐标轴刻度大小
plt.yticks(fontsize=18)
# 坐标轴中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
# 调整图的位置
plt.subplots_adjust(top=0.9, bottom=0.22)
# 设置尺寸
fig.set_size_inches(24, 12)

# po_annotation1 为 ‘买’ 时需要显示的标注信息
# 该 list 内部存放多个子 list,每个子 list 为 [标注点的坐标, 标注]
po_annotation1 = []
for i in range(len(x)):
    # 标注点的坐标
    point_x = x[i]
    point_y = y2[i]
    point, = plt.plot(point_x, point_y, 'o', c='darkgreen')
    # 标注框偏移量
    offset1 = 80
    offset2 = 80
    # 标注框
    bbox1 = dict(boxstyle="round", fc='lightgreen', alpha=0.6)
    # 标注箭头
    arrowprops1 = dict(arrowstyle="->", connectionstyle="arc3,rad=0.")
    # 标注
    annotation = plt.annotate(text1[i], xy=(x[i], y2[i]), xytext=(-offset1, offset2), textcoords='offset points',
                              bbox=bbox1, arrowprops=arrowprops1, size=15)
    # 默认鼠标未指向时不显示标注信息
    annotation.set_visible(False)
    po_annotation1.append([point, annotation])

po_annotation2 = []
for i in range(len(x)):
    # 标注点的坐标:
    point_x = x[i]
    point_y = y3[i]
    point, = plt.plot(point_x, point_y, 'o', c='firebrick')
    # 标注框偏移量
    offset1 = 30
    offset2 = 80
    # 标注框
    bbox2 = dict(boxstyle="round", fc='salmon', alpha=0.6)
    # 标注箭头
    arrowprops2 = dict(arrowstyle="->", connectionstyle="arc3,rad=0.")
    # 标注
    annotation = plt.annotate(text2[i], xy=(x[i], y3[i]), xytext=(-offset1, offset2), textcoords='offset points',
                              bbox=bbox2, arrowprops=arrowprops2, size=15)
    # 默认鼠标未指向时不显示标注信息
    annotation.set_visible(False)
    po_annotation2.append([point, annotation])


# 定义鼠标响应函数
def on_move(event):
    visibility_changed = False
    for point, annotation in po_annotation1:
        should_be_visible = (point.contains(event)[0] == True)

        if should_be_visible != annotation.get_visible():
            visibility_changed = True
            annotation.set_visible(should_be_visible)

    for point, annotation in po_annotation2:
        should_be_visible = (point.contains(event)[0] == True)

        if should_be_visible != annotation.get_visible():
            visibility_changed = True
            annotation.set_visible(should_be_visible)

    if visibility_changed:
        plt.draw()


# 鼠标移动事件
on_move_id = fig.canvas.mpl_connect('motion_notify_event', on_move)
plt.show()

效果

在这里插入图片描述

实现Python+matplotlib数据可视化鼠标悬停自动标注功能,可以使用matplotlib的annotate()函数,该函数可以在添加注释文本。 具体实现步骤如下: 1. 导入必要的库: ```python import matplotlib.pyplot as plt from matplotlib.offsetbox import OffsetImage, AnnotationBbox ``` 2. 创建形并绘制数据: ```python fig, ax = plt.subplots() ax.plot(x_data, y_data) ``` 3. 定义鼠标悬停事件的回调函数,该函数将在鼠标悬停时被调用,根据鼠标所在的数据点位置添加注释文本: ```python def on_hover(event): for i in range(len(x_data)): if event.xdata is not None and event.ydata is not None: if x_data[i] - 0.5 <= event.xdata <= x_data[i] + 0.5 and \ y_data[i] - 0.5 <= event.ydata <= y_data[i] + 0.5: img = plt.imread(image_files[i]) imagebox = OffsetImage(img, zoom=0.2) ab = AnnotationBbox(imagebox, (x_data[i], y_data[i])) ax.add_artist(ab) fig.canvas.draw_idle() ``` 4. 将回调函数绑定到形的鼠标悬停事件上: ```python fig.canvas.mpl_connect('motion_notify_event', on_hover) ``` 完整代码: ```python import matplotlib.pyplot as plt from matplotlib.offsetbox import OffsetImage, AnnotationBbox x_data = [1, 2, 3, 4, 5] y_data = [2, 4, 1, 5, 3] image_files = ['image1.png', 'image2.png', 'image3.png', 'image4.png', 'image5.png'] fig, ax = plt.subplots() ax.plot(x_data, y_data) def on_hover(event): for i in range(len(x_data)): if event.xdata is not None and event.ydata is not None: if x_data[i] - 0.5 <= event.xdata <= x_data[i] + 0.5 and \ y_data[i] - 0.5 <= event.ydata <= y_data[i] + 0.5: img = plt.imread(image_files[i]) imagebox = OffsetImage(img, zoom=0.2) ab = AnnotationBbox(imagebox, (x_data[i], y_data[i])) ax.add_artist(ab) fig.canvas.draw_idle() fig.canvas.mpl_connect('motion_notify_event', on_hover) plt.show() ``` 执行该代码后,将会在添加自动标注功能。当鼠标悬停在数据点附近时,会自动在该点添加注释文本,并显示与该数据点相关的片。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值