kerln888 发表于 2026-02-22 18:38
@FishC matplotlib可以给子图添加悬停功能吗??
是的,Matplotlib可以通过事件处理给子图添加悬停功能。虽然Matplotlib本身没有内置的悬停组件,但我们可以利用mpl_connect方法绑定鼠标移动事件来实现类似效果。以下是一个简单示例,当鼠标悬停在子图的数据点上时,会显示该点的坐标信息:
import matplotlib.pyplot as plt
import numpy as np
# 创建图形和子图
fig, ax = plt.subplots()
x = np.arange(10)
y = np.random.rand(10)
points, = ax.plot(x, y, 'o')# 绘制散点图
# 初始化文本对象用于显示悬停信息
hover_text = ax.text(0, 0, '', backgroundcolor='yellow', alpha=0.7)
def on_hover(event):
# 检查事件是否发生在当前子图内
if event.inaxes == ax:
# 计算鼠标位置与数据点的距离
distances = np.sqrt((x - event.xdata)**2 + (y - event.ydata)**2)
min_index = np.argmin(distances)
min_distance = distances
# 如果距离足够近,则显示悬停信息
if min_distance < 0.5:# 阈值可根据需要调整
hover_text.set_text(f'({x:.2f}, {y:.2f})')
hover_text.set_position((x, y))
fig.canvas.draw_idle()
else:
hover_text.set_text('')
fig.canvas.draw_idle()
# 绑定鼠标移动事件
fig.canvas.mpl_connect('motion_notify_event', on_hover)
plt.show()
注意事项:
1. 上述代码使用motion_notify_event事件来检测鼠标移动,并通过计算鼠标与数据点的距离来触发悬停显示。
2. 悬停灵敏度通过距离阈值(示例中为0.5)控制,您可以根据实际情况调整。
3. 此方法适用于简单的悬停需求,对于复杂交互(如多子图或大量数据),可能需要更精细的事件处理或考虑使用其他库(如Plotly)。
如果需要为多个子图添加悬停功能,只需为每个子图单独绑定事件并处理相应的数据即可。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC 使用mplcursors对matplotlib增加悬停功能。柱状图x坐标是1,2,3。y轴坐标是1,2,3.如何实现鼠标移动到x轴0到1,y轴0-3这个区域,显示x坐标1的柱状信息
kerln888 发表于 2026-02-22 23:44
@FishC 使用mplcursors对matplotlib增加悬停功能。柱 ...
要在鼠标移动到特定区域时显示柱状图信息,可以使用 mplcursors 实现。以下是一个完整的解决方案:
import matplotlib.pyplot as plt
import mplcursors
import numpy as np
# 创建数据
x =
y =
labels =
# 创建图形和坐标轴
fig, ax = plt.subplots()
bars = ax.bar(x, y, color='skyblue', edgecolor='black')
# 自定义悬停函数
def on_hover(sel):
# 获取鼠标坐标(数据坐标)
x_mouse, y_mouse = sel.target
# 定义触发区域:x轴0到1,y轴0到3
if 0 <= x_mouse <= 1 and 0 <= y_mouse <= 3:
# 显示第一个柱子的信息(索引0对应x=1)
sel.annotation.set_text(labels)
else:
# 其他区域正常显示对应柱子的信息
index = sel.index
sel.annotation.set_text(labels)
# 启用mplcursors
cursor = mplcursors.cursor(bars, hover=True)
cursor.connect("add", on_hover)
# 设置图形属性
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_title('带悬停功能的柱状图')
ax.set_xticks(x)
plt.show()
工作原理:
1. 创建柱状图,每个柱子有对应的标签信息
2. 定义自定义悬停函数 on_hover,检测鼠标位置
3. 当鼠标在x轴0-1、y轴0-3范围内时,显示第一个柱子的信息
4. 在其他区域时,正常显示对应柱子的信息
关键点说明:
- sel.target 获取鼠标在数据坐标系中的位置
- 通过条件判断确定鼠标是否在指定区域内
- 使用 labels 显示第一个柱子的信息(x=1对应的柱子)
如果只想在指定区域显示悬停,可以简化函数:
def on_hover(sel):
x_mouse, y_mouse = sel.target
if 0 <= x_mouse <= 1 and 0 <= y_mouse <= 3:
sel.annotation.set_text(labels)
else:
sel.annotation.set_visible(False)# 隐藏悬停
这样配置后,当鼠标移动到x轴0-1、y轴0-3区域时,会自动显示第一个柱子的信息。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC matplotlib多柱状图,可以获取x轴和y轴的最大值吗?
kerln888 发表于 2026-02-22 23:52
@FishC matplotlib多柱状图,可以获取x轴和y轴的最大 ...
可以获取。以下是具体方法:
import matplotlib.pyplot as plt
import numpy as np
# 示例数据
labels = ['A', 'B', 'C', 'D']# x轴标签(分类)
data1 = # 第一组柱子高度
data2 = # 第二组柱子高度
data3 = # 第三组柱子高度
x = np.arange(len(labels)) # 柱子的x坐标
width = 0.25 # 柱子的宽度
fig, ax = plt.subplots()
# 绘制多柱状图
rects1 = ax.bar(x - width, data1, width, label='组1')
rects2 = ax.bar(x, data2, width, label='组2')
rects3 = ax.bar(x + width, data3, width, label='组3')
# 获取y轴最大值(所有柱子中的最大高度)
all_heights = data1 + data2 + data3
y_max = max(all_heights)# 或者用 np.max(all_heights)
print(f"Y轴最大值 (数据): {y_max}")
# 获取x轴“最大值”的两种常见理解:
# 1. 如果你的x轴是数值型(例如 x = ),想要x坐标最大值:
if isinstance(x, np.ndarray):
x_max_coord = x.max() + width * 2# 考虑到最右侧柱子的偏移
print(f"X轴坐标最大值 (考虑多柱偏移): {x_max_coord}")
# 2. 更常见的情况:x轴是分类,我们关心有多少组(即刻度数量)
x_group_count = len(labels)
print(f"X轴分组数量: {x_group_count}")
# 你也可以直接从坐标轴对象获取当前范围
# 注意:这通常在绘制后调用,返回的是当前视图范围
xlim_current = ax.get_xlim()
ylim_current = ax.get_ylim()
print(f"当前X轴范围: {xlim_current}")
print(f"当前Y轴范围: {ylim_current}")
# 设置图表
ax.set_ylabel('Y值')
ax.set_xlabel('X分组')
ax.set_title('多柱状图示例')
ax.set_xticks(x)
ax.set_xticklabels(labels)
ax.legend()
plt.show()
关键点解释:
1.Y轴最大值:直接比较所有柱状图数据列表,找出最大值。
2.X轴“最大值”:
* 对于分类轴,通常指分组数量 len(labels)。
* 对于数值轴,可计算最大坐标值(需考虑多柱的偏移宽度)。
3.绘图后,可用 ax.get_xlim() 和 ax.get_ylim() 获取坐标轴当前显示范围。
这样就能灵活获取和控制图表边界了。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC 回到刚刚的问题。使用mplcursors对matplotlib增加悬停功能。柱状图x坐标不是数字1,2,3,而是苹果,香蕉,荔枝。y轴坐标是1%,2%,3%.如何实现鼠标移动到x轴0到苹果,y轴0-3%这个区域,显示x坐标苹果的柱状信息。移动到x轴苹果到香蕉,y轴0-3%这个区域,显示x坐标香蕉的柱状信息。移动到x轴香蕉到荔枝,y轴0-3%这个区域,显示x坐标荔枝的柱状信息。
kerln888 发表于 2026-02-22 23:57
@FishC 回到刚刚的问题。使用mplcursors对matplotlib ...
要使用 mplcursors 实现柱状图的悬停功能,并按照指定区域显示对应分类的信息,可以按照以下步骤操作:
1. 创建柱状图时,直接使用分类数据(如苹果、香蕉、荔枝)作为 x 坐标,matplotlib 会自动处理。
2. 使用 mplcursors 绑定到柱状图对象,并设置悬停事件。
3. 在悬停事件中,通过索引获取对应的分类和数值,并显示在注解中。
以下是完整的代码示例:
import matplotlib.pyplot as plt
import mplcursors
# 数据准备
x_categories = ['苹果', '香蕉', '荔枝']
y_values = # 百分比数值
# 创建柱状图
fig, ax = plt.subplots()
bars = ax.bar(x_categories, y_values)
# 设置 y 轴标签和范围
ax.set_ylabel('百分比')
ax.set_ylim(0, max(y_values) + 1)
# 初始化 mplcursors,绑定到柱状图对象
cursor = mplcursors.cursor(bars, hover=True)
# 定义悬停时显示的信息
@cursor.connect("add")
def on_add(sel):
# 获取当前柱子的索引
index = sel.target.index
# 根据索引获取分类和数值
label = x_categories
value = y_values
# 设置注解文本
sel.annotation.set_text(f"{label}: {value}%")
plt.show()
代码说明:
- x_categories 存储分类标签,y_values 存储对应的百分比数值。
- ax.bar() 直接使用分类数据创建柱状图,每个柱子对应一个分类。
- mplcursors 绑定到 bars 对象,当鼠标悬停在柱子上时触发事件。
- on_add 函数中,通过 sel.target.index 获取柱子索引,从而得到分类和数值,并设置注解文本。
运行此代码后,鼠标悬停在每个柱子上(即对应的 x 轴区域)时,会显示该柱子的分类和百分比信息。例如,悬停在第一个柱子上(对应 x 轴“苹果”区域)会显示“苹果: 1%”。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC matplotlib legend可以放在坐标外吗?比如放在坐标下面
kerln888 发表于 2026-02-23 00:20
@FishC matplotlib legend可以放在坐标外吗?比如放在 ...
是的,Matplotlib 的图例可以放在坐标轴外部,比如坐标下面。你可以使用 bbox_to_anchor 参数来指定图例的位置。
示例代码:
import matplotlib.pyplot as plt
# 创建示例数据
x =
y1 =
y2 =
plt.plot(x, y1, label='Line 1')
plt.plot(x, y2, label='Line 2')
# 将图例放在坐标轴下方,居中
plt.legend(bbox_to_anchor=(0.5, -0.1), loc='upper center')
# 调整图形边界,确保图例显示完整
plt.subplots_adjust(bottom=0.2)
plt.show()
在这个例子中,bbox_to_anchor=(0.5, -0.1) 将图例定位在坐标轴下方(水平居中,y 坐标为负值表示在轴外),loc='upper center' 设置图例的锚点在图例的上方中心。使用 plt.subplots_adjust(bottom=0.2) 可以增加底部空间,防止图例被裁剪。你也可以尝试其他位置,比如将 bbox_to_anchor 设置为 (0, -0.1) 来左对齐,或者调整 loc 参数如 'lower center' 来微调。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC matplotlib子图的legend可以放在坐标外吗?ax1 = fig.add_subplot(gs),比如放在坐标下面
kerln888 发表于 2026-02-23 00:39
@FishC matplotlib子图的legend可以放在坐标外吗?ax1 ...
可以,matplotlib 的子图图例可以通过 bbox_to_anchor 参数放置在坐标轴外部,例如坐标下方。以下是一个示例代码,展示如何实现:
import matplotlib.pyplot as plt
# 创建图形和网格子图
fig = plt.figure()
gs = fig.add_gridspec(1, 1)# 简单网格示例
ax1 = fig.add_subplot(gs)# 创建子图
# 绘制示例数据
ax1.plot(, , label='示例曲线')
# 添加图例,放置在坐标轴下方外部
# bbox_to_anchor 的 (0.5, -0.1) 表示在坐标轴中心下方(负值表示外部)
ax1.legend(loc='upper center', bbox_to_anchor=(0.5, -0.1), ncol=1)
# 调整布局以避免图例被裁剪
plt.tight_layout()
plt.show()
关键点:
- 使用 bbox_to_anchor 指定图例位置,例如 (0.5, -0.1) 将图例放在子图中心下方。
- loc='upper center' 设置图例锚点为子图上部中心,与 bbox_to_anchor 配合。
- plt.tight_layout() 自动调整布局,确保图例可见。
如果图例仍被裁剪,可手动调整子图位置,例如:
plt.subplots_adjust(bottom=0.2)# 为底部留出更多空间
此方法适用于任何子图,包括通过 add_subplot(gs[...]) 创建的。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC matplotlib的legend过长,可以分几列排列吗?
kerln888 发表于 2026-02-23 11:03
@FishC matplotlib的legend过长,可以分几列排列吗?
是的,matplotlib的图例可以通过设置 ncol 参数来分列排列。这个参数指定了图例的列数,从而将过长的图例分成多行显示。
例如,如果你有多个图例项,可以这样设置:
import matplotlib.pyplot as plt
# 示例数据
x =
y1 =
y2 =
y3 =
y4 =
plt.plot(x, y1, label='Line 1')
plt.plot(x, y2, label='Line 2')
plt.plot(x, y3, label='Line 3')
plt.plot(x, y4, label='Line 4')
# 添加图例,设置分两列显示
plt.legend(ncol=2)
plt.show()
在这个例子中,ncol=2 会让图例分两列排列。你可以根据需要调整这个数字,比如 ncol=3 分三列。
如果图例项很多,分列排列可以有效避免图例过长影响图表美观。此外,你还可以结合其他参数(如 loc 调整位置)进一步优化图例显示。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC js,data-forge怎么对series去重?比如:
let dataFrame = new DataFrame([
{
A: 1,
B: 10,
},
{
A: 2,
B: 20,
},
{
A: 2,
B: 30,
}
]);
dataFrame.getSeries("A")怎么去重
kerln888 发表于 2026-02-23 19:29
@FishC js,data-forge怎么对series去重?比如:
let ...
在 Data-Forge 中,可以使用 distinct() 方法对 Series 进行去重。该方法会返回一个新的 Series,包含原 Series 中的唯一值。
示例代码:
let dataFrame = new DataFrame([
{ A: 1, B: 10 },
{ A: 2, B: 20 },
{ A: 2, B: 30 }
]);
let seriesA = dataFrame.getSeries("A");
let uniqueSeries = seriesA.distinct();
console.log(uniqueSeries.toArray()); // 输出:
这样,uniqueSeries 就是去重后的 Series。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC
let dataFrame = new DataFrame([
{ A: 2021-06-26T03:45:00.000Z, B: 10 },
{ A: 2021-06-27T03:45:00.000Z, B: 20 },
{ A: 2021-06-28T03:45:00.000Z, B: 30 }
]);
使用Data-Forge,let seriesA = dataFrame.getSeries("A");seriesA如何只取年
kerln888 发表于 2026-02-23 20:33
@FishC
let dataFrame = new DataFrame();
使用Dat ...
你好!要从系列 A 中只取年份,你可以使用 select 方法将每个日期值转换为年份。假设系列中的值是日期字符串,你需要先将它们转换为 Date 对象,然后提取年份。
以下是示例代码:
let dataFrame = new DataFrame([
{ A: '2021-06-26T03:45:00.000Z', B: 10 },
{ A: '2021-06-27T03:45:00.000Z', B: 20 },
{ A: '2021-06-28T03:45:00.000Z', B: 30 }
]);
let seriesA = dataFrame.getSeries("A");
let yearSeries = seriesA.select(value => new Date(value).getFullYear());
// 查看结果
console.log(yearSeries.toArray()); // 输出:
注意:在原始代码中,日期值没有引号,但在 JavaScript 中,如果直接写日期字符串,需要引号。所以我在代码中添加了引号。如果你的日期值已经是字符串或 Date 对象,请相应调整。
解释:
- 使用 getSeries 获取系列 A。
- 使用 select 方法对每个值应用一个函数,该函数将值转换为 Date 对象并调用 getFullYear() 获取年份。
- 结果是一个新系列 yearSeries,包含年份。
这样,你就只取了年份。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC
let dataFrame = new DataFrame([
{ A: '2021-06-26T03:45:00.000Z', B: 10, C:'香蕉', D:'猴子' },
{ A: '2021-06-27T03:45:00.000Z', B: 20, C:'香蕉', D:'狮子'},
{ A: '2022-06-28T03:45:00.000Z', B: 30, C:'苹果', D:'大象'},
{ A: '2021-07-28T03:45:00.000Z', B: 50, C:'苹果', D:'猴子'},
{ A: '2025-06-28T03:45:00.000Z', B: 60, C:'梨子', D:'狮子'},
{ A: '2021-09-28T03:45:00.000Z', B: 30, C:'橘子', D:'老虎'},
]);
使用Data-Forge,筛选出A in ,B in ,C in ['苹果', '梨子'] D in ['猴子', '狮子']。应该怎么做
kerln888 发表于 2026-02-23 23:09
@FishC
let dataFrame = new DataFrame();
使用Data ...
要筛选满足多个条件的数据,可以使用 Data-Forge 的 where 方法,结合逻辑运算符组合条件。以下是对应的 JavaScript 代码:
const DataFrame = require('data-forge');
let dataFrame = new DataFrame([
{ A: '2021-06-26T03:45:00.000Z', B: 10, C:'香蕉', D:'猴子' },
{ A: '2021-06-27T03:45:00.000Z', B: 20, C:'香蕉', D:'狮子'},
{ A: '2022-06-28T03:45:00.000Z', B: 30, C:'苹果', D:'大象'},
{ A: '2021-07-28T03:45:00.000Z', B: 50, C:'苹果', D:'猴子'},
{ A: '2025-06-28T03:45:00.000Z', B: 60, C:'梨子', D:'狮子'},
{ A: '2021-09-28T03:45:00.000Z', B: 30, C:'橘子', D:'老虎'},
]);
// 提取年份并转换为数字
dataFrame = dataFrame.withSeries('Year',
dataFrame.deflate(row => new Date(row.A).getFullYear()));
// 筛选条件
const filtered = dataFrame.where(row => {
const year = row.Year;
const bValue = row.B;
const cValue = row.C;
const dValue = row.D;
return (.includes(year) &&
.includes(bValue) &&
['苹果', '梨子'].includes(cValue) &&
['猴子', '狮子'].includes(dValue));
});
console.log(filtered.toString());
这段代码执行以下步骤:
1. 使用 withSeries 添加一个新列 "Year",提取日期列 A 的年份。
2. 在 where 方法中定义筛选条件,使用 includes 检查每个值是否在指定范围内。
3. 条件之间使用逻辑与 (&&) 连接,确保同时满足所有条件。
输出结果将只包含满足所有条件的行:
- A 列年份为 2021 或 2022
- B 列值为 30 或 50
- C 列值为 "苹果" 或 "梨子"
- D 列值为 "猴子" 或 "狮子"
如果不希望保留 "Year" 列,可以在筛选后使用 dropSeries('Year') 删除。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
@FishC
let dataFrame = new DataFrame([
{ A: '2021-06-26T03:45:00.000Z', B: 10, C:'香蕉', D:'猴子' },
{ A: '2021-06-27T03:45:00.000Z', B: 20, C:'香蕉', D:'狮子'},
{ A: '2022-06-28T03:45:00.000Z', B: 30, C:'苹果', D:'大象'},
{ A: '2021-07-28T03:45:00.000Z', B: 50, C:'苹果', D:'猴子'},
{ A: '2025-06-28T03:45:00.000Z', B: 60, C:'梨子', D:'狮子'},
{ A: '2021-09-28T03:45:00.000Z', B: 30, C:'橘子', D:'老虎'},
]);
使用Data-Forge,筛选出A in ,A in ,C in ['苹果', '梨子'] D in ['猴子', '狮子']。应该怎么做