Search code examples
gnuplot

Is it possible to read in the data from a file to a gnuplot array?


Is there a way to load data from a file into a Gnuplot array? I am working with a program that provides the data and calls gnuplot internally to create a plot. Now I am trying to set the xrange that the upper limit is set where the data in the second column finally approaches zero. I have googled a lot and tried different methods. Unfortunately without success. The most promising but still not working approach seems to me to import the data and store it in an array. An excerpt from the code is provied below:

stats '<datafile>' using 1:($2/1000.) nooutput
array myarray[STATS_records]
do for [i=STATS_records:0:-1] {
  stats '<datafile>' using 1:($2/1000.) index i nooutput
  myarray[i] = STATS_min_y
}

The stats expression in the loop causes an error because no values are found. Thank you in advance for your suggestions or alternative solutions.


Solution

  • From your current question title and code snippet I assume you want to read data reversed into an array.

    Now I am trying to set the xrange that the upper limit is set where the data in the second column finally approaches zero.

    This sentence makes me think that maybe there is more behind which you don't show and which can maybe solved also without arrays. Maybe we are running into a xy-problem?

    The following script reads a column of a data file reversed into an array.

    Data: SO76218289.dat

     1    1.0
     2    2.1
     3    3.2
     4    4.3
     5    5.4
     6    6.5
     7    7.6
     8    8.7
     9    9.8
    10   10.9
    

    Script: (requires gnuplot>=5.2.0)

    ### read data from file reversed into array
    reset session
    
    FILE = "SO76218289.dat"
    
    stats FILE u 0 nooutput     # get number of rows
    rowCount = STATS_records
    array A[rowCount]           # set array size
    
    stats FILE u (A[int(rowCount-$0)] = $2) nooutput
    
    print A
    ### end of script
    

    Result:

    [10.9,9.8,8.7,7.6,6.5,5.4,4.3,3.2,2.1,1.0]
    

    Addition:

    Actually, it was a bit of a xy-problem: You asked for putting data into an array, but the actual goal was to limit the xrange to the range where y>0. This can be done simpler. Using the ternary operator (check help ternary) the x-values will be set to NaN if y<0. A value of NaN will not be plotted and considered for the x-autorange. Hence, in the example below the x-range is automatically limited to [3:7]. If the y-values might get below zero within the limited range and you nevertheless want lines drawn down to zero, the script needs to be adapted.

    Script:

    ### limit xrange to data y>0
    reset session
    
    $Data <<EOD
     1   -1.0
     2   -0.5
     3    0.5
     4    3.0
     5    2.0
     6    1.0
     7    0.5 
     8   -0.1
     9   -0.5
    10   -1.0
    EOD
    
    plot $Data u ($2>0 ? $1 : NaN):2 w lp pt 7 lc "red" notitle
    ### end of script
    

    Result:

    enter image description here

    Addition 2:

    Just to illustrate, you can also limit the data to an x-range where y>0 and including the first sequence of N values y<=0. This requires stats and a more difficult statement to understand using ternary operators and serial evaluation (check help operators binary). The final limitation will be done by every (check help every).

    Script:

    ### limit x-range to values with y>0 and N values y<=0
    reset session
    
    $Data <<EOD
     1   -1.0
     2   -0.5
     3    0.5
     4    3.0
     5    2.0
     6    1.0
     7    0.5 
     8    0.0
     9    0.0
    10    0.0
    11   -1.0
    12   -2.0
    EOD
    
    N  = 3             # max. number of y-values <0 in a sequence
    n0 = n1 = NaN
    c  = 0
    stats $Data u ($2>0 && n0!=n0 ? n0=$0 : $2<=0 && n0==n0 && n1!=n1 ? c=c+1 : c=0, c==N ? n1=$0 : 0) nooutput
    print n0,n1
    
    plot $Data u 1:2 every ::n0::n1 w lp pt 7 lc "red"
    ### end of script
    

    Some explanations:

    • first n0 and n1 are initialized to NaN and c=0.

    What is the meaning of:

    ($2>0 && n0!=n0 ? n0=$0 : $2<=0 && n0==n0 && n1!=n1 ? c=c+1 : c=0, c==N ? n1=$0 : 0)
    
    • if y>0 and n0 is NaN (see gnuplot: How to compare to NaN?) then set n0 to the current line index $0 which will be the first time y>0.
    • else if y<=0 and n0 is not NaN and n1 is NaN, increase the counter c by 1, else reset the counter to c=0.
    • if c is equal to N set n1 to the current line index $0.

    In summary: n0 contains the line index with the first time y>0 and n1 contains the line index when y was N-times <=0 (but only after n0 was set to some value). When you plot the data, you simply limit it via every ::n0::n1.

    The example will limit the x-range to [3:10] because the last N=3 y-values are y<=0.

    Result:

    enter image description here