
把一个数据文件丢进 gnuplot、两行命令画出一条折线这件事我在上一篇里已经讲透了。真正让人卡住的从来不是怎么画出第一条线而是画完之后那堆事四条曲线叠在一张图上挤成一团图例压住了数据点导出的 PDF 丢进排版软件里字号小得看不清中文标签变成一堆方块同一个脚本换台机器跑出来线条粗细全变了。我前段时间帮某实验室的一位同学整理论文配图他有 11 张图横轴刻度有 3 种风格线宽有 5 种原因是每张图都是临时敲命令敲出来的没有一份能复用。这篇gnuplot教程的第二部分就专门对付这些画得出但交不出去的问题多图布局、数据入口的切片、坐标轴与刻度的精细控制、样式系统、终端与导出选型、脚本化批量出图以及一套我自己踩出来的排查清单。适合已经能画出基本图形、准备把图交付出去的人看完全没碰过 gnuplot 的读者建议先补一下基础绘图和plot命令的语法否则后面有些参数会觉得突兀。1. 从能画到能交付这一篇要解决的到底是什么1.1 第一篇留下的三个半成品我观察下来初学者在第一篇之后交出来的图问题高度集中在三个地方。第一是布局多子图的间距靠肉眼调set size和set origin反复试改一次数据要重排半小时第二是刻度默认刻度朝外、上下左右都带镜像刻度线看起来像软件截图而不是论文插图第三是导出屏幕上看着挺清楚存成 PNG 放进文档一放大就糊换成 PDF 又发现里面的线宽和屏幕对不上。这三个问题的共同点是它们都不属于绘图逻辑而属于输出工程靠看函数语法是学不会的。所以这一篇的组织方式不是按命令字母顺序讲而是按一份图从数据到成品的实际流程走。你先要知道数据怎么切进来第 2 节然后决定图怎么排第 3 节接着调刻度和图例第 4 节再统一线型配色第 5 节最后选终端导出第 6 节一直到把这套东西写进脚本第 7 节。第 8 节是我自己的报错记录本很多坑在里面。1.2 为什么我坚持用脚本而不是交互式点gnuplot 有交互式窗口输一行看一行确实方便。但凡是要交付的图我强烈建议你从一开始就写成脚本文件用gnuplot script.gp或load script.gp执行。理由很硬论文配图会改改到第三轮的时候你根本记不住上一版用了什么线宽合作者要复现你的图你发一个.gp文件过去是最省事的而且脚本天然带版本管理的属性改动有迹可循。交互式还有个隐蔽的坏处——状态残留。你在窗口里试过set logscale y忘了unset后面画的图全都莫名其妙变成对数轴而屏幕上你未必第一时间发现。脚本每次从头执行状态是干净的这个问题自动消失。我现在的习惯是探索阶段在交互窗口里乱试一旦图形形状定下来立刻把这些命令抄进脚本之后所有调整都在脚本里做窗口只用来快速看效果。注意脚本文件里不要写pause和pause mouse之类的交互命令否则批量跑的时候会挂在那里等输入尤其是在没有图形界面的环境里。1.3 一份可复用的脚本骨架在展开各个细节之前先把骨架摆出来后面每一节讲的都是往这个骨架里填东西。这个结构我用了好几年改动很小# fig-common.gp —— 公共样式被其他脚本 load set encoding utf8 set border 3 set tics nomirror out scale 0.7 set key top left opaque box set grid xtics ytics lc rgb #dddddd lw 0.5 set style line 1 lc rgb #2b6cb0 lt 1 lw 1.6 pt 7 ps 0.8 set style line 2 lc rgb #c53030 lt 1 lw 1.6 pt 5 ps 0.9 set style line 3 lc rgb #2f855a lt 1 lw 1.6 pt 9 ps 0.8然后每个图一个独立脚本开头load fig-common.gp结尾负责导出。这样做的价值在于哪天导师说线再粗一点你只改一个文件11 张图全部生效。我见过太多人每张图单独调最后自己都说不清哪张是最终版。2. 数据入口把脏活交给 using 和 every2.1 列选择、表达式与格式串using是 gnuplot 里信息密度最高的一个关键字新手往往只用using 1:2其实它后面能挂一串东西。最基本的形态是列号using 1:3表示第一列做 x、第三列做 y。再进一步列号位置可以写表达式用$1、$2引用当前行的列值比如using 1:($2*1000)把第二列换算成毫单位using ($1-$1[0]):2则是把第一列转成相对首行的增量——这个写法在很多时序数据里特别有用省掉了在外部脚本里预处理一遍。格式串是另一个容易被忽略的能力。using 1:2 %lf %lf里的引号部分是 C 语言scanf风格的格式说明当你遇到时间戳或者科学计数法带单位的数据时用它比在外面改文件省事。比如时间数据用set timefmt %Y-%m-%d %H:%M:%S配set xdata time然后用using 1:3直接把第一列当时间解析。这套组合我在处理带日期列的日志数据时用得最多。还有个实用技巧是第三列做点大小或颜色using 1:2:3加上pt 7 ps variable或者using 1:2:3 with points palette。前者让每个点的尺寸跟着第三列走后者直接把第三列映射到颜色条。做散点图时这两招能在一张图里塞进三个维度比画两张图直观。2.2 every 与 index多段数据怎么切数据文件里经常是好几段拼在一起段与段之间用空行隔开。gnuplot 把空行分隔的块叫一个index用index 0、index 1分别取。如果你只想画第二段plot data.dat index 1 using 1:2 with lines。反过来把所有段一次性画出来是plot data.dat using 1:2默认会全部画中间空行当作断点处理需要with lines时加notitle之类避免图例里出现一堆重名条目。every解决的是另一类问题——采样。语法是every N:M:TN 是点间隔每 N 个点取一个M 是数据块间隔T 是起始行偏移。最常见的用法是跳过表头文件第一行是列名every ::1表示从第 1 行开始行号从 0 计也就是跳过第 0 行。我处理带注释头的 CSV 时几乎每次都写every ::1比在外面tail -n 2干净。提示every ::1::100是取第 1 到第 100 行。范围写错一个数字很容易出问题尤其是列数不一致的文件gnuplot 会报Bad data on line排查时先把every去掉看看全量能不能读。数据量大到几十万点时画图前先降采样是有必要的四五十万个点画上去肉眼分辨不出差别但渲染会慢到让人怀疑程序卡死。every 100取百分之一通常就够看趋势了真要精确的包络线用smooth mcsplines或者分箱统计更合理。2.3 数据预处理该放在哪一层这是个经常被问到的问题算平均值、算误差、归一化到底该在 gnuplot 里做还是在 Python/awk 里做完再喂给 gnuplot我的判断标准是看这段处理会不会被复用。如果只是画图前的一次性换算写在using表达式里最省事图和数据一一对应改完立刻能看到效果如果是需要反复引用的统计量比如误差棒上下限、拟合参数就在外部算好存成独立文件再在 gnuplot 里stats或fit读进来。stats命令值得单独说一句。stats data.dat using 2 nooutput执行完之后会生成一系列STATS_min、STATS_max、STATS_mean、STATS_stddev之类的变量你可以直接把STATS_max写进set yrange里做自动留白stats data.dat using 2 nooutput set yrange [STATS_min - 0.1*(STATS_max-STATS_min) : STATS_max 0.15*(STATS_max-STATS_min)]这个写法解决了一个很烦的问题——手动写set yrange [0:100]换一批数据就顶到边框上了。nooutput的作用是抑制打印统计报告脚本里不加这个会刷一屏。3. 多图布局multiplot 的排布逻辑与尺寸计算3.1 multiplot 的两套坐标系set multiplot之后图形的摆放由两套东西决定layout和margins。gnuplot 5 以后推荐用set multiplot layout 2,2这种简写它会自动把画布切成 2×2 的格子。但自动排布的内边距往往不合心意四个子图的刻度标签会互相挤这时候要用margins手动指定外框set multiplot layout 2,2 margins 0.10,0.96,0.10,0.96 spacing 0.06,0.08四个数字分别是左、右、下、上边界取值是屏幕坐标0 到 1。注意一个反直觉的点spacing的两个数字是横向和纵向的间隙单位是字符高度的倍数不是屏幕坐标。我第一次调的时候按屏幕坐标试了半天间距纹丝不动后来翻文档才发现单位不对。还有一套是老的set originset size组合适合不规则排布比如上面一张宽图、下面两张窄图。写法是先set multiplot然后每张图之前设set origin 0,0.55、set size 1,0.45画完再unset multiplot。这套写法灵活但难调我的建议是能用layout就别用它除非遇到1 大 2 小这种非对称排版。3.2 三联图与双栏图的实战尺寸论文里最常见的两种排版单栏竖排三张宽高比接近 1:2.4或者双栏横排两张接近 2:1。尺寸不是拍脑袋定的得从版心宽度倒推。假设单栏版心宽 84mm你要放三张子图横向不分割纵向叠三张每张高度大约 (总高 - 两个间隙) / 3。总高通常控制在版心的 0.8 倍左右也就是 100mm 上下减去 2×3mm 间隙每张约 31mm。这个高度对带刻度标签的图来说偏矮所以更常见的做法是只给最下面那张留横轴标签上面两张的横轴刻度标签去掉。去掉的方法在第 4 节还会提核心就是两行set xtics format 关掉刻度文字set xlabel 关掉轴名。上面两张图只保留 y 轴标签下面一张保留全部视觉上才不显得拥挤。如果是双栏横排两张每张宽度大约 40mm高度可以给到 60mm宽高比接近 2:3适合画折线或者柱状。这个尺寸下 7pt 的字非常勉强建议把字号降到 6pt 或者干脆把两张改成上下排。排版形式单图宽 (mm)单图高 (mm)建议字号备注单栏单图84607-8pt最宽松细节最清楚单栏竖排三联8428-326-7pt上两图去横轴标签双栏横排两图40-42606-7pt图例改放图内双栏通栏单图174707-8pt适合多曲线对比3.3 共享坐标轴的正确处理方式多子图共享同一套横轴刻度最容易犯的错是每张图都写一遍set xrange [0:100]数据一改就要改三处。正确做法是在set multiplot之后、进入子图之前统一设一次范围后面不再动。gnuplot 的set xrange是全局状态不会因为你画了下一张图就重置。图例也是同样的问题。多子图里如果每张图都有同一套图例重复四遍非常难看。常规做法是只在第一张图里set key on后面全部unset key然后在第一张图里用set key的位置和opaque属性让图例压在数据上也不糊。位置用set key at screen 0.02,0.98这种屏幕坐标比top left更可控尤其是各子图数据范围不同的情况。标签共享还有一种更彻底的方式在整张 multiplot 的外面单独画一个标签层。做法是把set border 0、set xtics format 、set ytics format 只有set xlabel和set ylabel有效然后plot NaN撑起一个空绘图区。听着绕但确实能解决三个子图共用一个居中大标签的需求我一般能不用就不用简单起见还是让最下面的图承担标签。4. 坐标轴与刻度让图看起来专业的那些细节4.1 border、tics、zeroaxis 的组合拳默认出来的图四周都有边框上下左右都有刻度线朝外镜像刻度还带文字。这套默认值在屏幕上挺友好放到文档里就显得杂。我常用的清爽版是四行set border 3 set tics nomirror out scale 0.7 set xtics format %.0f set ytics format %.1fset border 3的意思是只保留左边和下边位掩码1 是下、2 是左、4 是上、8 是右3 12。nomirror关掉对侧的镜像刻度线out让刻度线朝外scale 0.7把刻度线缩短到默认的七成。这三项组合起来图的软件味能去掉大半。有些图需要在零点画一条参考线set xzeroaxis和set yzeroaxis就是干这个的但默认样式太粗太黑得配set xzeroaxis lt 2 lc rgb #888888 lw 0.8才好看。如果要画的是任意位置的参考线而不是零轴用set arrowset arrow from 50, graph 0 to 50, graph 1 nohead dt 2 lc rgb #999999 lw 0.8注意graph 0和graph 1表示纵坐标用相对整个绘图区的比例这样竖线的上下端才能贴合边框不会被yrange限制。nohead去掉箭头dt 2是虚线样式这两个参数不写的话会出现一个带箭头的实线完全不是想要的效果。注意set arrow是累加的每调一次就多一根。脚本里反复执行或者reread的时候箭头会越叠越多。养成习惯每次设箭头之前先unset arrow或者给箭头编号set arrow 1 from ...用编号覆盖。4.2 对数轴、科学计数法与刻度密度对数轴的坑主要集中在标签上。set logscale y 10之后默认标签可能是0.001、0.01这种占位特别宽把左边距撑得很难看。改成 10 的幂次形式set format y 10^{%L}%L会替换成指数值输出就是 10^{-3} 这种排版效果。前提是终端支持增强文本enhancedcairo 系列和 postscript 系列都支持老式 png 终端不支持。刻度密度是另一个反复调的东西。set xtics 10表示间隔 10 一个刻度set xtics 0,10,100是指定起点、间隔、终点set mxtics 2在每两个主刻度之间插一个小刻度。我的经验是主刻度数字别超过 6 个超过就该改用科学计数法或者缩小量级在轴标签里写 ×10³ 然后刻度值除以 1000。数字挤在一起的时候宁可少放几个刻度也不要把字体缩小到看不清。科学计数法的轴标签有个取巧写法set ylabel Amplitude (10^3)然后把数据除过 1000 再画。这比让 gnuplot 自动在轴顶端标个x10^3更可控因为自动那个位置经常和图例打架。手动写的代价是数据换算要自己做但这段换算写在using ($2/1000)里也就一行的事。4.3 图例定位、去重与内容定制set key的选项很多常用的就那么几个位置top left、bottom right、outside、opaque加不透明底框、box加边框、samplen样例线长度、spacing行距。图例压住数据是高频问题解决办法有三个层次挪位置、加半透明底、干脆放图外。放图外是最稳的set key outside right会把图例推到绘图区右侧最大宽度由set key width控制。缺点是图会变窄如果图本身不大就不合适。加底框适合数据在图例区域内不密集的情况set key top right opaque box lc rgb #cccccc spacing 1.1 samplen 2lc rgb在这里控制的是边框颜色底框的填充色得配合set key box和终端的透明能力gnuplot 本身不支持给图例底框设半透明填充实际效果是白色实底。这点和某些绘图库不同不用找透明参数。图例文字去重靠notitle。调smooth或者fit的时候plot d.dat using 1:2 with lines title raw, using 1:2 smooth csplines notitle——第二条曲线用两个单引号复用上一个文件名notitle让它不出现在图例里。这个简写在脚本里很常见但注意两个单引号之间不能有空格写错了会被当成空文件名。5. 样式系统线型、点型、颜色怎么定才可复现5.1 linetype 与 linestyle 的分工gnuplot 里ltlinetype、lwlinewidth、ptpointtype、pspointsize、lclinecolor、dtdashtype这几个在plot命令里能直接写也能预先用set style line N ...定义好再用ls N引用。我的建议一律用后者。理由很实际直接在plot里写参数意味着每加一条曲线就要重复一遍颜色和线宽一旦要改风格得全篇搜索替换。用set style line定义成编号绘图命令里只写ls 1、ls 2改样式只改定义那一处。这在多子图场景下几乎是必须的否则四个子图四份样式改一轮要改四次。set style line 1 lc rgb #2b6cb0 lt 1 lw 1.6 pt 7 ps 0.8 dt 1 set style line 2 lc rgb #c53030 lt 1 lw 1.6 pt 5 ps 0.9 dt 2 set style line 3 lc rgb #2f855a lt 1 lw 1.6 pt 9 ps 0.8 dt 3 set style increment user最后那行set style increment user很关键它让plot里不写样式的曲线按你的style line顺序取而不是按默认颜色轮换。没有这行你定义的样式根本不会被自动应用。5.2 配色与线条透明度的现实做法gnuplot 对线条本身没有 alpha 通道想要半透明线这个效果实际得靠混色——把目标色往背景色通常是白色混算出等效的浅色。比如 20% 透明度的蓝色就是把#2b6cb0和#ffffff按 2:8 混合得到#d5e3f0左右。这事手工算一次还行多了就烦我一般写个小函数算def mix(fg, bg(255,255,255), alpha0.2): return #%02x%02x%02x % tuple( int(f*alpha b*(1-alpha)) for f, b in zip(fg, bg))填充区域倒是原生支持透明fs transparent solid 0.25 noborder配合with filledcurves用做置信区间阴影非常合适。这个参数在 pdfcairo 和 pngcairo 上都能正常渲染反倒是某些老终端会忽略导出的图里变成实心色块所以导出后一定要看一眼。配色本身我给自己定了几条死规矩同一张图不超过 5 种颜色不用纯红纯绿纯蓝饱和度太高印刷出来刺眼相邻两条曲线在灰度打印下必须能分辨判断方法很简单——把导出的图转灰度看一眼分不清就重选。常用的低饱和配色是蓝#2b6cb0、红#c53030、绿#2f855a、橙#c05621、紫#6b46c1这几个在灰度下的明度差还算明显。5.3 字体、字号与中文标签中文标签是 gnuplot 新手的第一道坎。现象是命令没报错图上该有字的地方一片空白或者出来一堆方块。原因通常是字体指定了不支持中文的西文字体或者终端没有加载字体路径。正确的做法分三步。先set encoding utf8这一步很多人漏掉然后选 cairo 系终端set terminal pngcairo font Noto Sans CJK SC,10之类的字体名必须和系统里装的完全一致最后检查字体路径show fontpath能看到 gnuplot 去哪些目录找字体。字体名写错不会报错只会静默变成方块所以第一次用某个字体的时候先画一行中文测试一下确认渲染正常再往下做。set encoding utf8 set terminal pdfcairo size 8.4cm,6cm font Noto Serif CJK SC,8 enhanced set output fig.pdf set xlabel 时间 (s) set ylabel 电压 (mV) plot d.dat using 1:2 with lines ls 1 title 实测 unset output字号这块有个容易忽略的点size单位是厘米时终端实际生成的画布尺寸和 PDF 的物理尺寸是两回事。size 8.4cm,6cm表示输出宽度 8.4 厘米插入文档时如果是 1:1 放进去字号 8pt 就真的是 8pt。但如果文档里要缩放到 70% 排版实际看到的字号就是 5.6pt小得看不清。所以定字号前先确认最终的排版尺寸宁可一开始就按缩小后的比例反推。提示font ,8这种省略字体名只写大小的写法是合法的表示用终端的默认字体改字号时最省事。但如果默认字体不含中文就会出方块所以中英文混排的图别用省略写法。6. 终端与导出选哪个终端、尺寸怎么算6.1 常见终端的适用场景对照gnuplot 的终端terminal决定了输出格式选错了后面的努力全是白费。我把常用的几个列成表按用途选就行终端输出适用场景主要限制pdfcairoPDF 矢量论文、报告插图单页不支持多页pngcairoPNG 位图网页、幻灯片需指定 dpi 防糊svgSVG 矢量网页、可编辑插图文字转曲需手动处理epsEPS 矢量部分排版流程中文字体支持弱dumb纯文本无图形环境预览只能看趋势qt/wxt屏幕窗口交互调试不产生文件论文配图我 90% 用pdfcairo因为矢量、体积小、字体嵌入可靠。给网页或者 PPT 用就pngcairo加set term pngcairo size 1600,1200 font ,14尺寸单位是像素直接按需要的分辨率给。svg适合需要后期在矢量软件里微调的场景但要注意转成别的格式时文字可能变成路径改起来就麻烦了。6.2 从物理尺寸反推像素与字号这一步涉及换算很多人在这里翻车。核心公式只有一条像素 厘米 / 2.54 × dpi。比如要做一张 8 厘米宽、300 dpi 的 PNG宽度就是 8 / 2.54 × 300 ≈ 945 像素。高度按宽高比算如果图的比例是 4:3高度就是 709 像素。字号在 PDF 里是绝对的8pt 就是 8pt在 PNG 里则是相对于画布像素的。同样是 8pt 字画布 945 像素宽的时候看着正常画布放大到 2000 像素宽时字就变得很小——因为font ,8在 pngcairo 里是按点算的点又和 dpi 挂钩。稳妥的做法是 PNG 也显式指定 dpiset term pngcairo size 8cm,6cm font ,8gnuplot 会按 72 dpi 换算如果你需要 300 dpi 的实际精度就把 size 按比例放大同时字号同比例放大比如size 2400,1800 font ,32效果等价。这个换算我写在脚本里的处理方式是定义两个变量一处改处处生效W 8.4 H 6.0 DPI 300 set terminal pngcairo size W/2.54*DPI, H/2.54*DPI font ,8*DPI/72虽然看着有点绕但改一次 DPI尺寸和字号同步变比手工调两处靠谱。6.3 导出之后必须做的三项自查图导出来不代表完事我每次都会做三项检查。第一把 PDF 缩放到 100% 看一遍重点看刻度数字有没有被边框切掉、图例有没有压住曲线、轴标签有没有和刻度标签重叠。第二转成灰度看一遍确认多条曲线仍然可分辨。第三在目标文档里实际插入一次看缩放后的字号是否还能看清。第三项最容易被跳过也最容易出问题。屏幕上 100% 看着舒服的字缩到半栏宽之后往往就糊了。我吃过一次亏一张 6 条曲线的图字号 8pt缩到 60% 之后刻度全糊成一团最后只能把曲线减到 4 条重画。还有一个隐蔽的坑是set output的关闭。脚本里set output a.pdf之后如果没有unset output文件可能只写了一部分用阅读器打开是空白或者截断的。用pdfcairo的时候尤其要注意gnuplot 在切换终端或者退出时才真正 flush中途查看文件内容会不完整。养成习惯每段导出代码以unset output收尾。7. 脚本化变量、循环与批量出图7.1 用变量做参数化模板gnuplot 支持用户变量语法就是x 1.5然后在任何接受数值的地方用x。这个能力在批量出图时价值极大。举个我实际用过的场景同一批数据要出 6 张图横轴范围一样但纵轴不一样图标题也不一样。写法是files run1 run2 run3 run4 run5 run6 titles A B C D E F do for [i1:6] { f word(files, i) t word(titles, i) set output sprintf(fig-%s.pdf, t) set title sprintf(Condition %s, t) plot f..dat using 1:2 with lines ls 1 title t } unset outputword(str, i)取第 i 个词sprintf拼字符串do for做循环。这套组合几乎能覆盖所有批量改一点东西的需求。注意f..dat里的点号是字符串拼接不是小数点这个语法在 gnuplot 里有点反直觉初学容易写成f .dat然后报错。变量还有个高级用法是配合reread。脚本里写rereadgnuplot 会重新执行当前脚本形成无限循环——听起来吓人但配合pause可以做简单的动画或者参数扫描。我一般不用因为容易忘记停止条件把终端卡死。7.2 循环里的状态污染问题批量出图最常见的 bug 是状态残留。循环体里设了set logscale y下一轮忘了unset第二张图就变成对数轴。我的处理方式是在循环体开头统一重置一次do for [i1:6] { reset load fig-common.gp # ... 本轮的具体设置 }reset会把所有设置恢复到启动时的默认值等于每轮都从干净状态开始。代价是公共样式要重新load一次不过这一步很快不影响性能。如果循环里要保留某些设置比如统一的set terminal就把这些放在循环外面reset之后再重新设一遍。另一个坑是set output在循环里的行为。每轮都要重新set output到新文件名并且上一轮的输出必须先unset output关掉否则文件句柄累积某些系统上会报too many open files。我习惯在循环体末尾固定写unset output哪怕下一轮马上又设。7.3 脚本的组织方式与调用参数脚本多了之后要考虑怎么组织。我的做法是分三层style.gp放公共样式func.gp放自定义函数拟合模型、单位换算每个图一个fig-xxx.gp。图脚本开头load前两个这样单张图可以独立运行也能被上层批量脚本call。gnuplot 的call支持传参语法是call fig.gp arg1 2脚本里用$0、$1、$2取。$0是脚本名$1起是参数全部按字符串传入需要数值的时候用int()或real()转。这样一套脚本换个参数就能出不同版本的图比复制粘贴强很多gnuplot -e datafilerun1.dat; outfilefig1.pdf fig-template.gp-e参数可以在命令行直接赋值适合被 Makefile 或者 shell 脚本批量调用。这个用法我最初是从别人的构建脚本里学的后来发现比写十个.gp文件清爽得多。8. 常见问题与排查速查表8.1 报错信息的读法gnuplot 的报错信息普遍不太友好但它有个规律报错会给出出错的行号和行内容。看到line 12: invalid command就去看第 12 行多半是拼写错误或者漏了参数。Bad data on line N是数据文件的问题第 N 行格式不对通常是列数不一致或者有非数字内容。undefined variable是变量没定义就用了检查是不是在reset之后忘了重新赋值。报错信息常见原因处理办法Bad data on line N列数不一致、含非数字字符检查第 N 行用every跳表头undefined variable: X变量未定义或被 reset 清掉检查赋值顺序或移到 reset 之后invalid command拼写错误、语法过时看行号定位查对应版本语法Cant open file路径错、文件名含空格用绝对路径文件名加引号all points y value undefined数据列全被过滤掉检查using表达式和过滤条件terminal not found终端名拼错或未编译set term查可用列表Not enough columnsusing引用了不存在的列数一下文件实际列数all points y value undefined这个报错我遇到得最多典型场景是using 1:($20?$2:1/0)这种过滤表达式把所有点都滤掉了。排查时先把表达式简化成using 1:2确认数据能出来再逐步加过滤条件。8.2 图能出来但不对劲的现象排查有些问题不报错但图明显不对。我整理了几种典型现象。线条变成台阶状是采样点太少set samples 100改成 1000曲线末端突然拉一条直线到原点是数据末尾有空行或者缺失值用set datafile missing NaN指定缺失标记图例里出现重复条目是同一份数据画了两次没加notitle图整体被裁掉一块是set size或者margins设得太满bmargin不够放轴标签。还有一种很隐蔽的情况图看起来正常但数值不对。原因可能是using里列号写错了也可能是数据文件的分隔符不对。CSV 文件忘了set datafile separator ,的话gnuplot 会把整行当成一列using 2直接越界但如果只有一列它会静默地把整行当一个数解析画出来的图看着像那么回事实际全是错的。这个坑我踩过对着一条合理的曲线查了半天最后发现是分隔符的问题。8.3 跨版本、跨平台的差异备忘gnuplot 的版本差异主要体现在语法上。4.x 到 5.x 之间变化不小set style data linespoints的行为、do for的引入、dtdashtype取代老式lt虚线都是 5.x 之后的事。如果你在别人的脚本里看到set termoption dashed那多半是 4.x 时代的写法。我现在的建议是统一用 5.2 以上的版本语法稳定社区示例也多。跨平台的差异主要在字体和路径。字体名在 Linux 上可能是Noto Sans CJK SC在另一个系统上可能是别的名字写死字体名会导致换机器就出方块。稳妥的做法是把字体名做成变量或者用if判断if (GPVAL_SYSTEM eq Linux) { CJK Noto Sans CJK SC } \ else { CJK Microsoft YaHei }GPVAL_SYSTEM是 gnuplot 预定义的系统标识变量用它做分支比自己猜可靠。路径分隔符同理反斜杠在字符串里有转义含义跨平台脚本统一用正斜杠gnuplot 在大多数系统上都能识别。最后一条经验是关于版本升级的升级之前先把现有脚本跑一遍把输出图存下来做对比。gnuplot 的默认样式在小版本间也可能变比如默认颜色序列、默认点型大小。我升级过一次三张图的配色全变了因为默认的 color sequence 调整过当时以为是脚本坏了查了半天才发现是版本默认值的问题。这套流程走下来一份图从数据到成品大概要花两三个小时但第二份开始就快了——因为公共样式和模板都在改的只是数据文件路径和轴范围。我现在做一批 10 张的图从接到数据到全部导出基本控制在半天以内剩下的时间都花在调整数据表达上而不是跟工具较劲。刚开始写脚本的时候别追求一次写完美先让它跑通再逐步把重复的部分抽成公共文件这个过程本身就是在积累你自己的模板库。