如何在bash中从文本文件中绘制图形?

时间:2012-12-08 12:31:50

标签: bash graph curses

我有一个文本文件,每行包含两个空白的分隔字段: x y

1 0
10 29
5 2

现在我想看到 y = f(x)的图表,其中 x y 取自文件。

我更喜欢终端中的curses图片,但它也可以是任何图形格式的图片。

bash中最简单的方法是什么?

1 个答案:

答案 0 :(得分:4)

这是一个非常有趣的可能性。我要向你展示的东西可能不是你想要的,它可能没有优化,它可能是一大堆垃圾,但它真的很有趣。 (我不期待任何赞成票)。

此脚本或多或少在每个点处绘制*,其坐标在文件中给出(作为脚本的第一个参数给出)。它计算终端的行数和列数(使用命令stty,如果你碰巧安装它,那就好了,否则,它不会起作用)。

#!/bin/bash

isnumber() {
   for i; do
      [[ "$i" =~ [[:digit:]] ]] || return 1
      [[ "$i" =~ ^[+-]?[[:digit:]]*\.?[[:digit:]]*$ ]] || return 1
   done
   return 0
}

die() {
   echo >&2 "$@"
   exit 1
}

[[ -n $1 ]] || die "You must provide an argument"

xarray=()
yarray=()

# Read file input
while read x y _; do
   isnumber "$x" "$y" || continue
   xarray+=( "$x" )
   yarray+=( "$y" )
done < "$1"

# Check that we have at least one point
(( ${#xarray[@]} )) || die "Error, there's no valid point inf file \`$1'"

# Compute xmin, xmax, ymin and ymax:
read xmin xmax ymin ymax valid < <(
   bc -l < <(
      echo "ymin=${yarray[0]}; ymax=${yarray[0]}"
      echo "xmin=${xarray[0]}; xmax=${xarray[0]}"
      for i in "${!xarray[@]}"; do
         echo "y=${yarray[i]}; if (ymax<y) ymax=y; if (ymin>y) ymin=y"
         echo "x=${xarray[i]}; if (xmax<x) xmax=x; if (xmin>x) xmin=x"
      done
      echo 'print xmin," ",xmax," ",ymin," ",ymax'
      # This will tell us if we have xmin<xmax and ymin<ymax
      echo 'print " ",(xmin<xmax)*(ymin<ymax)'
   )
)

# Check that xmin<xmax and ymin<ymax
(( valid )) || die "Error, ! ( (xmin<xmax) && (ymin<ymax) )"

# Get terminal's number of rows and columns
IFS=' ;' read _ _ _ _ nbrows _ nbcols _ < <(stty -a)
((nbrows-=1))
((maxcols=nbcols-1))
((maxrows=nbrows-1))

# Create an array full of spaces:
points=()
for ((i=0;i<nbrows*nbcols;++i)); do points+=( ' ' ); done

# Put a '*' at each x y in array points
while read r c; do
   printf -v X "%.f" "$c"
   printf -v Y "%.f" "$r"
   points[X+Y*nbcols]='*'
done < <(
   bc -l < <(
      echo "xmin=$xmin; dx=$maxcols/($xmax-xmin)"
      echo "ymax=$ymax; dy=$maxrows/(ymax-($ymin))"
      for i in "${!xarray[@]}"; do
         echo "print (ymax-(${yarray[i]}))*dy,\" \",(${xarray[i]}-xmin)*dx,\"\n\""
      done
   )
)

# Now, print it! The clear is not mandatory    
clear
printf "%c" "${points[@]}"

调用脚本plot_file_in_terminal(或者更短的名字)。

你可以尝试一下,这很有趣,有一个Mandelbrot集:下面的脚本生成一个M-set(你可以给出x和y坐标的像素数作为输入,好吧,通过以下几点来计算自己):

#!/bin/bash

die() {
   echo >&2 "$@"
   exit 1
}

nbx=${1:-100}
nby=${2:-100}
Nmax=${3:-100}

[[ $nbx =~ ^[[:digit:]]+$ ]] && ((nbx>5)) || die "First argument (nbx) must be an integer > 5"
[[ $nby =~ ^[[:digit:]]+$ ]] && ((nby>5)) || die "Second argument (nby) must be an integer > 5"
[[ $Nmax =~ ^[[:digit:]]+$ ]] && ((Nmax>5)) || die "Third argument (Nmax) must be an integer > 5"

xmin=-1.5
xmax=1
ymin=-1
ymax=1

bc -l <<EOF
for (k=0;k<$nbx;++k) {
   for (l=0;l<$nby;++l) {
      x0=k*($xmax-($xmin))/($nbx-1)+($xmin)
      y0=l*($ymax-($ymin))/($nby-1)+($ymin)
      x=x0
      y=y0
      isin=1
      for (i=0;i<$Nmax;++i) {
         if(x^2+y^2>1) {
            isin=0
            break
         }
         xn=x^2-y^2+x0
         y=2*x*y+y0
         x=xn
      }
      if(isin) print x0," ",y0,"\n"
   }
}
EOF

将其命名为genMandelbrot,如果您的终端大于或等于100x50,则将其用作./genMandelbrot > Mset./genMandelbrot 100 50 > Mset。然后:

./plot_file_in_terminal Mset

很好,嗯?

如果你想要一个正弦函数(比如从0到2 * pi):

bc -l <<< "for (i=0;i<400;++i) { x=i*6.28/400; print x,\" \",s(x),\"\\n\" }" > sine

然后致电:

./plot_file_in_terminal sine

输出

Mandelbrot Set(80x24)

                                                        **
                                                    **********
                                                  ***********
                                             *  *************** *   *
                                    *********************************** ****
                                    **************************************** *
                                **********************************************
                              **************************************************
         **************       **************************************************
       ******************** ****************************************************
 **  **************************************************************************
****************************************************************************
 **  **************************************************************************
       ******************** ****************************************************
         **************       **************************************************
                              **************************************************
                                **********************************************
                                    **************************************** *
                                    *********************************** ****
                                             *  *************** *   *
                                                  ***********
                                                    **********
                                                        **
gniourf@somewhere:~/cool_path$ 

正弦(80x24)

                *********
             ****       ***
           ***             **
          **                 **
        **                    **
       **                       **
     ***                         **
    **                            **
   **                               **
  **                                 **
 **                                   **
*                                      **                                      *
                                        **                                    **
                                         **                                 **
                                           **                              **
                                            **                            **
                                             **                          **
                                              ***                      **
                                                **                    **
                                                 ***                ***
                                                   ***            ***
                                                     ***       ****
                                                        ********    
gniourf@somewhere:~/an_even_cooler_path$ 

在你的OP中,你提到了“最简单的做法”......你可以注意到,这个解决方案并不完全是单行。

编辑。

  • 健壮性:检查xmin!=xmaxymin!=ymax,以便不除以0
  • 速度:在同一xmin个实例中计算xmaxyminymaxbc
  • 速度:不再使用tput,它是迟钝而且太慢了!而是构建一个点数组(每个字段包含一个空格或*)。

托多斯。

  • 有很多东西可以让我们真正能够轻松地工作。这项练习留待读者阅读。