"""

数学算式三维建模工具

用户输入数学表达式(如 "sin(x)*cos(y)"),自动生成3D曲面图

支持交互式输入、预设示例、自定义范围和网格密度

"""

 

import numpy as np

import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

import sympy as sp

from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application

 

# ==================== 配置区域 ====================

DEFAULT_X_RANGE = (-5, 5) # 默认x轴范围

DEFAULT_Y_RANGE = (-5, 5) # 默认y轴范围

DEFAULT_GRID_SIZE = 60 # 默认网格密度(数值越大越精细)

DEFAULT_CMAP = 'viridis' # 默认颜色映射

 

# 预设示例:用户可以快速选择

PRESET_EXAMPLES = {

    '1': ('双曲抛物面', 'sin(x)*cos(y)'),

    '2': ('椭圆抛物面', 'x**2 + y**2'),

    '3': ('马鞍面', 'x**2 - y**2'),

    '4': ('正弦波纹', 'sin(x**2 + y**2)'),

    '5': ('指数衰减', 'exp(-(x**2 + y**2)/5)'),

    '6': ('环形波', 'cos(sqrt(x**2 + y**2))'),

    '7': ('三维高斯', 'exp(-(x**2 + y**2)/4)'),

    '8': ('多峰曲面', 'sin(x)*sin(y) + 0.5*cos(x*y)'),

}

 

 

def parse_expression(expr_str: str):

    """

    安全解析用户输入的数学表达式

    使用sympy解析,支持常见数学函数和运算

 

    参数:

        expr_str: 字符串表达式,如 "sin(x)*cos(y)"

 

    返回:

        (sympy表达式, 变量列表)

    """

    # 定义允许的变量:x, y

    variables = {'x': sp.Symbol('x'), 'y': sp.Symbol('y')}

 

    # 定义允许的数学函数映射

    allowed_functions = {

        'sin': sp.sin, 'cos': sp.cos, 'tan': sp.tan,

        'asin': sp.asin, 'acos': sp.acos, 'atan': sp.atan,

        'sinh': sp.sinh, 'cosh': sp.cosh, 'tanh': sp.tanh,

        'exp': sp.exp, 'log': sp.log, 'log10': sp.log10,

        'sqrt': sp.sqrt, 'abs': sp.abs,

        'pi': sp.pi, 'e': sp.E,

    }

 

    # 添加转换:支持隐式乘法(如 "2x" 自动转为 "2*x")

    transformations = standard_transformations + (implicit_multiplication_application,)

 

    try:

        # 解析表达式

        expr = parse_expr(

            expr_str,

            local_dict=allowed_functions,

            global_dict={},

            transformations=transformations

        )

 

        # 检查表达式中包含的变量

        used_symbols = expr.free_symbols

        if not used_symbols.issubset(set(variables.values())):

            unknown = used_symbols - set(variables.values())

            raise ValueError(f"表达式中包含未知变量: {unknown},请只使用 x 和 y")

 

        return expr, variables

 

    except Exception as e:

        raise ValueError(f"表达式解析失败: {str(e)}")

 

 

def plot_3d_expression(expr_str: str,

                       x_range=DEFAULT_X_RANGE,

                       y_range=DEFAULT_Y_RANGE,

                       grid_size=DEFAULT_GRID_SIZE,

                       cmap=DEFAULT_CMAP,

                       save_path=None):

    """

    根据数学表达式绘制3D曲面图

 

    参数:

        expr_str: 数学表达式字符串,如 "sin(x)*cos(y)"

        x_range: x轴范围 (min, max)

        y_range: y轴范围 (min, max)

        grid_size: 网格密度

        cmap: 颜色映射

        save_path: 保存图片路径(可选)

    """

    # 1. 解析表达式

    expr, variables = parse_expression(expr_str)

    x_sym = variables['x']

    y_sym = variables['y']

 

    # 2. 将sympy表达式转换为可调用的numpy函数

    try:

        f = sp.lambdify((x_sym, y_sym), expr, modules=['numpy'])

    except Exception as e:

        raise ValueError(f"表达式转换失败: {str(e)}")

 

    # 3. 生成网格数据

    x_vals = np.linspace(x_range[0], x_range[1], grid_size)

    y_vals = np.linspace(y_range[0], y_range[1], grid_size)

    X, Y = np.meshgrid(x_vals, y_vals)

 

    # 4. 计算Z值

    try:

        Z = f(X, Y)

        # 处理无穷大或NaN值

        Z = np.nan_to_num(Z, nan=0.0, posinf=0.0, neginf=0.0)

    except Exception as e:

        raise ValueError(f"计算Z值时出错: {str(e)}")

 

    # 5. 创建3D图形

    fig = plt.figure(figsize=(12, 9))

    ax = fig.add_subplot(111, projection='3d')

 

    # 绘制曲面

    surf = ax.plot_surface(X, Y, Z,

                           cmap=cmap,

                           linewidth=0,

                           antialiased=True,

                           alpha=0.9)

 

    # 添加颜色条

    fig.colorbar(surf, ax=ax, shrink=0.5, aspect=10, label='Z值')

 

    # 设置坐标轴标签

    ax.set_xlabel('X', fontsize=12)

    ax.set_ylabel('Y', fontsize=12)

    ax.set_zlabel('Z', fontsize=12)

 

    # 设置标题

    title = f'z = {expr_str}'

    ax.set_title(title, fontsize=14, pad=20)

 

    # 自动调整视角 - 使用一个较好的默认视角

    ax.view_init(elev=25, azim=-60)

 

    # 设置z轴范围,使图形更美观

    z_max = np.max(np.abs(Z))

    if z_max > 0:

        ax.set_zlim(-z_max * 1.1, z_max * 1.1)

 

    # 添加网格

    ax.grid(True, linestyle='--', alpha=0.3)

 

    # 调整布局

    plt.tight_layout()

 

    # 保存图片

    if save_path:

        plt.savefig(save_path, dpi=150, bbox_inches='tight')

        print(f"图片已保存至: {save_path}")

 

    # 显示图形

    plt.show()

 

    return fig, ax

 

 

def print_presets():

    """打印预设示例"""

    print("\n" + "=" * 50)

    print("预设示例(可直接输入编号选择):")

    print("=" * 50)

    for key, (name, expr) in PRESET_EXAMPLES.items():

        print(f" {key}. {name:12} -> z = {expr}")

    print("=" * 50)

 

 

def interactive_mode():

    """交互式模式:用户输入表达式并生成3D图"""

    print("\n" + "=" * 55)

    print("🧊 数学算式三维建模工具 v1.0")

    print("=" * 55)

    print(" 使用说明:")

    print(" - 输入数学表达式,如: sin(x)*cos(y)")

    print(" - 支持函数: sin, cos, tan, exp, log, sqrt, abs 等")

    print(" - 支持运算符: +, -, *, /, ** (幂运算)")

    print(" - 输入 'list' 查看预设示例")

    print(" - 输入 'quit' 或 'exit' 退出程序")

    print("=" * 55)

 

    # 默认参数

    x_range = DEFAULT_X_RANGE

    y_range = DEFAULT_Y_RANGE

    grid_size = DEFAULT_GRID_SIZE

    cmap = DEFAULT_CMAP

 

    while True:

        try:

            # 获取用户输入

            user_input = input("\n 请输入表达式 (或命令): ").strip()

 

            if not user_input:

                continue

 

            # 处理命令

            if user_input.lower() in ('quit', 'exit', 'q'):

                print("再见!")

                break

 

            if user_input.lower() == 'list':

                print_presets()

                continue

 

            # 检查是否为预设示例编号

            if user_input in PRESET_EXAMPLES:

                name, expr = PRESET_EXAMPLES[user_input]

                print(f"选择预设: {name} -> z = {expr}")

                expr_str = expr

            else:

                expr_str = user_input

 

            # 额外参数设置(可选)

            print("\n 当前参数: x∈[{}, {}], y∈[{}, {}], 网格={}".format(

                x_range[0], x_range[1], y_range[0], y_range[1], grid_size))

 

            # 询问是否修改参数

            change_params = input(" 修改参数? (y/n, 默认n): ").strip().lower()

            if change_params == 'y':

                try:

                    x_min = float(input(f" x最小值 (当前{x_range[0]}): ") or x_range[0])

                    x_max = float(input(f" x最大值 (当前{x_range[1]}): ") or x_range[1])

                    y_min = float(input(f" y最小值 (当前{y_range[0]}): ") or y_range[0])

                    y_max = float(input(f" y最大值 (当前{y_range[1]}): ") or y_range[1])

                    grid = int(input(f" 网格密度 (当前{grid_size}): ") or grid_size)

                    x_range = (x_min, x_max)

                    y_range = (y_min, y_max)

                    grid_size = max(10, min(200, grid)) # 限制范围

                except ValueError:

                    print("参数格式错误,使用默认值")

 

            # 绘制3D图

            print(f" 正在生成 3D 曲面: z = {expr_str} ...")

            plot_3d_expression(expr_str, x_range, y_range, grid_size, cmap)

            print("✅ 绘图完成!")

 

        except KeyboardInterrupt:

            print("\n 再见!")

            break

        except Exception as e:

            print(f" 错误: {str(e)}")

            print("请检查表达式语法,或输入 'list' 查看示例")

 

 

def main():

    """主函数"""

    # 如果有命令行参数,直接绘制

    import sys

    if len(sys.argv) > 1:

        expr_str = sys.argv[1]

        print(f"绘制表达式: z = {expr_str}")

        try:

            plot_3d_expression(expr_str)

        except Exception as e:

            print(f"错误: {str(e)}")

            print("使用方法: python script.py 'sin(x)*cos(y)'")

    else:

        # 交互式模式

        interactive_mode()

 

 

if __name__ == "__main__":

    main()

```

 

                           使用与交互

 

运行脚本后,您可以直接输入数学表达式(如 sin(x)*cos(y))即可生成3D曲面图。程序会实时解析并渲染,支持调整视角和缩放。

 

· 输入方式:支持直接输入表达式(如 x**2 + y**2),或输入数字编号(如 1)快速选择预设示例。输入 list 可查看所有预设,输入 quit 退出程序。

· 参数微调:每次绘图前可修改X/Y轴范围(默认-5~5)和网格密度(默认60),网格越大曲面越精细但渲染稍慢。

· 交互操作:生成的3D图支持鼠标拖拽旋转、滚轮缩放,右键平移,方便从任意角度观察曲面形态。

· 视觉优化:自动调整Z轴范围、添加颜色条和网格线,曲面颜色映射(默认为viridis)可清晰反映高度变化。

 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐