【问题标题】:Plotting an IR Spectrum with Gnuplot使用 Gnuplot 绘制红外光谱
【发布时间】:2025-12-29 05:35:15
【问题描述】:

我有一个我想要绘制的感兴趣化合物的红外光谱,并且我有一个包含所有数据点的 spectrum.dat 文件。它的形式是:

    # X  Y     
    300  100
    301  100
    302   99
    303   70
    ...
    3999  98
    4000 100

我想使用典型的 IR 光谱 x 轴来绘制此图,但我在这样做时遇到了麻烦。 If you are unfamiliar, this is what a typical IR spectrum might look like(除了图表本身的标签)。请注意,x 轴是反转的,并且在超过 2000 个单位(厘米倒数)时,它的缩放比例突然加倍。有没有办法强迫 Gnuplot 以这种方式绘制我的数据?到目前为止,我已经设法想出了以下脚本:

    # Make an SVG of size 800x500
    set terminal svg size 800,500 fname 'CMU Sans Serif' fsize '10'
    set output 'ir.svg'
    # Color definitions
    set border linewidth 1.5
    set style line 1 lc rgb '#a0a0a0' lt 1 lw 2 pt 7 # gray
    # Format graph
    unset key
    set xlabel 'Wavenumbers'
    set ylabel 'Transmittance'
    set xrange [4000:300]
    # Plot data
    plot 'spectrum.dat' with lines ls 1

这很好地反转了 x 轴,但我不知道如何以这种不寻常的方式更改缩放比例。

【问题讨论】:

标签: plot gnuplot spectrum infrared chemistry


【解决方案1】:

作为一名化学家,我有动力回答...

据我所知,gnuplot 不容易允许任意轴缩放(除非有人对如何使用 set link 有好主意)。在这种情况下,我的策略是分别绘制两半并让它们无缝连接:

#!/usr/bin/env gnuplot

set terminal png size 800,500
set output 'ir.png'

set xlabel 'Wavenumbers' offset 20
set ylabel 'Transmittance'

set tics out nomirror

set key bottom right

set bmargin 4

set yrange [0:1]

set multiplot layout 1,2 title 'IR Spectrum of Cholesterol'

# left half of plot
set xrange [4000:2000]
set rmargin 0
set border 7
plot 'cholesterol.txt' notitle

# right half of plot
set xrange [1999:300]
set lmargin 0
set rmargin 2
set border 13

unset xlabel
unset ylabel
unset ytics

plot 'cholesterol.txt' title 'Cholesterol'

unset multiplot

我的一个小问题是,2000 被写了两次,在我的屏幕上看起来更粗,但我会把烦躁的抽动留给你。

【讨论】:

    【解决方案2】:

    andyras 的回答很好,就布局选项而言,这可以说是一种更简单(更优雅:-P)的解决方案。这也应该是一个更通用的解决方案。如果没有太多的抽动(如果抽动太多,请阅读下图),那么可以将曲线本身缩放到 2000 以上,然后手动添加所有抽动。由于我没有可用的红外光谱数据,我将使用虚拟文件“+”并将 log(x) 从 4000 绘制到 500:

    xmax=4000 ; xmin = 500
    pivot = 2000 ; rescfactor = 2.
    rescale(x) = (x >= pivot ? x : pivot + rescfactor*(x-pivot))
    set xrange [rescale(xmax):rescale(xmin)]
    set xtics ("4000" 4000, "3000" 3000, "2000" 2000, \
    "1500" rescale(1500), "1000" rescale(1000), "500" rescale(500))
    plot "+" u (rescale($1)):(log($1)) w l
    

    在您的情况下,您只需将 log($1) 替换为 2 或您正在绘制的任何内容。

    在较新版本的 gnuplot(从 4.4 开始)中,可以使用循环自动添加抽动:

    xmax = 4000 ; xmin = 500 ; step = 500
    set xtics (sprintf("%i",xmax) rescale(xmax)) # Add the first tic by hand
    set for [i=xmin:xmax-step:step] xtics add (sprintf("%i",i) rescale(i))
    

    从 gnuplot 4.6 开始,还可以使用 do for 进行不同的 for 构造:

    do for [i=xmin:xmax-step:step] {set xtics add (sprintf("%i",i) rescale(i))}
    

    【讨论】:

    • 不错的答案,我可能会做的一个改变是定义pivot=2000; rescale(x) = ($1 >= pivot ? $1 : pivot + 2.*($1-pivot)),这样您就可以在所有数量上调用该函数。
    • @andyras 改变了,我还添加了一个缩放因子。有趣的是,我今天需要在工作中使用这个解决方案来处理完全不相关的事情......
    • 如果您将xtics 的迭代更改为使用set for,它也适用于版本4.4:set for [i=xmin:xmax-step:step] xtics add (sprintf("%i",i) rescale(i))。只有 do for 结构是在 4.6 版中引入的。