gnuplot用数组打印多个文件

时间:2016-12-21 11:53:02

标签: bash gnuplot

我需要使用bash脚本在一个绘图中绘制多个文件。我可以通过在绘图函数中手动声明文件的位置来管理它,即

plot "$outputdir/10/values.csv" using 1:2 with lines title "10", \
"$outputdir/20/values.csv" using 1:2 with lines title "20", \
"$outputdir/30/values.csv" using 1:2 with lines title "30"

这将在一个图中打印所有三个值文件。但是我有一个动态数组,它会根据它想要获得的值来改变。所以让我们说数组arr看起来像这样

arr=(10 20 30 40)
#Sometimes arr has more values ex; arr=(10 20 30 40 50 60 70 80)
#arr corresponds to folders that will be created
#And will contain a values.csv file that I want to plot

如果我不手动更改绘图代码

,则不会打印40 / values.csv

我目前尝试修复此问题是gnuplot中的for循环

#The array arr is dynamically generated in another function
#Varies in size as example above

ArrLength=${#arr[@]} #Get the length of array
plot for [p=0:$ArrLength] "$outputdir/${arr[$p]}/values.csv" using 1:2 with lines title "${arr[$p]}"

绘图时我没有出错,但在绘图中只绘制了一个值,这就是数组中的第一个值,即它只绘制$ outputdir / 10 / values.csv。

我尝试设置p = 0:4来绘制前五个文件,但它仍然只绘制了第一个文件。上面的for循环有什么问题?

祝你好运

1 个答案:

答案 0 :(得分:2)

你似乎是以一种奇怪的方式混合bash和gnuplot。使用bash脚本尝试使用插入的变量动态生成gnuplot脚本是一种让自己迷惑的快速方法。它也使得阅读和调试变得困难。很容易忘记bash正在评估什么以及gnuplot正在评估什么。

当我查看你的第一行时

ArrLength=${#arr[@]} #Get the length of array

我可以看到这是bash代码,因为gnuplot会解释以第一个#开头的注释。 (这也是bash的数组语法,而不是gnuplot的。)美元符号$在gnuplot中有不同的含义。 $不是标记变量标识符,而是列号操作符($2是第2列,$i是列 i 等)。所以看一下

plot for [p=0:$ArrLength] "$outputdir/${arr[$p]}/values.csv" using 1:2 with lines title "${arr[$p]}"

这显然是一行bash语法,显然是在试图写一行gnuplot的字符串中。 Bash将评估变量$ArrLength$outputdir${arr[$p]},并将其替换为其值的一些字符串。还要记住,p是gnuplot中的变量,而不是bash中的变量。 Bash会将$p评估为某些内容(如果尚未定义,则为空字符串)。您不能指望gnuplot变量p${arr[$p]}的bash评估中用作索引,然后以某种方式为gnuplot循环的每次迭代产生不同的字符串。

简而言之,你所写的不是gnuplot语法,它也不是一个简单而完整的bash脚本。目前尚不清楚你究竟打算如何将bash和gnuplot这样组合在一起,但似乎你加入它们太紧了。

我的建议是编写 bash脚本并编写 gnuplot脚本(作为单独的文件)。 Gnuplot有自己的流量控制,迭代循环和变量评估。您可以编写一个自包含的gnuplot脚本,用于您需要执行的所有操作的一般情况,然后在bash脚本的命令行中为其提供详细信息。

例如,您的子目录似乎都是10的倍数,并且始终以10开头。唯一可变的方面是有多少(最后一个是什么)。假设最后一个值以某种方式存储在gnuplot变量last中。另外,假设我们还以某种方式在outputdir中使用了基本输出目录:

(在 gnuplot 脚本中,名为plot.gp):

plot for [p=10:last:10] sprintf("%s/%d/values.csv", outputdir, p) with lines title sprintf("%d", p)

for [p=10:last:10]表示从10到last(包括)迭代,每次迭代加10。第一个sprintf()函数(如C)使用outputdirp构建一个字符串(两者都是gnuplot中的变量)。 using 1:2不是必需的,因为前两列是使用with lines的默认列,但如果您想要显式,则可以包含它们。第二个sprintf()从迭代变量p构建标题字符串。

现在,假设outputdirlast具有有意义的值。在命令行上调用gnuplot时,可以从bash脚本中分配这些值:

(在 bash 脚本中,调用gnuplot脚本)

gnuplot -e "last=40" -e "outputdir=\"$outputdir\"" plot.gp

-e选项告诉gnuplot在文件plot.gp中运行脚本之前评估给定的字符串。在此示例中,gnuplot变量last将具有值40,而gnuplot变量outputdir将具有bash评估$outputdir的任何值。注意双引号内的转义双引号。外部双引号是允许bash评估字符串中的变量($outputdir需要由bash评估)。内部(转义)引号用于分隔gnuplot代码中的字符串。例如,如果bash评估$outputdirdata,那么gnuplot会看到outputdir="data",这是对变量outputdir的字符串的有效gnuplot赋值。如果需要,您可以将这两个-e选项合并为一个:

gnuplot -e "last=40;outputdir=\"$outputdir\"" plot.gp

您可能希望在bash中使用数组中last的值,而不是像这样硬编码。所以在实践中它看起来更像是

gnuplot -e "last=${arr[${#arr[@]}-1]};outputdir=\"$outputdir\"" plot.gp

或者,如果你有bash 4.3或更高版本,你应该可以使用negative index

gnuplot -e "last=${arr[-1]};outputdir=\"$outputdir\"" plot.gp

请注意,使用数组变量时没有转义引号。预计它将评估为整数(4090等),我们希望将last分配给整数,而不是outputdir之类的字符串。

如果这个字符串看起来很复杂,请尝试像这样考虑整个脚本。很容易对bash正在做什么以及gnuplot正在做什么感到困惑。

总之,编写一个bash脚本和一个单独的 gnuplot脚本。 Gnuplot能够处理一般情况。从bash开始,只需动态提供一些细节,不要试图动态生成整个脚本。它确实使事情变得更简单。