matplotlib的功能及中文字体和数学符号等显示问题的处理

matplotlib的功能

matplotlib 是 Python 中一个非常强大的绘图库,广泛应用于数据可视化领域。跨平台兼容:支持 Windows/macOS/Linux

matplotlib的安装和基本情况,可参见 https://blog.csdn.net/cnds123/article/details/135904075

下面先简要介绍matplotlib的功能

基本模块

matplotlib.pyplot是 matplotlib 的核心模块,提供了一个类似于 MATLAB 的绘图接口,非常适合交互式绘图。

matplotlib.pyplot是 matplotlib 的核心模块,提供了一个类似于 MATLAB 的绘图接口,非常适合交互式绘图。这是最常用的模块,提供了类似MATLAB的绘图接口。

示例

import matplotlib.pyplot as plt

# 绘制一条简单的折线图
x = [1, 2, 3, 4, 5]
y = [1, 4, 9, 16, 25]

plt.plot(x, y, label="y = x^2")   # 绘制折线图
plt.title("Simple Line Plot")     # 设置标题
plt.xlabel("X-axis")          # 设置X轴标签
plt.ylabel("Y-axis")          # 设置Y轴标签
plt.legend()             # 添加图例
plt.grid(True)             # 添加网格
plt.show()             # 显示图形

运行效果:

matplotlib.figure:

用于创建和管理整个图形容器(Figure对象),可以包含多个子图(Axes)。

顺便提示,当您使用 import matplotlib.pyplot as plt 后,可以直接通过 plt.figure() 创建图形对象,不需要额外导入 matplotlib.figure。只有在一些特殊情况下,比如您需要直接使用 Figure 类的特定方法或属性,或者在没有导入 pyplot 的情况下创建独立的 Figure 对象时,才需要明确导入 matplotlib.figure。【from matplotlib.figure import Figure 主要用于后端无关的图形创建,特别是在需要嵌入到其他GUI框架或Web应用中时使用。】

示例

import matplotlib.pyplot as plt

# 创建一个 Figure 对象
fig = plt.figure(figsize=(10, 5))  # figsize 设置图形大小

# 添加第一个子图
ax1 = fig.add_subplot(1, 2, 1)  # 1行2列的第1个
ax1.plot([1, 2, 3], [1, 4, 9], 'r')  # 绘制红色折线图
ax1.set_title("Subplot 1")      # 设置子图标题
ax1.set_xlabel("X-axis")       # 设置X轴标签
ax1.set_ylabel("Y-axis")       # 设置Y轴标签

# 添加第二个子图
ax2 = fig.add_subplot(1, 2, 2)  # 1行2列的第2个
ax2.bar([1, 2, 3], [1, 4, 9])   # 绘制柱状图
ax2.set_title("Subplot 2")      # 设置子图标题
ax2.set_xlabel("X-axis")      # 设置X轴标签
ax2.set_ylabel("Y-axis")      # 设置Y轴标签

plt.show()         # 显示图形

运行效果:

matplotlib.axes:表示图形中的一个绘图区域,表示具体的绘图区域,提供更精细的控制,可以设置坐标轴范围、标题、标签等。

示例

import matplotlib.pyplot as plt

# 创建一个 Figure 和一个 Axes
fig, ax = plt.subplots()

# 绘制散点图
x = [1, 2, 3, 4, 5]
y = [1, 4, 9, 16, 25]
ax.scatter(x, y, color='blue', marker='o')  # 绘制蓝色圆点散点图

# 设置坐标轴范围
ax.set_xlim(0, 6)  # X轴范围
ax.set_ylim(0, 30)  # Y轴范围

# 设置标题和标签
ax.set_title("Scatter Plot")
ax.set_xlabel("X-axis")
ax.set_ylabel("Y-axis")

# 添加网格
ax.grid(True)

plt.show()   # 显示图形

运行效果:

【pyplot 模块已经包含了创建和管理 Figure 和 Axes 对象的所有常用功能。

通常只需要 import matplotlib.pyplot as plt 就足够了。

直接导入 matplotlib.figure 或 matplotlib.axes 主要用于高级自定义或特殊场景。】

高级模块

mplot3d:3D 绘图(曲面、散点、柱状图等)

示例:三维曲面图

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D  # 导入3D绘图模块

# 创建数据
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))  # 创建一个正弦曲面

# 创建图形和3D坐标轴
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')  # 指定为3D坐标轴

# 绘制曲面图
ax.plot_surface(X, Y, Z, cmap='viridis')  # 使用颜色映射

# 设置标题和标签
ax.set_title("3D Surface Plot")
ax.set_xlabel("X-axis")
ax.set_ylabel("Y-axis")
ax.set_zlabel("Z-axis")

plt.show()

运行效果:

FuncAnimation:动画支持

示例:简单的动画

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

# 创建图形和坐标轴
fig, ax = plt.subplots()
x = np.linspace(0, 2 * np.pi, 100)
line, = ax.plot(x, np.sin(x))  # 初始曲线

# 更新函数
def update(frame):
    line.set_ydata(np.sin(x + frame / 10))  # 更新曲线的 y 值
    return line,  # 返回更新的对象

# 创建动画
ani = FuncAnimation(fig, update, frames=range(100), blit=True)

# 显示动画
plt.show()

运行效果:

其它

支持中文显示,但需要进行一些显式配置:

plt.rcParams['font.sans-serif'] = ['SimHei']  # Windows

plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']  # macOS

plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示异常

完美兼容 NumPy、Pandas、SciPy

常用函数的语法和作用
plt.title(label, fontdict=None, loc='center', pad=None, **kwargs)
作用
    为当前图表添加标题。
参数
    label:标题文本(字符串)。
    fontdict:可选,字典类型,用于设置字体属性(如大小、颜色等),如 {'fontsize':14, 'color':'red'}。
    loc:可选,标题位置,取值为 'center'(默认)、'left'、'right'。
    pad:可选,标题与图表顶部的间距(浮点数)。单位为点(points)。
    **kwargs:其他可选参数,例如 fontsize、color 等,如 fontsize=12, color='blue'。
示例
    plt.title('正弦函数图像', fontdict={'fontsize': 16, 'color': 'blue'})

plt.xlabel(xlabel, fontdict=None, labelpad=None, **kwargs)
作用
    为 X 轴添加标签。
参数
    xlabel:标签文本(字符串)。
    fontdict:可选,设置字体属性。
    labelpad:可选,标签与坐标轴( X 轴)的间距,单位为点(points)。
    **kwargs:其他可选参数,例如 fontsize、color 等。
示例
    plt.xlabel('时间 (秒)', fontdict={'fontsize': 12})

plt.ylabel(ylabel, fontdict=None, labelpad=None, **kwargs)
作用
    为 Y 轴添加标签。
参数
    与 plt.xlabel() 相同。
示例
    plt.ylabel('温度 (°C)', rotation=0, labelpad=20)  # rotation=0 让标签水平显示

plt.plot(*args, scalex=True, scaley=True, data=None, **kwargs)
作用
    绘制折线图或散点图。
参数
    *args:可变参数,支持多种形式:
        x, y:X 和 Y 坐标数组(如 plt.plot([1,2,3], [4,5,6]))。
        y:仅 Y 坐标(此时 X 默认为 [0,1,2,...])。
        x, y, format_string:指定线条样式(如 'r--' 表示红色虚线)。
    scalex 和 scaley:布尔值,是否调整 x 轴和 y 轴的范围以适应数据。
    data:数据源,可以是一个 Pandas DataFrame 或其他数据结构。
    **kwargs:其他可选参数,用于自定义线条的样式,例如:
        color/c:线条颜色。
        linestyle/ls:线条样式,如 '-'(实线)、'--'(虚线)、'-.'(点划线)等。
        linewidth/lw:线宽
        marker:数据点的标记样式,如 'o'(圆圈)、's'(正方形)、'*'(星号)等。
        markersize/ms:标记大小
        label:图例标签。
示例
    x = [0, 1, 2, 3, 4]
    y = [0, 2, 4, 6, 8]
    plt.plot(x, y, color='red', linestyle='--', marker='o', label='Line 1')

plt.text(x, y, s, fontdict=None, withdash=False, **kwargs)
作用
    在图表中指定位置添加文本。
参数
    x, y:文本位置的坐标(浮点数)。
    s:文本内容(字符串)。
    fontdict:可选,设置字体属性。
    **kwargs:其他属性,如 rotation(旋转角度)、ha(水平对齐)、va(垂直对齐)等。
        fontsize:文本的字体大小。
        color:文本的颜色。
        ha(水平对齐方式):可选值为 'left'、'center'、'right'。
        va(垂直对齐方式):可选值为 'top'、'center'、'bottom'。
        rotation:旋转角度
示例
    plt.text(2, 5, 'v₀ = 80 m/s', fontsize=12, color='blue', ha='center', va='bottom')

matplotlib中文字体和数学符号等显示问题的处理

下面着重介绍matplotlib中文字体和数学符号等显示方面确实容易出现报错或显示为方框□问题。

先看一个示例

源码:

import matplotlib.pyplot as plt
import numpy as np

# 设置中文字体,解决运行报错或显示为方框□问题
plt.rcParams["font.family"] = ["SimHei","Microsoft YaHei", "KaiTi", "FangSong"]
# 解决负号显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False  

# 生成数据
x = np.linspace(0, 2*np.pi, 100)
y1 = np.sin(x)
y2 = np.cos(x)

# 创建图形和子图
plt.figure(figsize=(10, 6))

# 绘制正弦曲线
plt.plot(x, y1, 'b-', label=r'$\alpha_i=\sin(\theta_i)$')  # (使用 LaTeX 语法)包含下标和希腊字母

# 绘制余弦曲线
plt.plot(x, y2, 'r--', label=r'$\beta^2=\cos^2(\phi)$')  #(使用 LaTeX 语法) 包含上标和希腊字母

# 添加标题和标签
plt.title('中文字体测试:正弦和余弦函数')
plt.xlabel('X轴:弧度')
plt.ylabel('Y轴:函数值')

# 添加图例(包含数学表达式)
plt.legend(loc='upper right')

# 添加文本注释(包含上下标和根号)
plt.text(3.5, 0.6, r'$\sqrt{x^2 + y^2}$', fontsize=15)
plt.text(3.5, 0.4, r'$x_{min}=0$', fontsize=15)
plt.text(3.5, 0.3, r'$y_{max}=1$', fontsize=15)
plt.text(3.5, 0.1, r'$y = \frac{1}{2}gt^2$',fontsize=15) # 分数

# 设置网格
plt.grid(True)

# 显示图形
plt.show()

说明,在代码中,你看到的 r'$...$' 格式就是 LaTeX 数学模式的用法。下面简要解释:

基本语法规则

在 Matplotlib 中使用 LaTeX 语法时,需要注意:

  • 用美元符号 $ 包裹表达式:例如 r'$\alpha$' 会渲染为希腊字母 α。
  • 原始字符串(Raw String:字符串前加 r,避免 Python 转义特殊字符(如 \)。
  • 支持标准 LaTeX 命令:如 \sqrt(根号)、^(上标)、_(下标)等。

 常见数学符号与命令

上标使用 ^,例如:

     r'$x^2$'  # 渲染为 x²

     r'$e^{i\pi}$'  # 渲染为 e^(iπ)

下标使用 _,例如:

     r'$x_{min}$'  # 渲染为 xₘᵢₙ

     r'$\sum_{i=1}^n$'  # 渲染为求和符号,下标 i=1,上标 n

组合使用:

     r'$A_{ij}^2$'  # 渲染为 Aᵢⱼ²

等等

将 Matplotlib 图表嵌入到 Tkinter 窗口的例子

可以使用 Tkinter 结合 Matplotlib 开发程序,并将 Matplotlib 图表嵌入到 Tkinter 窗口中。这种组合允许你创建图形用户界面(GUI),并在其中显示和交互式地更新图表——实现“数据可视化+交互控制”一体化界面

下是一个简单示例,将正弦函数图像嵌入tkinter窗口的示例,支持实时调节参数并更新图表。先给出运行效果:

源码如下:

import tkinter as tk
from tkinter import ttk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import numpy as np

# 设置matplotlib支持中文显示
plt.rcParams["font.family"] = ["SimHei", "Microsoft YaHei"]

class MatplotlibInTkinterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Matplotlib 嵌入 Tkinter 示例")
        self.root.geometry("900x600")
        
        # 创建界面布局
        self.create_widgets()
        self.init_plot()
        
    def create_widgets(self):
        """创建界面控件"""
        # 左侧控制面板
        control_frame = tk.Frame(self.root, width=250, bg="#f0f0f0")
        control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10)
        control_frame.pack_propagate(False)  # 防止控件自动调整大小
        
        # 右侧绘图区域
        self.plot_frame = tk.Frame(self.root, bg="white")
        self.plot_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 左侧控件:参数调节
        tk.Label(control_frame, text="函数参数调节", font=("Arial", 12, "bold")).pack(pady=10)
        
        # 频率调节
        tk.Label(control_frame, text="频率 (Hz):").pack(anchor=tk.W, padx=15, pady=5)
        self.freq_var = tk.DoubleVar(value=1.0)
        freq_scale = tk.Scale(control_frame, from_=0.1, to=5.0, resolution=0.1,
                             orient=tk.HORIZONTAL, variable=self.freq_var,
                             command=self.update_plot)
        freq_scale.pack(fill=tk.X, padx=15, pady=5)
        
        # 幅值调节
        tk.Label(control_frame, text="幅值:").pack(anchor=tk.W, padx=15, pady=5)
        self.amp_var = tk.DoubleVar(value=1.0)
        amp_scale = tk.Scale(control_frame, from_=0.1, to=3.0, resolution=0.1,
                           orient=tk.HORIZONTAL, variable=self.amp_var,
                           command=self.update_plot)
        amp_scale.pack(fill=tk.X, padx=15, pady=5)
        
        # 相位调节
        tk.Label(control_frame, text="相位 (度):").pack(anchor=tk.W, padx=15, pady=5)
        self.phase_var = tk.DoubleVar(value=0)
        phase_scale = tk.Scale(control_frame, from_=0, to=360, resolution=10,
                             orient=tk.HORIZONTAL, variable=self.phase_var,
                             command=self.update_plot)
        phase_scale.pack(fill=tk.X, padx=15, pady=5)
        
        # 重置按钮
        reset_btn = tk.Button(control_frame, text="重置参数", command=self.reset_params,
                           bg="#4CAF50", fg="white", font=("Arial", 10))
        reset_btn.pack(pady=15)
        
    def init_plot(self):
        """初始化图表"""
        # 创建matplotlib的Figure和Axes对象
        self.fig, self.ax = plt.subplots(figsize=(7, 5), dpi=100, facecolor="white")
        self.ax.set_title("正弦函数图像", fontsize=14)
        self.ax.set_xlabel("x (弧度)")
        self.ax.set_ylabel("y")
        self.ax.grid(True, alpha=0.3)
        
        # 创建Canvas并嵌入到tkinter
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.plot_frame)
        self.canvas.draw()
        canvas_widget = self.canvas.get_tk_widget()
        canvas_widget.pack(fill=tk.BOTH, expand=True)
        
        # 添加工具栏
        toolbar_frame = tk.Frame(self.plot_frame)
        toolbar_frame.pack(side=tk.TOP, fill=tk.X)
        toolbar = NavigationToolbar2Tk(self.canvas, toolbar_frame)
        toolbar.update()
        
        # 初始绘图
        self.update_plot()
        
    def update_plot(self, *args):
        """更新图表数据"""
        # 获取参数
        freq = self.freq_var.get()
        amp = self.amp_var.get()
        phase = np.radians(self.phase_var.get())
        
        # 生成数据
        x = np.linspace(-4*np.pi, 4*np.pi, 1000)
        y = amp * np.sin(freq * x + phase)
        
        # 清除旧图表并绘制新图表
        self.ax.clear()
        self.ax.plot(x, y, color="#2196F3", linewidth=2)
        self.ax.set_title(f"y = {amp}·sin({freq}x + {phase*180/np.pi:.0f}°)", fontsize=12)
        self.ax.set_xlabel("x (弧度)")
        self.ax.set_ylabel("y")
        self.ax.grid(True, alpha=0.3)
        self.ax.set_xlim(-4*np.pi, 4*np.pi)
        self.ax.set_ylim(-amp*1.2, amp*1.2)
        
        # 刷新画布
        self.canvas.draw()
        
    def reset_params(self):
        """重置参数"""
        self.freq_var.set(1.0)
        self.amp_var.set(1.0)
        self.phase_var.set(0)
        self.update_plot()

# 运行程序
if __name__ == "__main__":
    root = tk.Tk()
    app = MatplotlibInTkinterApp(root)
    root.mainloop()

更改扩充上面代码功能

先看运行图:

源码如下:

import tkinter as tk
from tkinter import ttk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np

class DataVisualizationApp:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("数据可视化工具")
        self.root.geometry("1000x700")
        
        # 设置matplotlib参数
        plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
        plt.rcParams['axes.unicode_minus'] = False
        
        self.create_layout()
        self.create_left_panel()
        self.create_right_panel()
        
    def create_layout(self):
        """创建主要布局"""
        # 左侧面板 - 固定宽度
        self.left_frame = tk.Frame(self.root, width=300, bg="#f8f9fa")
        self.left_frame.pack(side="left", fill="y", padx=5, pady=5)
        self.left_frame.pack_propagate(False)
        
        # 右侧面板
        self.right_frame = tk.Frame(self.root, bg="white")
        self.right_frame.pack(side="right", fill="both", expand=True, padx=5, pady=5)
        
    def create_left_panel(self):
        """创建左侧控制面板"""
        # === 控制参数区域 ===
        control_frame = tk.LabelFrame(self.left_frame, text="控制参数", 
                                    font=("Microsoft YaHei", 11, "bold"), 
                                    fg="#ff6600", bg="#f8f9fa")
        control_frame.pack(fill="x", padx=10, pady=10)
        
        # 配置列权重
        control_frame.columnconfigure(1, weight=1)
        
        # 函数类型选择
        tk.Label(control_frame, text="函数类型:", bg="#f8f9fa").grid(
            row=0, column=0, sticky="w", padx=5, pady=8)
        self.func_var = tk.StringVar(value="sin")
        func_combo = ttk.Combobox(control_frame, textvariable=self.func_var, 
                                values=["sin", "cos", "tan", "exp"], 
                                width=20, state="readonly")
        func_combo.grid(row=0, column=1, padx=5, pady=8, sticky="ew")
        func_combo.bind("<<ComboboxSelected>>", self.update_plot)
        
        # 频率调节
        freq_frame = tk.Frame(control_frame, bg="#f8f9fa")
        freq_frame.grid(row=1, column=0, columnspan=2, sticky="ew", padx=5, pady=5)
        freq_frame.columnconfigure(1, weight=1)
        
        tk.Label(freq_frame, text="频率:", bg="#f8f9fa").grid(row=0, column=0, sticky="w")
        self.freq_var = tk.DoubleVar(value=1.0)
        self.freq_label = tk.Label(freq_frame, text="1.0", bg="#f8f9fa", fg="#333")
        self.freq_label.grid(row=0, column=2, sticky="e", padx=(10,0))
        
        freq_scale = tk.Scale(freq_frame, from_=0.1, to=5.0, resolution=0.1, 
                            orient="horizontal", variable=self.freq_var,
                            command=self.on_freq_change, showvalue=0, bg="#f8f9fa")
        freq_scale.grid(row=1, column=0, columnspan=3, sticky="ew", pady=2)
        
        # 幅值调节
        amp_frame = tk.Frame(control_frame, bg="#f8f9fa")
        amp_frame.grid(row=2, column=0, columnspan=2, sticky="ew", padx=5, pady=5)
        amp_frame.columnconfigure(1, weight=1)
        
        tk.Label(amp_frame, text="幅值:", bg="#f8f9fa").grid(row=0, column=0, sticky="w")
        self.amp_var = tk.DoubleVar(value=1.0)
        self.amp_label = tk.Label(amp_frame, text="1.0", bg="#f8f9fa", fg="#333")
        self.amp_label.grid(row=0, column=2, sticky="e", padx=(10,0))
        
        amp_scale = tk.Scale(amp_frame, from_=0.1, to=3.0, resolution=0.1, 
                           orient="horizontal", variable=self.amp_var,
                           command=self.on_amp_change, showvalue=0, bg="#f8f9fa")
        amp_scale.grid(row=1, column=0, columnspan=3, sticky="ew", pady=2)
        
        # 相位调节
        phase_frame = tk.Frame(control_frame, bg="#f8f9fa")
        phase_frame.grid(row=3, column=0, columnspan=2, sticky="ew", padx=5, pady=5)
        phase_frame.columnconfigure(1, weight=1)
        
        tk.Label(phase_frame, text="相位:", bg="#f8f9fa").grid(row=0, column=0, sticky="w")
        self.phase_var = tk.DoubleVar(value=0.0)
        self.phase_label = tk.Label(phase_frame, text="0°", bg="#f8f9fa", fg="#333")
        self.phase_label.grid(row=0, column=2, sticky="e", padx=(10,0))
        
        phase_scale = tk.Scale(phase_frame, from_=0, to=360, resolution=10, 
                             orient="horizontal", variable=self.phase_var,
                             command=self.on_phase_change, showvalue=0, bg="#f8f9fa")
        phase_scale.grid(row=1, column=0, columnspan=3, sticky="ew", pady=2)
        
        # 重置按钮
        reset_btn = tk.Button(control_frame, text="重置参数", command=self.reset_params,
                            bg="#4CAF50", fg="white", font=("Microsoft YaHei", 10, "bold"),
                            cursor="hand2", width=12)
        reset_btn.grid(row=4, column=0, columnspan=2, pady=15)
        
        # === 信息说明区域 - 确保显示竖直滚动条 ===
        info_frame = tk.LabelFrame(self.left_frame, text="信息说明", 
                                 font=("Microsoft YaHei", 11, "bold"), 
                                 fg="#333333", bg="#f8f9fa")
        info_frame.pack(fill="both", expand=True, padx=10, pady=10)
        
        # 创建scrolledtext风格的文本区域
        text_frame = tk.Frame(info_frame, bg="#f8f9fa")
        text_frame.pack(fill="both", expand=True, padx=5, pady=5)
        
        # 配置grid权重
        text_frame.grid_rowconfigure(0, weight=1)
        text_frame.grid_columnconfigure(0, weight=1)
        
        # 文本框
        self.info_text = tk.Text(text_frame, 
                               wrap="word", 
                               font=("Microsoft YaHei", 9), 
                               bg="white",
                               relief="sunken", 
                               borderwidth=2,
                               padx=8,
                               pady=5)
        self.info_text.grid(row=0, column=0, sticky="nsew")
        
        # 竖直滚动条
        v_scrollbar = tk.Scrollbar(text_frame, 
                                  orient="vertical",
                                  command=self.info_text.yview,
                                  cursor="hand2",
                                  width=18, # 加宽滚动条
                                  bg="#d0d0d0",
                                  troughcolor="#f0f0f0",
                                  activebackground="#a0a0a0")
        v_scrollbar.grid(row=0, column=1, sticky="ns")
        
        # 绑定滚动条
        self.info_text.config(yscrollcommand=v_scrollbar.set)
        
        # 添加说明文本
        self.update_info_text()
        self.info_text.config(state="disabled")

##    # 方案一问题:图像显示不完整
##    def create_right_panel(self):
##        """创建右侧matplotlib绘图区域 - 修复边缘显示问题"""
##        # 创建matplotlib图形 
##        self.fig, self.ax = plt.subplots(figsize=(8, 5), facecolor='white', dpi=100)
##        
##        # 关键修复:调整子图边距,确保图表完整显示包括边框
##        self.fig.subplots_adjust(
##            left=0.08,      # 左边距
##            right=0.95,     # 右边距 - 这个值看右边显示
##            top=0.90,       # 顶边距
##            bottom=0.23     # 底边距 - 这个值看下边显示
##        )
##        
##        # 创建Canvas 
##        self.canvas = FigureCanvasTkAgg(self.fig, master=self.right_frame)
##
##        # Canvas布局 - 调整padding确保边框显示
##        canvas_widget = self.canvas.get_tk_widget()
##        canvas_widget.pack(fill="both", expand=True, padx=8, pady=60)  # 增加padding
##        
##        # 初始化绘图
##        self.update_plot()

    # 方案二:图像显示完整
    def create_right_panel(self):
        """方案二:简洁有效的解决方案"""
        self.fig, self.ax = plt.subplots(figsize=(8, 5), facecolor='white', dpi=100)
        
        # 这一行代码?
        #self.fig.tight_layout(pad=3.5)
        
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.right_frame)
        canvas_widget = self.canvas.get_tk_widget()
        canvas_widget.pack(fill="both", expand=True, padx=10, pady=10)
        
        # 关键的事件绑定
        canvas_widget.bind('<Map>', lambda e: self.root.after(50, self.update_plot))

        
    def on_freq_change(self, value):
        """频率变化回调"""
        self.freq_label.config(text=f"{float(value):.1f}")
        self.update_plot()
        
    def on_amp_change(self, value):
        """幅值变化回调"""
        self.amp_label.config(text=f"{float(value):.1f}")
        self.update_plot()
        
    def on_phase_change(self, value):
        """相位变化回调"""
        self.phase_label.config(text=f"{int(float(value))}°")
        self.update_plot()
        
    def update_info_text(self):
        """更新信息说明"""
        self.info_text.config(state="normal")
        self.info_text.delete("1.0", "end")
        
        info = """数学函数可视化工具

使用说明:
1. 选择函数类型(sin, cos, tan, exp)
2. 调节频率改变函数周期性质
3. 调节幅值改变函数振幅大小
4. 调节相位改变函数偏移量

参数说明:
• 频率:控制函数周期性变化的快慢
  - 值越大,函数变化越快
  - 对应函数中x的系数
  
• 幅值:控制函数最大值的大小
  - 决定函数图像的高度
  - 对应函数前面的系数
  
• 相位:控制函数在x轴上的偏移
  - 以度为单位(0°-360°)
  - 正值表示左移,负值表示右移

函数类型介绍:
sin:正弦函数,标准的波形函数
cos:余弦函数,相位偏移的正弦函数
tan:正切函数,具有垂直渐近线
exp:指数函数,呈指数增长或衰减

实时预览:
参数改变时图表会自动更新,方便观察函数变化规律。可以通过调节不同参数来理解它们对函数图像的影响。

操作技巧:
• 可以组合调节多个参数观察效果
• 使用重置按钮快速恢复默认设置
• 观察不同函数类型的特点和差异
• 理解数学函数的几何意义

应用场景:
• 数学教学和学习
• 信号处理基础概念
• 波形分析和理解
• 函数变换的可视化学习
"""
        self.info_text.insert("1.0", info)
        self.info_text.config(state="disabled")
        
    def update_plot(self, *args):
        """更新图表 - 确保完整显示"""
        # 清除之前的图
        self.ax.clear()
        
        # 获取参数
        func_type = self.func_var.get()
        freq = self.freq_var.get()
        amp = self.amp_var.get()
        phase = np.radians(self.phase_var.get())
        
        # 生成数据
        if func_type in ["sin", "cos"]:
            periods = max(3, int(freq * 2))
            x_range = periods * 2 * np.pi / freq
            x = np.linspace(-x_range, x_range, 2000)
        else:
            x = np.linspace(-4*np.pi, 4*np.pi, 2000)
        
        if func_type == "sin":
            y = amp * np.sin(freq * x + phase)
            title = f"y = {amp:.1f} × sin({freq:.1f}x + {self.phase_var.get():.0f}°)"
        elif func_type == "cos":
            y = amp * np.cos(freq * x + phase)
            title = f"y = {amp:.1f} × cos({freq:.1f}x + {self.phase_var.get():.0f}°)"
        elif func_type == "tan":
            y = amp * np.tan(freq * x + phase)
            y = np.clip(y, -10*amp, 10*amp)
            title = f"y = {amp:.1f} × tan({freq:.1f}x + {self.phase_var.get():.0f}°)"
        elif func_type == "exp":
            y = amp * np.exp(freq * x + phase)
            y = np.clip(y, -100*amp, 100*amp)
            title = f"y = {amp:.1f} × exp({freq:.1f}x + {self.phase_var.get():.0f}°)"
        
        # 绘制图形
        self.ax.plot(x, y, linewidth=2.5, color='#2196F3', alpha=0.8)
        self.ax.grid(True, alpha=0.3, linestyle='--')
        self.ax.set_xlabel("x", fontsize=12)
        self.ax.set_ylabel("y", fontsize=12)
        self.ax.set_title(title, fontsize=14, color='#ff6600', pad=20)
        
        # 设置坐标轴范围
        if func_type in ["sin", "cos"]:
            periods = max(3, int(freq * 2))
            x_range = periods * 2 * np.pi / freq
            self.ax.set_xlim(-x_range, x_range)
            self.ax.set_ylim(-amp*1.2, amp*1.2)
        elif func_type == "tan":
            self.ax.set_xlim(-2*np.pi, 2*np.pi)
            self.ax.set_ylim(-3*amp, 3*amp)
        else:
            self.ax.set_xlim(-2, 2)
            y_max = max(10, amp*3)
            self.ax.set_ylim(-y_max, y_max)
        
        # 设置刻度
        self.ax.tick_params(axis='both', which='major', labelsize=10)
        
        # 强制更新布局 - 确保边框完整显示
        self.fig.canvas.draw()
        
    def reset_params(self):
        """重置所有参数"""
        self.freq_var.set(1.0)
        self.amp_var.set(1.0)
        self.phase_var.set(0.0)
        self.func_var.set("sin")
        
        self.freq_label.config(text="1.0")
        self.amp_label.config(text="1.0")
        self.phase_label.config(text="0°")
        
        self.update_plot()
        
    def run(self):
        """运行应用程序"""
        self.root.mainloop()

# 运行应用
if __name__ == "__main__":
    app = DataVisualizationApp()
    app.run()

注意:其中create_right_panel(self) 这个函数,方案二的代码,解决了方案一(代码已被注释掉)图像显示不完整问题!

【方案一图像显示不完整,表现为程序打开时,图像的边侧部分被遮挡显示不出来,但点击全屏后显示是正常的,全屏后还原显示也是正常。】

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐