【问题标题】:Months in gnuplotgnuplot 中的月份
【发布时间】:2020-12-08 19:46:38
【问题描述】:

我有一个包含 12 个数字的 csv 文件,对应于 12 个月。文件示例如下:

$ cat data.csv
"3","5","6","5","4","6","7","6","4","4","3","3",

我想使用“一月、二月、三月等”在 x 轴上绘制这些月份。

我找到了这个脚本,但我不知道如何输入月份:

for FILE in data.csv; do
 gnuplot -p << EOF
 set datafile separator ","
 set xlabel "xlabel"
 set ylabel "ylabel"
 set title "graphTitle"
 plot "$FILE" using $xcolumn:$ycolumn
  EOF
done

预期的输出应该是一个图,其中 x 轴是月份,y 轴是 csv 文件中的数据。 请注意,CSV 文件中没有月份,只有数字。这就是为什么我要问什么是最好的方法来实现这一点,而不必在 CSV 中手动输入它们或循环遍历数组。有没有gnuplot函数可以添加日期并且可以格式化?

谢谢

【问题讨论】:

  • 您能提供data.csv 的样本吗?至于月份的名称......如果数据文件具有月份的名称和数字数据(即gnuplot 可以读取为 x/y 坐标的格式),它会是什么样子? ...我想知道哪些(编码)选项可用于自动生成月份的名称,但需要知道gnuplot 可以读取的有效格式
  • 嗨@mar​​kp-fuso,data.csv 的样本已经在问题中。我已经复制了 data.csv 的确切内容。这是"3","5","6","5","4","6","7","6","4","4","3","3",
  • 好的,所以你知道for FILE in data.csvFILE=data.csv 循环一次,对吧?
  • 是的,我知道这一点,我需要它用于 $x 变量。但是我不知道如何按照这个逻辑输出月份。
  • 假设您没有在某些“奇怪”的语言环境下运行,您可以通过 locale mon 自动生成月份...包含在我的回答中(如下)

标签: bash awk gnuplot paste


【解决方案1】:

更新:在查看了 OP 帖子和更多代码后,我猜测所需的格式如下:

January:"3",February:"5",March:"6",April:"5",May:"4",June:"6",July:"7",August:"6",September:"4",October:"4",November:"3",December:"3",

如果是这种情况,我们可以使用相同的解决方案(如下),并通过tr 将最终结果转置回单行/多列数据集,例如:

$ paste -d" " <(locale mon | tr ';' '\n') <(tr ',' '\n' < data.csv) | grep -v '^ $' | tr ' \n' ':,'
January:"3",February:"5",March:"6",April:"5",May:"4",June:"6",July:"7",August:"6",September:"4",October:"4",November:"3",December:"3",

以及更新 OPs 代码:

datfile=$(mktemp)
for FILE in data.csv
do
    paste -d" " <(locale mon | tr ';' '\n') <(tr ',' '\n' < data.csv) | grep -v '^ $' | tr ' \n' ':,' > "${datfile}"

    gnuplot -p <<-EOF
    set datafile separator ","
    set xlabel "xlabel"
    set ylabel "ylabel"
    set title "graphTitle"
    plot "${datfile}" using $xcolumn:$ycolumn
    EOF
done
'rm' -rf "${datfile}" > /dev/null 2>&1

看起来gnuplot 可以接受各种格式的数据,包括:

January "3"
February "5"
March "6"
April "5"
May "4"
June "6"
July "7"
August "6"
September "4"
October "4"
November "3"
December "3"

注意:如果 OP 确定这不是可接受的文件格式,那么我相信我们可以想出别的东西……只需要用有效文件的样本更新问题显示月份和数字的格式。

因此,如果我们可以即时生成此数据集,我们就可以将其提供给gnuplot ...

首先我们让locale 为我们生成月份:

$ locale mon
January;February;March;April;May;June;July;August;September;October;November;December

接下来我们可以将单行/多列数据集转置为多行/单列数据集:

$ locale mon | tr ';' '\n'
January
February
March
April
May
June
July
August
September
October
November
December

$ tr ',' '\n' < data.csv
"3"
"5"
"6"
"5"
"4"
"6"
"7"
"6"
"4"
"4"
"3"
"3"

从这里我们可以将paste这两个数据集放在一起,使用空格作为列分隔符:

$ paste -d" " <(locale mon | tr ';' '\n') <(tr ',' '\n' < data.csv)
January "3"
February "5"
March "6"
April "5"
May "4"
June "6"
July "7"
August "6"
September "4"
October "4"
November "3"
December "3"

最后一步是将其写入 (tmp) 文件,例如:

$ datfile=$(mktemp)
$ paste -d" " <(locale mon | tr ';' '\n') <(tr ',' '\n' < data.csv) | grep -v '^ $' > "${datfile}"
$ cat "${datfile}"
January "3"
February "5"
March "6"
April "5"
May "4"
June "6"
July "7"
August "6"
September "4"
October "4"
November "3"
December "3"

注意grep -v '^ $' 是为了去掉与data.csv 中最后一个逗号(,)相关的末尾多余的行

从这里"${datfile}" 可以根据需要提供给gnuplot,一旦不再需要就删除,例如:

$ gnuplot ... "${datfile}" ...
$ 'rm' -rf "${datfile}" > /dev/null 2>&1

【讨论】:

  • 嗨@mar​​kp-fuso 非常感谢您的详细回答。这对我来说很有意义,但是在运行它时出现以下错误:gnuplot&gt; plot "/tmp/tmp.CSHtJEV8sR" using : line 0: constant expression required 我无法运行它。我什至输出了 $d{datfile} 的结果,对我来说看起来不错。知道为什么吗?
  • 我不是gnuplot 用户...我的回答仅仅集中在尝试构建一个有效的输入/数据文件——这又是基于对哪些格式有效的猜测;最终结果...没有更多详细信息(例如,${datfile} 文件的确切内容、$xcolumn$ycolumn 变量的值,以及正在运行的整个gnuplot 命令)...我不会去有很大帮助
【解决方案2】:

如果您不介意输入月份名称,我认为最简单的是这个。为清楚起见,数据显示在行内,而不是从文件中读取。

$DATA << EOD
"3","5","6","5","4","6","7","6","4","4","3","3",
EOD

set datafile sep comma
set xrange [0:13]
unset key

array Month[12] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

plot for [N=1:12] $DATA using (N):(column(N)):xticlabel(Month[N]) with impulse lw 5

如果您不想输入月份名称,则以下应生成等价的名称。 "%b" 将生成如上所述的缩写月份名称。 "%B"将生成完整的月份名称。

Month(i) = strftime("%b", i * 3600.*24.*28.)
plot for [N=1:12] $DATA using (N):(column(N)):xticlabel(Month(N)) with impulse lw 5

【讨论】:

    【解决方案3】:

    如果您不想使用循环语法,有一种方法可以将 CSV 文件读取为 1x12 矩阵。此外,对于长月份名称,您可以使用 gnuplot 的 strftime 函数,为其指定格式说明符“%B”。

    gnuplot 脚本在这里。

    set key noautotitle
    set datafile separator comma
    set yrange [0:10]
    set xrange [-1:12]
    set xtics rotate by -45
    set grid xtics
    
    # This function generates the names "January", "February", ... 
    #                from the integer value 0, 1, ...
    #
    monthname(i) = strftime("%B",strptime("%m",sprintf("%i",i+1)))
    
    # `matrix every ...` specifier tells to read the data as a 1x12 matrix.
    #
    plot "data.csv" matrix every :::0:11:0 using 1:3:xtic(monthname($1)) with linespoints pt 7 
    

    【讨论】:

      【解决方案4】:

      另一种解决方案。因为你有一个尾随逗号,并且 gnuplot 期望它后面有一个数字,所以你会收到一个警告 warning: matrix contains missing or undefined values,你可以忽略它。因此,您应该将 x 最大值限制为更小的 12。 在您的情况下,将$Data 替换为您的文件名'data.csv'。您可能想要设置其他语言环境(检查 help locale)以获取其他语言的月份名称。

      代码:

      ### plot monthly data
      reset session
      
      $Data <<EOD
      "3","5","6","5","4","6","7","6","4","4","3","3",
      EOD
      
      set datafile separator comma
      set boxwidth 0.8
      set style fill solid 0.5
      set yrange[0:10]
      set xrange[-0.9:11.9]
      myMonth(i) = strftime("%b",i*3600*24*31)   # get month name as abbreviation, use %B for full name
      
      plot $Data matrix u 1:0:xtic(myMonth($1)) w boxes title "my data"
      ### end of code
      

      结果:

      【讨论】:

        【解决方案5】:

        一个awk 解决方案围绕与paste 答案相同的逻辑构建,但消除了一些子流程(例如,grep、多个tr's)...

        awk -F'[;,]' '                             # input field delimiters are ";" and ","
        BEGIN   { OFS=":" ; ORS="," }              # set output field delimiter as ":" and output record delimiter as ","
        FNR==NR { for (i=1 ; i<=NF ; i++)          # loop through fields from first file ...
                  month[i]=$(i)                    # store in our month[] array
                  next                             # skip to next input line
                }
                { for (i=1 ; i< NF ; i++)          # loop through fields from second file ...
                  print month[i],$(i)              # print month and current field
                }
        ' <(locale mon) data.csv
        

        这会生成:

        January:"3",February:"5",March:"6",April:"5",May:"4",June:"6",July:"7",August:"6",September:"4",October:"4",November:"3",December:"3",
        

        将其滚动到 OP 的代码中:

        datfile=$(mktemp)
        for FILE in data.csv
        do
            awk -F'[;,]' 'BEGIN{OFS=":";ORS=","} FNR==NR {for (i=1;i<=NF;i++) mon[i]=$(i); next} {for (i=1;i<NF;i++) print mon[i],$(i)}' <(locale mon) data.csv > "${datfile}"
        
            gnuplot -p <<-EOF
            set datafile separator ","
            set xlabel "xlabel"
            set ylabel "ylabel"
            set title "graphTitle"
            plot "${datfile}" using $xcolumn:$ycolumn
            EOF
        done
        'rm' -rf "${datfile}" > /dev/null 2>&1
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-13
          • 2012-01-08
          • 2019-11-09
          • 1970-01-01
          • 2014-06-16
          • 1970-01-01
          相关资源
          最近更新 更多