绘制包含 gnuplot/matplotlib 矩阵的大型文本文件

Plotting large text file containing a matrix with gnuplot/matplotlib

出于调试目的,我的程序以原始 ascii 格式将基于犰狳的矩阵写入文本文件,即复数写为 (1, 1)。此外,生成的矩阵导致文件大小 > 3 GByte。

我想“绘制”那些矩阵(代表字段),以便我可以查看字段中的不同点以进行调试。最好的方法是什么?

当使用

使用 gnuplot 直接绘制我的文件时
plot "matrix_file.txt" matrix with image

我收到回复

warning: matrix contains missing or undefined values
Warning: empty cb range [0:0], adjusting to [-1:1]

我也可以使用 Matplotlib,遍历文件中的每一行并将值转换为适当的 python 值,但我认为读取完整文件这样做会相当耗时。

因此,是否有其他合理的快速选项来绘制我的矩阵,或者有没有办法告诉 gnuplot 如何正确处理我的复数?

第一行的一部分看起来像

(0.0000000000000000e+00,0.0000000000000000e+00) (8.6305562282169946e-07,6.0526580514090297e-07) (1.2822974500623326e-05,1.1477679031930141e-05) (5.8656372718492336e-05,6.6626342814082442e-05) (1.6183121649896915e-04,2.3519364967920469e-04) (3.2919257507746272e-04,6.2745022681547850e-04) (5.3056616247733281e-04,1.3949688132772061e-03) (6.7714688179733437e-04,2.7240206117506108e-03) (6.0083005524875425e-04,4.8217990806492588e-03) (3.6759450038482363e-05,7.8957232784174231e-03) (-1.3887302495780910e-03,1.2126758313515496e-02) (-4.1629396217170980e-03,1.7638346107957101e-02) (-8.8831593853181175e-03,2.4463072133103888e-02) (-1.6244140097742808e-02,3.2509486873735290e-02) (-2.7017231109227786e-02,4.1531431496659221e-02) (-4.2022691198292300e-02,5.1101686500864850e-02) (-6.2097364532786636e-02,6.0590740956970250e-02) (-8.8060067117896060e-02,6.9150058884242055e-02) (-1.2067637255414780e-01,7.5697648270160053e-02) (-1.6062285417043359e-01,7.8902435158400494e-02) (-2.0844826713055306e-01,7.7163461035715558e-02) (-2.6452596415873003e-01,6.8580842184681204e-02) (-3.2898869195273894e-01,5.0918234150147214e-02) (-4.0163477687695504e-01,2.1561405580661022e-02) (-4.8179470918233597e-01,-2.2515842273449008e-02) (-5.6815035401912617e-01,-8.4759639628930100e-02) (-6.5850621484774385e-01,-1.6899215347429869e-01) (-7.4952345707877654e-01,-2.7928561041518252e-01) (-8.3644196044174313e-01,-4.1972419090890900e-01) (-9.1283160402230334e-01,-5.9403043419268908e-01) (-9.7042844114238713e-01,-8.0504703287094281e-01) (-9.9912107865273936e-01,-1.0540865412492695e+00) (-9.8715384989307420e-01,-1.3401890190155983e+00) (-9.2160320921981831e-01,-1.6593576679224276e+00) (-7.8916051033438095e-01,-2.0038702251062159e+00) (-5.7721850912406181e-01,-2.3617835609973805e+00) (-2.7521347260072193e-01,-2.7167550691449942e+00)

理想情况下,我希望能够选择是仅绘制实部、虚部还是 abs() 值。

也许不是您要求的,但我认为直接从您的代码中绘制是很巧妙的,并且修改您想要显示的内容也很简单abs(x),real(x),...这是一个简单的片段,用于绘制犰狳矩阵作为gnuplot 中的图像 (Linux)

#include <armadillo>
using namespace std;
using namespace arma;

void plot_image(mat& x, FILE* cmd_pipe)
{    
  fputs("set nokey;set yrange [*:*] reverse\n", cmd_pipe);
  fputs("plot '-' matrix with image\n", cmd_pipe);
  for(uword r=0; r<x.n_rows; r++){
    for(uword c=0; c<x.n_cols; c++){
      string str=to_string(x(r,c))+" ";
      fputs(str.c_str(), cmd_pipe);
    }
    fputs("\n", cmd_pipe);
  }
  fputs("e\n", cmd_pipe);
}

int main()
{
  FILE* gnuplot_pipe = popen("gnuplot -persist","w");
    
  mat x={{1,2,3,4,5},
         {2,2,3,4,5},
         {3,3,3,4,5},
         {4,4,4,4,5},
         {5,5,9,9,9}};
       
  plot_image(x,gnuplot_pipe);        
  return 0 ;    
}

输出为:

这里是一个 gnuplot 版本。 实际上,我还没有看到(还)关于如何从数据文件中绘制复数的 gnuplot 示例。 在这里,想法是通过以下方式将数据拆分为字符 (, 以及 ) 的列:

set datafile separator '(,)'

然后您可以分别通过 column(3*i-1)column(3*i) 来解决列中的第 i 个实部和虚部。

您正在通过在双循环中多次绘制数据来创建新数据集,这对于小数据是可以的。但是,我的猜测是,对于大型数据集,此解决方案可能会变得非常慢,尤其是当您从文件中绘图时。我假设如果您在数据块(而不是文件)中有一次数据,它可能会更快。检查 。通常,使用其他工具可能更有效,例如Python、awk等准备数据。

只是一个想法:如果你有大约。 3e9 字节的数据和(根据您的示例)大约。每个数据点 48-50 字节,如果您想将其绘制为方形图,则单边的像素数将为 sqrt(3e9/50)=7746 像素。我怀疑你有一个显示器可以一次显示这个。

编辑:

下面的修改版本现在使用 set print 数据块并且比原始版本快得多(使用 plot ... every ... 的双循环)。我已经可以通过我的小数据示例看到速度的提高。祝你的庞大数据集好运;-)。 仅供参考和比较,旧版本在这里再次列出:

# create a new datablock with row,col,Real,Imag,Abs
# using plot ...with table     (pretty slow and inefficient)
set table $Data2
    set datafile separator '(,)'          # now, split your data at these characters
    myReal(i) = column(3*i-1)
    myImag(i) = column(3*i)
    myAbs(i)  = sqrt(myReal(i)**2 + myImag(i)**2)
    plot for [row=0:rowMax-1] for [col=1:colMax] $Data u (row):(col):(myReal(col)):(myImag(col)):(myAbs(col)) every ::row::row w table
    set datafile separator whitespace     # set separator back to whitespace
unset table

代码:(使用set print修改)

### plotting complex numbers
reset session

$Data <<EOD
(0.1,0.1)   (0.2,1.2)   (0.3,2.3)   (0.4,3.4)   (0.5,4.5)
(1.1,0.1)   (1.2,1.2)   (1.3,2.3)   (1.4,3.4)   (1.5,4.5)
(2.1,0.1)   (2.2,1.2)   (2.3,2.3)   (2.4,3.4)   (2.5,4.5)
(3.1,0.1)   (3.2,1.2)   (3.3,2.3)   (3.4,3.4)   (3.5,4.5)
(4.1,0.1)   (4.2,1.2)   (4.3,2.3)   (4.4,3.4)   (4.5,4.5)
(5.1,0.1)   (5.2,1.2)   (5.3,2.3)   (5.4,3.4)   (5.5,4.5)
(6.1,0.1)   (6.2,1.2)   (6.3,2.3)   (6.4,3.4)   (6.5,4.5)
(7.1,0.1)   (7.2,1.2)   (7.3,2.3)   (7.4,3.4)   (7.5,4.5)
EOD

stats $Data u 0 nooutput   # get number of columns and rows, separator is whitespace
colMax = STATS_columns
rowMax = STATS_records

# create a new datablock with row,col,Real,Imag,Abs
# using print to datablock
set print $Data2
    myCmplx(row,col) = word($Data[row+1],col)
    myReal(row,col) = (s=myCmplx(row,col),s[2:strstrt(s,',')-1])
    myImag(row,col) = (s=myCmplx(row,col),s[strstrt(s,',')+1:strlen(s)-1])
    myAbs(row,col)  = sqrt(myReal(row,col)**2 + myImag(row,col)**2)
    do for [row=0:rowMax-1] {
        do for [col=1:colMax] {
            print sprintf("%d %d %s %s %g",row-1,col,myReal(row,col),myImag(row,col),myAbs(row,col))
        }
    }
set print

set key box opaque

set multiplot layout 2,2
    plot $Data2 u 1:2:3 w image ti "Real part"
    plot $Data2 u 1:2:4 w image ti "Imaginary part"
    set origin 0.25,0
    plot $Data2 u 1:2:5 w image ti "Absolute value"
unset multiplot
### end of code

结果: