Matplotlib 中文用户指南 4.5 标注

本文详细介绍Matplotlib中的标注功能,包括基本标注、高级标注、自定义样式等,展示如何使用annotate和text函数添加文本标注和箭头,以及如何利用各种坐标系统进行精确控制。

标注

原文:Annotation

译者:飞龙

协议:CC BY-NC-SA 4.0

基本标注

使用text()会将文本放置在轴域的任意位置。 文本的一个常见用例是标注绘图的某些特征,而annotate()方法提供辅助函数,使标注变得容易。 在标注中,有两个要考虑的点:由参数xy表示的标注位置和xytext的文本位置。 这两个参数都是(x, y)元组。

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = ax.plot(t, s, lw=2)

ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
            arrowprops=dict(facecolor='black', shrink=0.05),
            )

ax.set_ylim(-2,2)
plt.show()

源代码

在该示例中,xy(箭头尖端)和xytext位置(文本位置)都以数据坐标为单位。 有多种可以选择的其他坐标系 - 你可以使用xycoordstextcoords以及下列字符串之一(默认为data)指定xyxytext的坐标系。

| 参数 | 坐标系 |
| 'figure points' | 距离图形左下角的点数量 |
| 'figure pixels' | 距离图形左下角的像素数量 |
| 'figure fraction' | 0,0 是图形左下角,1,1 是右上角 |
| 'axes points' | 距离轴域左下角的点数量 |
| 'axes pixels' | 距离轴域左下角的像素数量 |
| 'axes fraction' | 0,0 是轴域左下角,1,1 是右上角 |
| 'data' | 使用轴域数据坐标系 |

例如将文本以轴域小数坐标系来放置,我们可以:

ax.annotate('local max', xy=(3, 1),  xycoords='data',
            xytext=(0.8, 0.95), textcoords='axes fraction',
            arrowprops=dict(facecolor='black', shrink=0.05),
            horizontalalignment='right', verticalalignment='top',
            )

对于物理坐标系(点或像素),原点是图形或轴的左下角。

或者,你可以通过在可选关键字参数arrowprops中提供箭头属性字典来绘制从文本到注释点的箭头。

arrowprops描述
width箭头宽度,以点为单位
frac箭头头部所占据的比例
headwidth箭头的底部的宽度,以点为单位
shrink移动提示,并使其离注释点和文本一些距离
**kwargsmatplotlib.patches.Polygon的任何键,例如facecolor

在下面的示例中,xy点是原始坐标(xycoords默认为'data')。 对于极坐标轴,它在(theta, radius)空间中。 此示例中的文本放置在图形小数坐标系中。 matplotlib.text.Text关键字args,例如horizontalalignmentverticalalignmentfontsize,从annotate传给Text实例。

源代码

注释(包括花式箭头)的所有高上大的内容的更多信息,请参阅高级标注pylab_examples示例代码:annotation_demo.py

不要继续,除非你已经阅读了基本标注text()annotate()

高级标注

使用框和文本来标注

让我们以一个简单的例子来开始。

源代码

pyplot模块(或Axes类的text方法)中的text()函数接受bbox关键字参数,并且在提供时,在文本周围绘制一个框。

与文本相关联的补丁对象可以通过以下方式访问:

bb = t.get_bbox_patch()

返回值是FancyBboxPatch的一个实例,并且补丁属性(如facecoloredgewidth等)可以像平常一样访问和修改。 为了更改框的形状,请使用set_boxstyle方法。

bb.set_boxstyle("rarrow", pad=0.6)

该参数是框样式的名称与其作为关键字参数的属性。 目前,实现了以下框样式。

名称属性
Circlecirclepad=0.3
DArrowdarrowpad=0.3
LArrowlarrowpad=0.3
RArrowrarrowpad=0.3
Roundroundpad=0.3,rounding_size=None
Round4round4pad=0.3,rounding_size=None
Roundtoothroundtoothpad=0.3,tooth_size=None
Sawtoothsawtoothpad=0.3,tooth_size=None
Squaresquarepad=0.3

源代码

注意,属性参数可以在样式名称中用逗号分隔(在初始化文本实例时,此形式可以用作bbox参数的boxstyle的值)。

bb.set_boxstyle("rarrow,pad=0.6")

使用箭头来标注

pyplot模块(或Axes类的annotate方法)中的annotate()函数用于绘制连接图上两点的箭头。

ax.annotate("Annotation",
            xy=(x1, y1), xycoords='data',
            xytext=(x2, y2), textcoords='offset points',
            )

这会使用textcoords中提供的,xytext处的文本标注提供坐标(xycoords)中的xy处的点。 通常,数据坐标中规定了标注点,偏移点中规定了标注文本。 请参阅annotate()了解可用的坐标系。

连接两个点(xyxytext)的箭头可以通过指定arrowprops参数可选地绘制。 为了仅绘制箭头,请使用空字符串作为第一个参数。

ax.annotate("",
            xy=(0.2, 0.2), xycoords='data',
            xytext=(0.8, 0.8), textcoords='data',
            arrowprops=dict(arrowstyle="->",
                            connectionstyle="arc3"),
            )

源代码

箭头的绘制需要几个步骤。

  • 创建两个点之间的连接路径。 这由connectionstyle键值控制。
  • 如果提供了补丁对象(patchApatchB),则会剪切路径以避开该补丁。
  • 路径进一步由提供的像素总量来缩小(shirnkA&shrinkB
  • 路径转换为箭头补丁,由arrowstyle键值控制。

源代码

两个点之间的连接路径的创建由connectionstyle键控制,并且可用以下样式。

名称属性
angleangleA=90,angleB=0,rad=0.0
angle3angleA=90,angleB=0
arcangleA=0,angleB=0,armA=None,armB=None,rad=0.0
arc3rad=0.0
bararmA=0.0,armB=0.0,fraction=0.3,angle=None

注意,angle3arc3中的3意味着所得到的路径是二次样条段(三个控制点)。 如下面将讨论的,当连接路径是二次样条时,可以使用一些箭头样式选项。

每个连接样式的行为在下面的示例中(有限地)演示。 (警告:条形样式的行为当前未定义好,将来可能会更改)。

源代码

然后根据给定的箭头样式将连接路径(在剪切和收缩之后)变换为箭头补丁。

名称属性
-None
->head_length=0.4,head_width=0.2
-[widthB=1.0,lengthB=0.2,angleB=None
|-|widthA=1.0,widthB=1.0
-|>head_length=0.4,head_width=0.2
<-head_length=0.4,head_width=0.2
<->head_length=0.4,head_width=0.2
<|-head_length=0.4,head_width=0.2
<-|>
fancyhead_length=0.4,head_width=0.4,tail_width=0.4
simplehead_length=0.5,head_width=0.5,tail_width=0.2
wedgetail_width=0.3,shrink_factor=0.5

源代码

一些箭头仅适用于生成二次样条线段的连接样式。 他们是fancysimplewedge。 对于这些箭头样式,必须使用angle3arc3连接样式。

如果提供了标注字符串,则patchA默认设置为文本的bbox补丁。

源代码

text命令一样,可以使用bbox参数来绘制文本周围的框。

源代码

默认情况下,起点设置为文本范围的中心。 可以使用relpos键值进行调整。 这些值根据文本的范围进行归一化。 例如,(0,0)表示左下角,(1,1)表示右上角。

源代码

将艺术家放置在轴域的锚定位置

有一类艺术家可以放置在轴域的锚定位置。 一个常见的例子是图例。 这种类型的艺术家可以使用OffsetBox类创建。 mpl_toolkits.axes_grid.anchored_artists中有几个预定义类。

from mpl_toolkits.axes_grid.anchored_artists import AnchoredText
at = AnchoredText("Figure 1a",
                  prop=dict(size=8), frameon=True,
                  loc=2,
                  )
at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
ax.add_artist(at)

源代码

loc关键字与legend命令中含义相同。

一个简单的应用是当艺术家(或艺术家的集合)的像素大小在创建时已知。 例如,如果要绘制一个固定大小为 20 像素 ×20 像素(半径为 10 像素)的圆,则可以使用AnchoredDrawingArea。 实例使用绘图区域的大小创建(以像素为单位)。 用户可以在绘图区任意添加艺术家。 注意,添加到绘图区域的艺术家的范围与绘制区域本身的位置无关,只和初始大小有关。

from mpl_toolkits.axes_grid.anchored_artists import AnchoredDrawingArea

ada = AnchoredDrawingArea(20, 20, 0, 0,
                          loc=1, pad=0., frameon=False)
p1 = Circle((10, 10), 10)
ada.drawing_area.add_artist(p1)
p2 = Circle((30, 10), 5, fc="r")
ada.drawing_area.add_artist(p2)

添加到绘图区域的艺术家不应该具有变换集(它们将被重写),并且那些艺术家的尺寸被解释为像素坐标,即,上述示例中的圆的半径分别是 10 像素和 5 像素。

源代码

有时,你想让你的艺术家按数据坐标(或其他坐标,而不是画布像素)缩放。 你可以使用AnchoredAuxTransformBox类。 这类似于AnchoredDrawingArea,除了艺术家的范围在绘制时由指定的变换确定。

from mpl_toolkits.axes_grid.anchored_artists import AnchoredAuxTransformBox

box = AnchoredAuxTransformBox(ax.transData, loc=2)
el = Ellipse((0,0), width=0.1, height=0.4, angle=30) # in data coordinates!
box.drawing_area.add_artist(el)

上述示例中的椭圆具有在数据坐标中对应于 0.1 和 0.4 的宽度和高度,并且当轴域的视图限制改变时将自动缩放。

源代码

如图例所示,可以设置bbox_to_anchor参数。 使用HPackerVPacker,你可以像图例中一样排列艺术家(事实上,这是图例的创建方式)。

源代码

请注意,与图例不同,默认情况下,bbox_transform设置为IdentityTransform

使用复杂坐标来标注

matplotlib 中的标注支持标注文本中描述的几种类型的坐标。 对于想要更多控制的高级用户,它支持几个其他选项。

  1. Transform实例,例如:

    ax.annotate("Test", xy=(0.5, 0.5), xycoords=ax.transAxes)

    相当于:

    ax.annotate("Test", xy=(0.5, 0.5), xycoords="axes fraction")

    使用它,你可以在其他轴域内标注一个点:

    ax1, ax2 = subplot(121), subplot(122)
    ax2.annotate("Test", xy=(0.5, 0.5), xycoords=ax1.transData,
                 xytext=(0.5, 0.5), textcoords=ax2.transData,
                 arrowprops=dict(arrowstyle="->"))
  2. Artist实例。xy值(或xytext)被解释为艺术家的bboxget_window_extent的返回值)的小数坐标。

    an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data",
                      va="center", ha="center",
                      bbox=dict(boxstyle="round", fc="w"))
    an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1, # (1,0.5) of the an1's bbox
                      xytext=(30,0), textcoords="offset points",
                      va="center", ha="left",
                      bbox=dict(boxstyle="round", fc="w"),
                      arrowprops=dict(arrowstyle="->"))

    源代码

    请注意,你的责任是在绘制an2之前确定坐标艺术家(上例中的an1)的范围。 在大多数情况下,这意味着an2需要晚于an1

  3. 一个返回BboxBaseTransform的实例的可调用对象。 如果返回一个变换,它与 1 相同,如果返回bbox,它与 2 相同。可调用对象应该接受renderer实例的单个参数。 例如,以下两个命令产生相同的结果:

    an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1,
                      xytext=(30,0), textcoords="offset points")
    an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1.get_window_extent,
                      xytext=(30,0), textcoords="offset points")
  4. 指定二元坐标的元组。 第一项用于x坐标,第二项用于y坐标。 例如,

    annotate("Test", xy=(0.5, 1), xycoords=("data", "axes fraction"))

    0.5 的单位是数据坐标,1 的单位是归一化轴域坐标。 你可以像使用元组一样使用艺术家或变换。 例如,

    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(3,2))
    ax=plt.axes([0.1, 0.1, 0.8, 0.7])
    an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data",
                      va="center", ha="center",
                      bbox=dict(boxstyle="round", fc="w"))
    
    an2 = ax.annotate("Test 2", xy=(0.5, 1.), xycoords=an1,
                      xytext=(0.5,1.1), textcoords=(an1, "axes fraction"),
                      va="bottom", ha="center",
                      bbox=dict(boxstyle="round", fc="w"),
                      arrowprops=dict(arrowstyle="->"))
    plt.show()

    源代码

  5. 有时,您希望您的注释带有一些“偏移点”,不是距离注释点,而是距离某些其他点。 OffsetFrom是这种情况下的辅助类。

    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(3,2))
    ax=plt.axes([0.1, 0.1, 0.8, 0.7])
    an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data",
                      va="center", ha="center",
                      bbox=dict(boxstyle="round", fc="w"))
    
    from matplotlib.text import OffsetFrom
    offset_from = OffsetFrom(an1, (0.5, 0))
    an2 = ax.annotate("Test 2", xy=(0.1, 0.1), xycoords="data",
                      xytext=(0, -10), textcoords=offset_from,
                      # xytext is offset points from "xy=(0.5, 0), xycoords=an1"
                      va="top", ha="center",
                      bbox=dict(boxstyle="round", fc="w"),
                      arrowprops=dict(arrowstyle="->"))
    plt.show()

    你可以参考这个链接:pylab_examples example code: annotation_demo3.py.

使用ConnectorPatch

ConnectorPatch类似于没有文本的标注。 虽然在大多数情况下建议使用标注函数,但是当您想在不同的轴上连接点时,ConnectorPatch很有用。

from matplotlib.patches import ConnectionPatch
xy = (0.2, 0.2)
con = ConnectionPatch(xyA=xy, xyB=xy, coordsA="data", coordsB="data",
                      axesA=ax1, axesB=ax2)
ax2.add_artist(con)

上述代码连接了ax1中数据坐标的xy点,与ax2中数据坐标的xy点。这是个简单的例子。

源代码

虽然ConnectorPatch实例可以添加到任何轴,但您可能需要将其添加到绘图顺序中最新的轴,以防止与其他轴重叠。

高级话题

轴域之间的缩放效果

mpl_toolkits.axes_grid.inset_locator定义了一些补丁类,用于互连两个轴域。 理解代码需要一些 mpl 转换如何工作的知识。 但是,利用它的方式很直接。

源代码

定义自定义盒样式

你可以使用自定义盒样式,boxstyle的值可以为如下形式的可调用对象:

def __call__(self, x0, y0, width, height, mutation_size,
             aspect_ratio=1.):
    """
    Given the location and size of the box, return the path of
    the box around it.

      - *x0*, *y0*, *width*, *height* : location and size of the box
      - *mutation_size* : a reference scale for the mutation.
      - *aspect_ratio* : aspect-ratio for the mutation.
    """
    path = ...
    return path

这里是个复杂的例子:

源代码

但是,推荐你从matplotlib.patches.BoxStyle._Base派生,像这样:

from matplotlib.path import Path
from matplotlib.patches import BoxStyle
import matplotlib.pyplot as plt

# we may derive from matplotlib.patches.BoxStyle._Base class.
# You need to override transmute method in this case.

class MyStyle(BoxStyle._Base):
    """
    A simple box.
    """

    def __init__(self, pad=0.3):
        """
        The arguments need to be floating numbers and need to have
        default values.

         *pad*
            amount of padding
        """

        self.pad = pad
        super(MyStyle, self).__init__()

    def transmute(self, x0, y0, width, height, mutation_size):
        """
        Given the location and size of the box, return the path of
        the box around it.

         - *x0*, *y0*, *width*, *height* : location and size of the box
         - *mutation_size* : a reference scale for the mutation.

        Often, the *mutation_size* is the font size of the text.
        You don't need to worry about the rotation as it is
        automatically taken care of.
        """

        # padding
        pad = mutation_size * self.pad

        # width and height with padding added.
        width, height = width + 2.*pad, \
                        height + 2.*pad,

        # boundary of the padded box
        x0, y0 = x0-pad, y0-pad,
        x1, y1 = x0+width, y0 + height

        cp = [(x0, y0),
              (x1, y0), (x1, y1), (x0, y1),
              (x0-pad, (y0+y1)/2.), (x0, y0),
              (x0, y0)]

        com = [Path.MOVETO,
               Path.LINETO, Path.LINETO, Path.LINETO,
               Path.LINETO, Path.LINETO,
               Path.CLOSEPOLY]

        path = Path(cp, com)

        return path


# register the custom style
BoxStyle._style_list["angled"] = MyStyle

plt.figure(1, figsize=(3,3))
ax = plt.subplot(111)
ax.text(0.5, 0.5, "Test", size=30, va="center", ha="center", rotation=30,
        bbox=dict(boxstyle="angled,pad=0.5", alpha=0.2))

del BoxStyle._style_list["angled"]

plt.show()

源代码

与之类似,您可以定义一个自定义的ConnectionStyle和一个自定义的ArrowStyle。 请参阅lib/matplotlib/patches.py的源代码,并查看每个样式类是如何定义的。

import numpy as np import pandas as pd import scipy.fft as fft from scipy import stats import cx_Oracle db = cx_Oracle.connect('yms/YMS@10.66.3.63:1521/rptdb_service') cursor = db.cursor() def process_csv(fill_path, time_column, data_column): """ :param fill_path: :param time_column: :param data_column: :return: """ df = pd.read_csv(fill_path) df[time_column] = pd.to_datetime(df[time_column]) sorted_df = df.sort_values(by=time_column) data_list = sorted_df[data_column].dropna().tolist() return data_list def preprocess_data(raw_data): """ 数据预处理 (使用引用[3]的滤波技术) :param raw_data: 原始传感器数据 :return: 预处理后的数据 """ # 中值滤波 (3点滑动窗口) filtered = np.zeros_like(raw_data) filtered[0] = raw_data[0] filtered[-1] = raw_data[-1] for i in range(1, len(raw_data) - 1): filtered[i] = np.median(raw_data[i - 1:i + 2]) # 数据归一化 (改进版) data_min = np.min(filtered) data_range = np.max(filtered) - data_min if data_range > 1e-6: # 避免除零 return (filtered - data_min) / data_range return filtered class StableSensorAnalyser: def __init__(self, sample_rate=10, min_std=0.05, stability_len=100): """ 稳定状态传感器分析器初始化 :param sample_rate: 采样频率 (Hz) :param min_std: 稳定状态标准差阈值 :param stability_len: 稳定状态最小持续时间 (样本数) """ self.sample_rate = sample_rate self.min_std = min_std self.stability_len = stability_len self.fault_counter = 0 self.fault_threshold = 5 # 连续检测次数阈值 self.history_var = [] # 历史方差记录 self.stable_zones = [] # 识别出的稳定区域 def detect_stable_zones(self, data): """ 自动识别稳定状态区间 (基于标准差阈值) :param data: 预处理后的传感器数据 """ self.stable_zones = [] start_idx = None for i in range(len(data) - self.stability_len): window = data[i:i + self.stability_len] window_std = np.std(window) if window_std < self.min_std: if start_idx is None: start_idx = i # 稳定区域开始 elif start_idx is not None: # 确保最小长度 if i - start_idx >= self.stability_len: self.stable_zones.append((start_idx, i)) start_idx = None # 处理末尾可能存在的稳定区域 if start_idx is not None and len(data) - start_idx >= self.stability_len: self.stable_zones.append((start_idx, len(data))) def dominant_frequency(self, data): """ 计算数据的主频 (基于FFT) :param data: 输入数据 :return: 主频率 (Hz) """ n = len(data) yf = fft.rfft(data) xf = fft.rfftfreq(n, 1 / self.sample_rate) idx = np.argmax(np.abs(yf)) print("xf[idx]: ", xf[idx]) return xf[idx] if idx < len(xf) else 0 def calc_dynamic_threshold(self): """ 计算动态方差阈值 (基于历史数据) :return: 自适应方差阈值 """ if len(self.history_var) < 10: # 需要足够历史数据 return self.min_std ** 2 # 返回初始方差阈值 q1 = np.quantile(self.history_var, 0.25) iqr = stats.iqr(self.history_var) return max(1e-6, q1 - 1.5 * iqr) # 确保正值 def sliding_var_detect(self, data): """ 滑动窗口方差检测 (使用Welford算法优化) :param data: 输入数据 :return: 故障点索引列表 """ faults = [] freq = self.dominant_frequency(data) # 自适应窗口大小 ($w = \max(30,\ \lceil 2f_s/\hat{f}_{\text{noise}} \rceil$) w = max(30, int(2 * self.sample_rate / (freq + 1e-9))) # 初始化Welford算法变量 n = 0 mean = 0 M2 = 0 for i in range(len(data)): # Welford增量计算方差 n += 1 delta = data[i] - mean mean += delta / n delta2 = data[i] - mean M2 += delta * delta2 # 当窗口填满后开始检测 if i >= w: # 移除离开窗口的数据点 old_val = data[i - w] old_mean = mean - (data[i] - mean) / (n - 1) # 近似旧均值 delta_old = old_val - old_mean M2 = max(0, M2 - delta_old * (data[i] - old_mean)) n -= 1 mean = old_mean # 计算窗口方差 if n > 1: variance = M2 / (n - 1) self.history_var.append(variance) # 获取当前动态阈值 threshold = self.calc_dynamic_threshold() # 故障检测逻辑 if variance < threshold: # MAD异常值检查抑制误报 median = np.median(data[i - w:i]) mad = np.median(np.abs(data[i - w:i] - median)) if mad > 0 and np.abs(data[i] - median) < 3 * mad: self.fault_counter += 1 else: self.fault_counter = max(0, self.fault_counter - 1) else: self.fault_counter = max(0, self.fault_counter - 1) # 触发故障报警 if self.fault_counter >= self.fault_threshold: faults.append(i) self.fault_counter = 0 # 重置计数器避免连续报警 return faults def analyse_sensor_data(self, raw_data): """ 完整分析流程入口 :param raw_data: 原始传感器数据 :return: (稳定区域列表, 故障点列表, 预处理数据) """ processed = preprocess_data(raw_data) self.detect_stable_zones(processed) all_faults = [] for start, end in self.stable_zones: segment = processed[start:end] faults_in_segment = self.sliding_var_detect(segment) # 转换回原始索引 all_faults.extend([start + idx for idx in faults_in_segment]) return self.stable_zones, all_faults, processed # ===================== 使用示例 ===================== if __name__ == "__main__": # # 生成模拟传感器数据 (包含稳定段和卡值故障) # sample_rate = 50 # 50 Hz采样率 # time = np.linspace(0, 10, 10 * sample_rate) # 10秒数据 # # # 创建数据:正常波动 + 稳定段 + 卡值故障 # data = np.sin(2 * np.pi * 0.5 * time) + np.random.normal(0, 0.1, len(time)) # # # 添加稳定段 (5-7秒) # data[5 * sample_rate:7 * sample_rate] = np.full(sample_rate * 2, 1.0) + np.random.normal(0, 0.01, sample_rate * 2) # # # 添加卡值故障 (8-9秒) # data[8 * sample_rate:9 * sample_rate] = np.full(sample_rate, 1.2) data = process_csv("D:/1106748/28317FDC081900-04.csv", "time_stamp", "var15") print(data); # 初始化分析器 analyser = StableSensorAnalyser(sample_rate=100) # 执行分析 stable_zones, faults, processed_data = analyser.analyse_sensor_data(data) # 输出结果 print(f"检测到稳定区域: {stable_zones}") print(f"检测到卡值故障点: {faults}") print(f"预处理数据长度: {len(processed_data)}") # # 可视化结果 (需要matplotlib) # try: # import matplotlib.pyplot as plt # # plt.figure(figsize=(12, 6)) # plt.plot(time, data, 'b-', label='原始数据') # plt.plot(time, processed_data, 'g-', alpha=0.7, label='预处理数据') # # # 标记稳定区域 # for start, end in stable_zones: # plt.axvspan(time[start], time[end], color='yellow', alpha=0.3) # # # 标记故障点 # if faults: # fault_times = [time[i] for i in faults] # plt.plot(fault_times, [processed_data[i] for i in faults], 'rx', markersize=8, label='卡值故障') # # plt.title('传感器数据稳定性分析') # plt.xlabel('时间 (秒)') # plt.ylabel('传感器读数') # plt.legend() # plt.grid(True) # plt.show() # except ImportError: # print("可视化需要matplotlib库") 我希望将生成的list画成图可视化出来
最新发布
10-31
<think>我们讨论的是如何将代码中生成的列表数据(如稳定区域、故障点、预处理数据等列表)进行可视化绘图。 根据用户之前的上下文,用户可能在处理一些信号处理或数据分析任务,并且已经有一些列表形式的数据需要可视化。 常见的可视化需求包括: 1. 绘制折线图(随时间变化的信号) 2. 绘制散点图(故障点在二维平面的分布) 3. 绘制柱状图(不同区域的统计信息) 我们将使用Python中常用的可视化库matplotlib和seaborn,以及之前引用中提到的pyecharts(用于交互式图表)来展示。 步骤: 1. 导入必要的库 2. 根据数据特点选择合适的图表类型 3. 绘制图形并设置标签、标题等 4. 显示或保存图形 我们将分别针对三种常见的数据情况(稳定区域、故障点、预处理数据)给出示例。 </think>### Python数据可视化方法:列表数据绘图实战指南 #### 1. 基础折线图绘制(适合时序数据) ```python import matplotlib.pyplot as plt # 示例数据(稳定区域数据) stable_zones = [0.85, 0.92, 0.88, 0.91, 0.93, 0.95] # 基础绘图 plt.figure(figsize=(10, 5)) plt.plot(stable_zones, marker='o', linestyle='-', color='g', label='稳定区域') # 定制化设置 plt.title('设备运行稳定区域分析', fontsize=14) plt.xlabel('时间序列', fontsize=12) plt.ylabel('稳定系数', fontsize=12) plt.grid(True, alpha=0.3) plt.legend() plt.show() ``` ![稳定区域折线图](https://via.placeholder.com/400x200?text=稳定区域可视化) *图1:稳定区域数据的折线图可视化[^3]* #### 2. 散点图绘制(适合故障点分布) ```python # 示例故障点数据 [(x坐标, y坐标, 故障等级)] fault_points = [(2.3, 4.5, 1), (5.6, 3.1, 3), (7.8, 6.2, 2), (3.4, 2.9, 3)] # 提取坐标和等级 x = [p[0] for p in fault_points] y = [p[1] for p in fault_points] levels = [p[2]*150 for p in fault_points] # 气泡大小映射故障等级 plt.figure(figsize=(8, 6)) plt.scatter(x, y, s=levels, alpha=0.7, c=levels, cmap='Reds') # 添加标注 for i, (xi, yi) in enumerate(zip(x, y)): plt.text(xi+0.1, yi+0.1, f'F{i+1}', fontsize=9) plt.colorbar(label='故障严重程度') plt.title('设备故障点分布热力图', fontsize=14) plt.xlabel('X坐标', fontsize=12) plt.ylabel('Y坐标', fontsize=12) plt.grid(True, linestyle='--', alpha=0.3) plt.show() ``` #### 3. 使用Pyecharts交互式图表(适合预处理数据) ```python from pyecharts.charts import Bar from pyecharts import options as opts # 示例预处理数据 preprocessed_data = [('清洗', 120), ('标准化', 85), ('降噪', 65), ('特征提取', 45)] # 创建柱状图 bar = ( Bar() .add_xaxis([d[0] for d in preprocessed_data]) .add_yaxis("耗时(ms)", [d[1] for d in preprocessed_data], category_gap="50%") .set_global_opts( title_opts=opts.TitleOpts(title="数据预处理各阶段耗时"), toolbox_opts=opts.ToolboxOpts(is_show=True), datazoom_opts=opts.DataZoomOpts(is_show=True) ) ) # 生成HTML文件或在Jupyter中显示 bar.render("preprocessing_time.html") ``` #### 4. 多图组合分析 ```python fig, axes = plt.subplots(2, 2, figsize=(12, 8)) # 子图1:原始数据分布 axes[0, 0].hist(raw_data, bins=20, color='skyblue', alpha=0.8) axes[0, 0].set_title('原始数据分布') # 子图2:预处理后数据 axes[0, 1].plot(processed_data, 'r-', linewidth=1) axes[0, 1].set_title('预处理后时序') # 子图3:故障点三维分布 ax3d = fig.add_subplot(2, 2, (3,4), projection='3d') x, y, z = zip(*fault_points_3d) ax3d.scatter(x, y, z, c=z, cmap='viridis') ax3d.set_title('故障点三维分布') plt.tight_layout() plt.show() ``` #### 5. 特殊数据类型可视化技巧 | 数据类型 | 推荐图表 | 关键参数 | |----------|----------|----------| | **周期数据** | 极坐标图 | `plt.subplot(polar=True)` | | **频谱数据** | 功率谱图 | `plt.psd(data, Fs=sample_rate)` | | **分类数据** | 饼图 | `plt.pie(sizes, labels=labels)` | | **相关性数据** | 热力图 | `seaborn.heatmap(correlation_matrix)` | ### 最佳实践建议 1. 数据标准化预处理:确保数据在绘图前完成归一化处理 ```python from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler(feature_range=(0, 1)) normalized_data = scaler.fit_transform(data) ``` 2. 交互式探索:推荐在Jupyter中使用`%matplotlib widget`启用交互控件 3. 动态数据更新:使用`FuncAnimation`实现实时数据流可视化 ```python from matplotlib.animation import FuncAnimation def update(frame): line.set_ydata(new_data[frame]) return line, ani = FuncAnimation(fig, update, frames=100, interval=50) ``` 4. 导出高质量图像:使用矢量格式保存专业报告用图 ```python plt.savefig('analysis.svg', format='svg', dpi=300) ``` > 可视化不仅是展示工具,更是数据分析的重要手段。选择合适的图表类型能有效揭示数据内在规律[^2][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值