Gnuplot:分类数据 - 将颜色与数据相匹配添加范围线
Gnuplot: categorised data - match color to data add range lines
给定一组适合某个类别的值,我想
a) 根据类别(x 轴)将数据值绘制为点(y 轴)
b) 将点颜色与类别相匹配
c) 添加一行,范围从每组的最小值到最大值
我所做的是使用此代码:
set terminal png
set output 'animals.png'
set ytics nomirror
unset key
set xrange [-0.5:5.5]
plot for [i=2:5] 'cat.dat' using i:xtic(1)
show xrange
在 x 轴上按类别成功标记,但颜色是根据列(而不是行)设置的,我不知道如何添加范围条(注意:不是误差条或百分位数,而是完整的最小值-> 最大范围)- 特别是因为数据是按列调用的,但随后需要按行进行分析。不过,AFAIK gnuplot 只做列。
有什么想法吗?
以上代码的输出:
示例数据(制表符分隔):
cat 0.26 0.4 0.23 0.16
dog 0.317 0.264 0.25 0.26
bat 0.33 0.42 0.32 0.48
rat 0.59 0.62 0.57 0.56
foo 0.59 0.67 0.71 0.70
bar 0.664 0.75 0.68 0.6
这需要多做几步,最重要的是,给每个类别一个唯一的索引号,并转置数据:
(我将在此处引用 GNU unix shell 命令)
$cat -n data_orig.dat | datamash transpose > data_trans.dat
$cat data_trans.dat #added spaces for readability
1 2 3 4 5 6
cat dog bat rat foo bar
0.26 0.317 0.33 0.59 0.59 0.664
0.4 0.264 0.42 0.62 0.67 0.75
0.23 0.25 0.32 0.57 0.71 0.68
0.16 0.26 0.48 0.56 0.70 0.6
现在可以按列正确分析数据,并根据索引号定义颜色。
条形由箭头组成,其中最小值和最大值取自每列的统计分析。
xticlabels
通过系统调用读入一维 word
数组(这是一个内部 gnuplot
函数),数组索引与数据列的唯一索引相匹配。
带有非常详细解释的脚本,以更好地支持新的 gnuplot 用户:
#output and style settings: make png-file, name it 'animals.png',
# yaxis tics on both sides, no legend
set terminal png
set output 'animals.png'
set ytics mirror
unset key
#data indices are integers from 1 to 6, a bit of space for the looks
set xrange [0.5:6.5]
#define color scheme for each data series
set palette defined ( 0 'purple', 1 'blue', 2 'green', \
3 'yellow', 4 'orange', 5 'red' , 6 'black' )
#hide color gradient bar of palette
unset colorbox
#define array names using word function:
# read in 2nd line of data by system call and run through words
# each space-delimited word is now an array element of names
names(n) = word( system("sed -n '2p' cat.dat_t" ) , n )
#create min->max bars
#loop over all data sets to create bars
do for [i=1:6] {
#among others this gives minimum and maximum values of the data set
#using i -> only handle column i in statistics
#every ::3 start with row 3 for statistical analysis
stats 'data_trans.dat' using i every ::3
#use min/max values for arrow y positions, index i for x positions
#heads = arrow head on both sides
#size 0.1,90 = 0.1 line lengths for arrow head
# and 90° arrow head line angles = T bar style
#lc palette cb i = use line color (lc) from palette value matching
# color bar (cb) value of index i
set arrow from i,STATS_min to i,STATS_max heads size 0.1,90 lc palette cb i
}
#plotting:
# for [i=1:6] loop over all 6 columns, use i as loop variable
# every ::3 start with row 3 for data plotting
# using (i):i:(i):xtic(names(i))
# syntax of using
# x-value:y-value:z-value:label_x_axis [:label_y_axis:label_z_axis]
# (i) -> literal value of i for x and z, z is used as color definition
# i -> y-values from column i
# xtic(names(i)) get element i of array names for xtic label
# lc palette -> coloring according to defined palette
# pt 7 ps 1.5 -> point style and size definition
plot for [i=1:6] 'data_trans.dat' every ::3 using (i):i:(i):xtic(names(i)) lc palette pt 7 ps 1.5
参考文献:
结果:
编辑:
如@theozh 的回答所示,linespoints
更适合显示范围。这允许通过在绘图命令行中添加 w lp
来跳过整个 bar/arrow 创建块。
正如您所注意到的,gnuplot 不喜欢行并且不幸的是不(还?)提供转置函数。在您的解决方案中,您使用的是 Unix 系统 calls/tools 和 sed
,它们不一定与平台无关。此外,您正在绘制点和单独的箭头来连接,如果您不坚持在最小值和最大值处使用水平条,我想您可以通过 linespoints
来简化它。
让我展示一些 "simplified" platform-independent gnuplot-仅 代码。
一般程序:
- 加载文件到数据块
- 转置数据块
- 用线点绘制列
没有header的数据文件TAB-separated:Animals.dat
cat 0.26 0.4 0.23 0.16
dog 0.317 0.264 0.25 0.26
bat 0.33 0.42 0.32 0.48
rat 0.59 0.62 0.57 0.56
foo 0.59 0.67 0.71 0.70
bar 0.664 0.75 0.68 0.6
下面的代码需要一个 FileToDatablock 例程和一个 DatablockTranspose 例程。
将文件加载到数据块的过程:FileToDatablock.gpp
### Load datafile "as is" into datablock for different platforms
# ARG1 = input filename
# ARG2 = output datablock
if (GPVAL_SYSNAME[:7] eq "Windows") { # "Windows_NT-6.1" is shown on a Win7 system
load '< echo '.ARG2.' ^<^<EOD & type "'.ARG1.'"'
}
if (GPVAL_SYSNAME eq "Linux") { # that's shown on a Raspberry
load '< echo "$Data << EOD" & cat "'.ARG1.'"'
}
if (GPVAL_SYSNAME eq "Darwin") { # this was shown on a MacOS Sierra 10.12.6
load '< echo "$Data << EOD" & cat "'.ARG1.'"' # identical to Linux
}
### end of code
转置数据块的 gnuplot 程序:DatablockTranspose.gpp
### transpose datablock (requires whitespace as separator)
# ARG1 = Input datablock
# ARG2 = Output datablock
set print @ARG2
do for [DBT_i=1:words(@ARG1[1])] {
DBT_Line = ""
do for [DBT_j=1:|@ARG1|] {
DBT_Line = DBT_Line.word(@ARG1[DBT_j],DBT_i).\
(DBT_j < |@ARG1| ? "\t" : "")
}
print DBT_Line
}
set print
undefine DBT_*
### end of code
实际代码:
### plotting rows
reset session
# load file to datablock
call "FileToDatablock" "Animals.dat" "$Data"
# transpose datablock by gnuplot procedure
call "DatablockTranspose.gpp" "$Data" "$DataTransposed"
set palette defined ( 0 'purple', 1 'blue', 2 'green', \
3 'yellow', 4 'orange', 5 'red' , 6 'black' )
unset colorbox
set xrange[0.5:|$Data|+0.5]
plot for [i=1:|$Data|] $DataTransposed u (i):i:(i):xtic(columnhead(i)) w lp pt 7 ps 1.5 lc palette not
### end of code
结果:
给定一组适合某个类别的值,我想
a) 根据类别(x 轴)将数据值绘制为点(y 轴) b) 将点颜色与类别相匹配 c) 添加一行,范围从每组的最小值到最大值
我所做的是使用此代码:
set terminal png
set output 'animals.png'
set ytics nomirror
unset key
set xrange [-0.5:5.5]
plot for [i=2:5] 'cat.dat' using i:xtic(1)
show xrange
在 x 轴上按类别成功标记,但颜色是根据列(而不是行)设置的,我不知道如何添加范围条(注意:不是误差条或百分位数,而是完整的最小值-> 最大范围)- 特别是因为数据是按列调用的,但随后需要按行进行分析。不过,AFAIK gnuplot 只做列。
有什么想法吗?
以上代码的输出:
示例数据(制表符分隔):
cat 0.26 0.4 0.23 0.16
dog 0.317 0.264 0.25 0.26
bat 0.33 0.42 0.32 0.48
rat 0.59 0.62 0.57 0.56
foo 0.59 0.67 0.71 0.70
bar 0.664 0.75 0.68 0.6
这需要多做几步,最重要的是,给每个类别一个唯一的索引号,并转置数据:
(我将在此处引用 GNU unix shell 命令)
$cat -n data_orig.dat | datamash transpose > data_trans.dat
$cat data_trans.dat #added spaces for readability
1 2 3 4 5 6
cat dog bat rat foo bar
0.26 0.317 0.33 0.59 0.59 0.664
0.4 0.264 0.42 0.62 0.67 0.75
0.23 0.25 0.32 0.57 0.71 0.68
0.16 0.26 0.48 0.56 0.70 0.6
现在可以按列正确分析数据,并根据索引号定义颜色。
条形由箭头组成,其中最小值和最大值取自每列的统计分析。
xticlabels
通过系统调用读入一维 word
数组(这是一个内部 gnuplot
函数),数组索引与数据列的唯一索引相匹配。
带有非常详细解释的脚本,以更好地支持新的 gnuplot 用户:
#output and style settings: make png-file, name it 'animals.png',
# yaxis tics on both sides, no legend
set terminal png
set output 'animals.png'
set ytics mirror
unset key
#data indices are integers from 1 to 6, a bit of space for the looks
set xrange [0.5:6.5]
#define color scheme for each data series
set palette defined ( 0 'purple', 1 'blue', 2 'green', \
3 'yellow', 4 'orange', 5 'red' , 6 'black' )
#hide color gradient bar of palette
unset colorbox
#define array names using word function:
# read in 2nd line of data by system call and run through words
# each space-delimited word is now an array element of names
names(n) = word( system("sed -n '2p' cat.dat_t" ) , n )
#create min->max bars
#loop over all data sets to create bars
do for [i=1:6] {
#among others this gives minimum and maximum values of the data set
#using i -> only handle column i in statistics
#every ::3 start with row 3 for statistical analysis
stats 'data_trans.dat' using i every ::3
#use min/max values for arrow y positions, index i for x positions
#heads = arrow head on both sides
#size 0.1,90 = 0.1 line lengths for arrow head
# and 90° arrow head line angles = T bar style
#lc palette cb i = use line color (lc) from palette value matching
# color bar (cb) value of index i
set arrow from i,STATS_min to i,STATS_max heads size 0.1,90 lc palette cb i
}
#plotting:
# for [i=1:6] loop over all 6 columns, use i as loop variable
# every ::3 start with row 3 for data plotting
# using (i):i:(i):xtic(names(i))
# syntax of using
# x-value:y-value:z-value:label_x_axis [:label_y_axis:label_z_axis]
# (i) -> literal value of i for x and z, z is used as color definition
# i -> y-values from column i
# xtic(names(i)) get element i of array names for xtic label
# lc palette -> coloring according to defined palette
# pt 7 ps 1.5 -> point style and size definition
plot for [i=1:6] 'data_trans.dat' every ::3 using (i):i:(i):xtic(names(i)) lc palette pt 7 ps 1.5
参考文献:
结果:
编辑:
如@theozh 的回答所示,linespoints
更适合显示范围。这允许通过在绘图命令行中添加 w lp
来跳过整个 bar/arrow 创建块。
正如您所注意到的,gnuplot 不喜欢行并且不幸的是不(还?)提供转置函数。在您的解决方案中,您使用的是 Unix 系统 calls/tools 和 sed
,它们不一定与平台无关。此外,您正在绘制点和单独的箭头来连接,如果您不坚持在最小值和最大值处使用水平条,我想您可以通过 linespoints
来简化它。
让我展示一些 "simplified" platform-independent gnuplot-仅 代码。
一般程序:
- 加载文件到数据块
- 转置数据块
- 用线点绘制列
没有header的数据文件TAB-separated:Animals.dat
cat 0.26 0.4 0.23 0.16
dog 0.317 0.264 0.25 0.26
bat 0.33 0.42 0.32 0.48
rat 0.59 0.62 0.57 0.56
foo 0.59 0.67 0.71 0.70
bar 0.664 0.75 0.68 0.6
下面的代码需要一个 FileToDatablock 例程和一个 DatablockTranspose 例程。
将文件加载到数据块的过程:FileToDatablock.gpp
### Load datafile "as is" into datablock for different platforms
# ARG1 = input filename
# ARG2 = output datablock
if (GPVAL_SYSNAME[:7] eq "Windows") { # "Windows_NT-6.1" is shown on a Win7 system
load '< echo '.ARG2.' ^<^<EOD & type "'.ARG1.'"'
}
if (GPVAL_SYSNAME eq "Linux") { # that's shown on a Raspberry
load '< echo "$Data << EOD" & cat "'.ARG1.'"'
}
if (GPVAL_SYSNAME eq "Darwin") { # this was shown on a MacOS Sierra 10.12.6
load '< echo "$Data << EOD" & cat "'.ARG1.'"' # identical to Linux
}
### end of code
转置数据块的 gnuplot 程序:DatablockTranspose.gpp
### transpose datablock (requires whitespace as separator)
# ARG1 = Input datablock
# ARG2 = Output datablock
set print @ARG2
do for [DBT_i=1:words(@ARG1[1])] {
DBT_Line = ""
do for [DBT_j=1:|@ARG1|] {
DBT_Line = DBT_Line.word(@ARG1[DBT_j],DBT_i).\
(DBT_j < |@ARG1| ? "\t" : "")
}
print DBT_Line
}
set print
undefine DBT_*
### end of code
实际代码:
### plotting rows
reset session
# load file to datablock
call "FileToDatablock" "Animals.dat" "$Data"
# transpose datablock by gnuplot procedure
call "DatablockTranspose.gpp" "$Data" "$DataTransposed"
set palette defined ( 0 'purple', 1 'blue', 2 'green', \
3 'yellow', 4 'orange', 5 'red' , 6 'black' )
unset colorbox
set xrange[0.5:|$Data|+0.5]
plot for [i=1:|$Data|] $DataTransposed u (i):i:(i):xtic(columnhead(i)) w lp pt 7 ps 1.5 lc palette not
### end of code
结果: