简介:面向美赛MCM/ICM参赛者与数学建模爱好者,这份绘图方法专题整理聚焦论文图表质量提升,解决建模论文中图件不够专业、排版不统一等常见问题。资源系统梳理图表在竞赛论文中的作用,及清晰度、准确性、简洁性、美观性基本要求,并横向对比PPT、Excel、Origin、Python、MATLAB、SPSS、COMSOL等常见绘图工具的适用场景。内容还覆盖ECharts、时间线、金字塔图、三维聚类图等特殊图表类型,以及MATLAB热力图绘制、多子图布局、地图配色和Python pyecharts地图实现等实操技巧,同时补充数据清洗、图表设计原则和矢量图编辑等进阶要点。整份资源为1个PDF文件,约4.83MB,内容精炼、便于查阅。目前已有243人学习下载,适合希望在短时间内系统掌握美赛图表规范并提升绘图水平的参赛者。
1. 美赛绘图方法决定论文下限:图表才是评委最先看到的东西
美赛(MCM/ICM)评审流程里,最关键的判断往往发生在前五分钟。评委拿到一份 PDF 后不会立刻从摘要开始细读,而是先快速扫一遍图表:模型的逻辑是否清晰、求解结果是否可信、队伍有没有工程素养,全部体现在图上。很多队伍把精力押在建模思路和求解算法上,最后用 Matplotlib 默认样式对付出图,结果中文乱码、坐标轴信息缺失、配色的刺眼程度让人根本不想细看内容,模型再扎实也被压了评分档次。这里梳理一套在有限比赛时间内可落地的绘图方法:从环境配置、高频图型实现、排版控制到提交前的验证检查,目标只有一个——让每一张图都在"论证"而非"装饰"。适合马上要参赛的队伍,也适合需要快速产出高质量学术图表的工程师。
2. 绘图工具选型与初始化配置:先把出图地基打牢
2.1 为什么选 Python 生态作为美赛绘图主力
美赛参赛队的工具选择基本集中在 Python 和 MATLAB 两派。MATLAB 的绘图交互体验好,但比赛期间要现场装字体、调分辨率,且导出矢量图时对中文字体的支持同样需要额外处理。Python 这边以 Matplotlib 为核心,配合 NumPy、Pandas、SciPy 完成数据读取与预处理,再按需补 Seaborn 做统计图、Plotly 做交互原型,整套链路完全能覆盖美赛从数据清洗到最终 PDF 导出的全部需求。
选 Python 的更实际理由是版本可控和可复现。比赛期间所有队员共用一个环境,写好一个plot_styles.py配置模块后,任何人出的图风格一致,不会出现第一题用蓝色系、第二题突然变成橙红系的情况。另一个理由是社区生态:任何图型需求,从三维地形到网络关系图,都能在五分钟内找到可改的现成实现。
2.2 中文字体和负号乱码的根治方法
美赛论文是英文写作,但绘图时经常需要标注中文备注、中文单位或中文图例。Matplotlib 默认字体不含中文字形,直接绘制会出现方框乱码。先确认当前系统可用字体:
python -c "import matplotlib.font_manager as fm; print([f.name for f in fm.fontManager.ttflist])"在输出清单里找中文字体:Windows 上通常有SimHei、Microsoft YaHei,macOS 上是PingFang SC、Hiragino Sans GB,Linux 服务器上一般是Noto Sans CJK SC。找到后统一写入 Matplotlib 的全局配置:
import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "Noto Sans CJK SC"] plt.rcParams["axes.unicode_minus"] = False # 修复负号显示为方块的问题第一行设置中文字体的回退列表,列表顺序表示优先级,前一个字体找不到字形时自动尝试后一个。第二行必须设置,axes.unicode_minus默认是True,渲染坐标轴负号时使用 Unicode 的减号字符,该字符在很多中文字体里没有对应字形,表现为一个空方块或乱码。两项配合才能让中英文混排的图表正常显示。
2.3 用 rcParams 统一全局风格参数
中文字体只是起点。比赛出图要风格统一,最佳做法是建立一个全局配置函数,在所有绘图脚本开头调用:
import matplotlib as mpl def set_contest_style(): mpl.rcParams.update({ "figure.dpi": 150, # 屏幕预览分辨率 "savefig.dpi": 300, # 导出分辨率,满足印刷要求 "savefig.bbox": "tight", # 保存时裁掉多余留白 "font.size": 11, # 全局字号 "axes.titlesize": 14, # 子图标题字号 "axes.labelsize": 12, # 坐标轴标签字号 "xtick.labelsize": 10, # x 轴刻度字号 "ytick.labelsize": 10, # y 轴刻度字号 "legend.fontsize": 10, # 图例字号 "axes.grid": True, # 默认打开网格线 "grid.alpha": 0.4, # 网格线透明度 "grid.linestyle": "--", # 虚线网格,避免压过数据线 "axes.spines.top": False, # 隐藏顶部边框 "axes.spines.right": False, # 隐藏右侧边框,更接近学术风格 "figure.figsize": (8, 5), # 默认画布尺寸,适合单栏图 })上述参数里最容易忽略的是savefig.bbox。不设置它时,保存的图片会带着坐标轴标签外围的多余空白,插入论文后视觉上左右不齐。设为"tight"会自动裁边。figure.figsize建议按实际排版位置调整:单栏图用(8, 5),双栏并排图用(12, 5),全宽图用(16, 6)。
3. 美赛高频图表类型的绘制实操:从数据到能直接用的图
3.1 折线图与置信区间带:模型预测结果的标配呈现
美赛中最常见的数据呈现是时间序列或多方案对比。单纯画三条折线不是本事,关键在于把预测区间、真实观测点和关键事件标注放进同一张图。以传染病模型预测为例,用fill_between绘制置信区间带:
import numpy as np import matplotlib.pyplot as plt # 模拟 SIR 模型的预测结果 t = np.arange(0, 30, 1) pred = 1000 * np.exp(-((t - 15) / 4) ** 2) lower, upper = pred * 0.92, pred * 1.08 # 模拟 95% 置信区间 fig, ax = plt.subplots(figsize=(8, 5)) ax.plot(t, pred, color="#1f77b4", linewidth=2, label="Predicted") ax.fill_between(t, lower, upper, color="#1f77b4", alpha=0.2, label="95% CI") ax.scatter([5, 12, 20], [pred[5], pred[12], pred[20]], color="#d62728", zorder=5, label="Observed") ax.axvline(x=10, color="#2ca02c", linestyle=":", label="Intervention") ax.set_xlabel("Day") ax.set_ylabel("Infected Population") ax.set_title("Prediction with Confidence Interval") ax.legend(loc="upper right", frameon=False) plt.tight_layout() plt.savefig("prediction_curve.png", dpi=300)fill_between接收lower和upper两个序列,alpha=0.2让区间带透明化,数据线保持视觉焦点。zorder=5强制散点绘制在折线上方,避免被线遮挡。axvline标注干预时点是美赛评委很受用的细节,它让模型结论和政策建议的关联一目了然。
3.2 热力图:相关性矩阵与时空数据可视化
相关性热力图几乎是每一道数据分析题的必备图。Seaborn的heatmap在底层调用 Matplotlib,却省掉了手动设置颜色映射和色条的麻烦:
import seaborn as sns import pandas as pd # 构造 5 个特征的相关性矩阵 df = pd.DataFrame(np.random.randn(100, 5), columns=["GDP", "Pop", "Edu", "Med", "Env"]) corr = df.corr() fig, ax = plt.subplots(figsize=(7, 6)) sns.heatmap(corr, annot=True, fmt=".2f", cmap="RdBu_r", center=0, square=True, linewidths=0.5, cbar_kws={"shrink": 0.8}, ax=ax) ax.set_title("Correlation Matrix of Evaluation Indicators") plt.tight_layout() plt.savefig("corr_heatmap.png", dpi=300)annot=True在格子里显示数值,fmt=".2f"控制显示格式。cmap="RdBu_r"使用红蓝反向色带,center=0让色带中心对齐零值,正负相关性用冷色和暖色区分,这是学术图表的标准做法。square=True强制格子为正方形,视觉上更整齐。
时空数据的呈现则用imshow或pcolormesh。比如无人机巡护路径的应急管理题,需要画出某一区域不同时间段的风险热力变化,imshow可以直接把二维数组渲染成图,配合colorbar说明数值含义:
# grid 是网格化的风险值,shape 为 (行, 列) fig, ax = plt.subplots(figsize=(8, 6)) im = ax.imshow(grid, cmap="YlOrRd", origin="lower", aspect="auto") cbar = plt.colorbar(im, ax=ax, shrink=0.8) cbar.set_label("Risk Score") ax.set_xticks(range(len(lon))) ax.set_yticks(range(len(lat))) ax.set_xticklabels([f"{x:.2f}" for x in lon], rotation=45) ax.set_yticklabels([f"{y:.2f}" for y in lat]) ax.set_xlabel("Longitude") ax.set_ylabel("Latitude")origin="lower"控制数组第一维对应的是 y 轴底部还是顶部。经纬度数据习惯上纬度从小到大从下往上排,所以设成lower。aspect="auto"让每个格子自动拉伸填满画布,避免非正方形区域导致图形变形。
3.3 三维曲面图:模型结果空间分布的直接呈现
美赛常涉及地形、温度场、资源分布等空间问题,三维曲面图是直观展示模型输出空间特征的方式。用plot_surface绘制:
from mpl_toolkits.mplot3d import Axes3D # 构造网格数据 x = np.linspace(-3, 3, 60) y = np.linspace(-3, 3, 60) X, Y = np.meshgrid(x, y) Z = np.exp(-(X**2 + Y**2)) * np.cos(0.5 * np.sqrt(X**2 + Y**2)) fig = plt.figure(figsize=(10, 7)) ax = fig.add_subplot(111, projection="3d") surf = ax.plot_surface(X, Y, Z, cmap="viridis", edgecolor="none", alpha=0.95) fig.colorbar(surf, ax=ax, shrink=0.6, pad=0.1) ax.view_init(elev=30, azim=135) ax.set_xlabel("X") ax.set_ylabel("Y") ax.set_zlabel("Z") plt.savefig("surface_3d.png", dpi=300)edgecolor="none"去掉网格边缘线,避免曲面被密集的黑线切割。view_init(elev, azim)控制视角,elev=30表示俯仰角 30 度,azim=135表示方位角 135 度,让曲面最有信息量的区域面向观察者。三维图的颜色映射首选viridis或plasma,这两种色带在灰度打印时仍然能区分梯度。
4. 论文级排版精度控制:从单张图到整篇视觉统一
4.1 子图布局与画布尺寸的配合
美赛一张图内经常要放多个相关子图,比如不同算法在不同数据集上的对比。推荐用subplots显式指定行数和列数,并共享坐标轴:
fig, axes = plt.subplots(2, 2, figsize=(12, 8), sharex=True, sharey=True) data_sets = [data1, data2, data3, data4] for ax, d in zip(axes.flat, data_sets): ax.plot(t, d["ours"], label="Ours", linewidth=2) ax.plot(t, d["baseline"], label="Baseline", linestyle="--") ax.set_title(d["name"]) ax.legend(frameon=False) fig.supxlabel("Time (hour)") fig.supylabel("Value") plt.tight_layout()sharex=True和sharey=True让所有子图共用同一套刻度,这样四个子图的量纲一致,视觉对比有效。axes.flat按行优先顺序展开二维的坐标轴数组。fig.supxlabel和fig.supylabel为整张图添加统一的坐标轴标签,而不是每个子图单独加。
4.2 双坐标轴与共享轴的边界条件
需要在同一张图上对比趋势但量纲不同的两组数据时,双 y 轴是绕不开的方案。常见错误是直接把两条线画上去然后加图例,结果两组数据曲线重叠在一起无法辨读。正确的做法是让两条线使用不同颜色,并让左右坐标轴颜色呼应:
fig, ax1 = plt.subplots(figsize=(8, 5)) ax2 = ax1.twinx() l1, = ax1.plot(t, price, color="#1f77b4", label="Price") l2, = ax2.plot(t, volume, color="#ff7f0e", label="Volume") ax1.set_xlabel("Time") ax1.set_ylabel("Price", color="#1f77b4") ax2.set_ylabel("Volume", color="#ff7f0e") ax1.tick_params(axis="y", colors="#1f77b4") ax2.tick_params(axis="y", colors="#ff7f0e") lines = [l1, l2] ax1.legend(lines, [l.line.get_label() for l in lines], loc="upper left") plt.tight_layout() plt.savefig("dual_axis.png", dpi=300)twinx()生成共享 x 轴的第二个坐标轴。颜色编码双轴是一个容易被忽视的排版细节:左轴及其刻度、标签用蓝色系,右轴用橙色系,读者不需要看图例就能把曲线和坐标轴对应起来。图例要用两个线对象合并生成,否则legend默认只显示ax1上的曲线。
4.3 配色体系和多图风格传递
整篇论文配色的统一性,对评委的专业感判断影响很大。推荐从seaborn的预设色板中选一条主线,避免在每张图里随手用不同颜色:
import seaborn as sns colors = sns.color_palette("deep", n_colors=6)"deep"色板的饱和度和明度经过调校,在白色背景上对比度足够,且在灰度打印时也有区分度。备选方案:"muted"色调更柔和,适合大面积的区域填充;"colorblind"色板基于色盲友好设计,如果论文要打印出来评阅,建议直接用它。选好一个色板后,把 RGB 值抽出来放进全局配置:
# 从深色板提取前 6 个颜色并转为十六进制 hex_colors = [mpl.colors.rgb2hex(c) for c in colors] # 结果类似: ['#4c72b0', '#dd8452', '#55a868', '#c44e52', '#8172b3', '#937860']每张图按顺序使用hex_colors[0]、hex_colors[1]等,保证同类信息(比如"本模型")在所有图中都用同一个颜色。
5. 出图验证清单:把隐藏问题在提交前全部找出来
5.1 缩放测试:把图缩小一倍再看
图在屏幕上看着清晰,但排版进 Word 或 LaTeX 后宽度通常只有原图的 60% 到 70%。把生成好的 PNG 用图片浏览器缩放到 50% 比例,重新审视一遍:线条是否还分得清?图例文字是否还能辨认?如果将 300 DPI 的 PNG 插到 Word 里再导出 PDF,图里的细线在屏幕上会有莫尔纹,打印后则可能断线。所以缩放测试是检验线宽和字号是否达标的唯一标准。
5.2 灰度打印模拟
评委里一定有人打印论文。彩色图在普通黑白打印机上输出时,红色和绿色会变成相近的灰色,导致两条曲线无法区分。验证方法:用 Matplotlib 直接把配色转为灰度:
from matplotlib import colors as mcolors def simulate_grayscale(path_in, path_out): fig = plt.figure() img = plt.imread(path_in) gray = np.dot(img[..., :3], [0.299, 0.587, 0.114]) plt.imsave(path_out, gray, cmap="gray") plt.close(fig) simulate_grayscale("prediction_curve.png", "prediction_gray.png")转灰度后如果两条曲线在图中没法分辨,就把其中一条改为虚线或点划线,用线型来区分而不是只用颜色。这是一个低成本但效果显著的防线。
5.3 嵌入 PDF 时的矢量图检查
美赛要求提交 PDF,图的格式直接决定了印刷清晰度。PNG 是位图,无论保存时用多高的 DPI,PDF 放大后依然会糊。矢量图格式(PDF 或 SVG)不存在这个问题。Matplotlib 支持直接导出 PDF 矢量图:
fig.savefig("figure_1.pdf", format="pdf")用 Inkscape 打开导出的 PDF,放大到 800% 检查线条边缘是否平滑。推荐在正式排版时用 PDF 格式的矢量图替换 PNG,若是论文提交系统强制要求位图,再降级为 600 DPI 的 PNG。一个常见坑是:savefig导出 PDF 后,某些自定义字体没有被嵌入 PDF 文件,其他电脑打开时字体被替换成默认字体,版面错乱。验证方法是在未安装中文字体的虚拟机里打开该 PDF 预览,确认无字形替换警告。
本文还有配套的精品资源,点击获取