Gnuplot 5.2网格配置、标签格式化、特殊连线绘制问题咨询
Gnuplot 5.2 绘图问题对应解决方案
1. 双轴等刻度、等范围自动缩放实现
要同时满足x/y轴数值范围一致、刻度步长一致、物理像素长度等比,不需要手动固定maxv和步长,按以下配置即可:
- 终端画布先设为1:1正方形,之前写的
set terminal windows size 800,800配置正确,把set size ratio -1替换成set size square,就能保证x/y轴的物理显示长度完全相等。 - 自动计算对称轴范围:先调用
stats命令统计数据集x、y方向的极值,取两个方向最大绝对值的较大值作为轴范围上限,步长交给gnuplot自动生成,因为x/y范围完全一致,自动生成的刻度步长也会完全匹配。
相关代码片段:
filename='file1.txt' # 统计x、y方向的极值 stats filename using ($2-$3):($4-$5) nooutput # 计算x、y方向的最大绝对值,留5%边距,对齐0.25的步长方便刻度显示 max_x = (abs(STATS_max_x) > abs(STATS_min_x)) ? abs(STATS_max_x) : abs(STATS_min_x) max_y = (abs(STATS_max_y) > abs(STATS_min_y)) ? abs(STATS_max_y) : abs(STATS_min_y) maxv = ceil( (max_x > max_y ? max_x : max_y)*1.05 / 0.25 ) * 0.25 set xrange [-maxv:maxv] set yrange [-maxv:maxv] set xtics auto set ytics auto set size square
更换不同数据集也不需要手动改范围和步长,可自动适配。
2. 标签数值精简格式化
之前用floor()、int()没效果是因为这类函数只能做整数截断,没法自动保留0.5这类必要小数,直接用gnuplot内置的格式化语法即可,不需要自己写判断逻辑:
用gprintf("%g", 数值)做格式化,%g格式会自动去掉无意义的尾随零,整数就显示为整数,带半值的小数就保留一位小数,正好匹配1、1.5、2、2.5的显示需求。
对应标签部分修改为:
filename using ($2-$3):($4-$5):(gprintf("%g", $1)) \ with labels tc lt 1 point pt 7 offset char 1,1 notitle, \
3. 绘制到原点最远点的包络连线
可以实现,不用逐点手动判断x²+y²最大值,用角度分箱的方式就能生成参考图里的包络线,适配5.2版本的实现代码如下:
# 初始化360个角度分箱,存储每个角度方向上的最大距离 array r_max[360] do for [i=1:360] { r_max[i] = 0 } # 遍历所有数据点,更新对应角度箱的最大距离 stats filename using ($2-$3):($4-$5) nooutput do for [i=0:STATS_records-1] { x = real(word(STATS_value_x, i+1)) y = real(word(STATS_value_y, i+1)) r = sqrt(x**2 + y**2) # 计算点对应的角度,转成0-360度范围做分箱索引 theta = (atan2(y,x) + 2*pi) * 180/pi bin = int(theta) + 1 if (r > r_max[bin]) { r_max[bin] = r } } # 把分箱得到的极坐标点转成直角坐标,存入临时数据块 set table $envelope do for [i=1:360] { if (r_max[i] > 0) { th = (i-1)*pi/180 print sprintf("%.4f %.4f", r_max[i]*cos(th), r_max[i]*sin(th)) } } unset table
最后plot的时候加一行$envelope using 1:2 w l lc red lw 1.5 notitle, \就能画出最远点的连线。
4. 高亮过原点的网格线
Gnuplot 5.2版本没有提供单独自定义0刻度网格线样式的原生参数,目前用额外画直线的方式就是最简便、最稳定的实现,优化下写法同时覆盖x、y轴的0线即可,不需要找其他偏门参数:
# 加粗显示x=0、y=0的轴线,比普通网格线深一个色号、粗一点 set arrow from graph 0, first 0 to graph 1, first 0 lc 'gray40' lw 1.5 nohead set arrow from first 0, graph 0 to first 0, graph 1 lc 'gray40' lw 1.5 nohead
这里用first坐标绑定0值,不管轴范围怎么自动缩放,两条线都会精准卡在0刻度位置,不需要手动调整坐标。
修正后完整绘图代码
set terminal windows 0 position 20,20 set terminal windows size 800,800 set grid xtics ytics set style circle radius graph 0.25/2 set ylabel 'Y' font ", 11" set xlabel 'X' font ", 11" filename='file1.txt' # 自动计算等比例轴范围 stats filename using ($2-$3):($4-$5) nooutput max_x = (abs(STATS_max_x) > abs(STATS_min_x)) ? abs(STATS_max_x) : abs(STATS_min_x) max_y = (abs(STATS_max_y) > abs(STATS_min_y)) ? abs(STATS_max_y) : abs(STATS_min_y) maxv = ceil( (max_x > max_y ? max_x : max_y)*1.05 / 0.25 ) * 0.25 set xrange [-maxv:maxv] set yrange [-maxv:maxv] set xtics auto set ytics auto set size square # 高亮0点轴线 set arrow from graph 0, first 0 to graph 1, first 0 lc 'gray40' lw 1.5 nohead set arrow from first 0, graph 0 to first 0, graph 1 lc 'gray40' lw 1.5 nohead # 生成最远点包络线 array r_max[360] do for [i=1:360] { r_max[i] = 0 } do for [i=0:STATS_records-1] { x = real(word(STATS_value_x, i+1)) y = real(word(STATS_value_y, i+1)) r = sqrt(x**2 + y**2) theta = (atan2(y,x) + 2*pi) * 180/pi bin = int(theta) + 1 if (r > r_max[bin]) { r_max[bin] = r } } set table $envelope do for [i=1:360] { if (r_max[i] > 0) { th = (i-1)*pi/180 print sprintf("%.4f %.4f", r_max[i]*cos(th), r_max[i]*sin(th)) } } unset table plot 0 lc 'gray' notitle, \ $envelope using 1:2 w l lc red lw 1.5 notitle, \ filename using ($2-$3):($4-$5):(gprintf("%g", $1)) \ with labels tc lt 1 point pt 7 offset char 1,1 notitle, \ filename using ($2-$3):($4-$5) w l lc black notitle
参考效果


内容的提问来源于stack exchange,提问作者oleg518
相关产品推荐
相关产品推荐

