theozh
theozh

Reputation: 25843

How to sort a datablock in gnuplot?

For sorting a file by column, Linux users have the utility sort. Windows users have to install, e.g. CoreUtils from GnuWin to get the same (or similar) functionality.

So, the minimal code for sorting the file first by column1 and then by column2, and then plotting the file would be something like this:

plot '<sort -k 1,2 "myFile.dat"' u 1:2

Now, however, I have a datablock $Data:

$Data <<EOD
1    6
4    8
3    7
2    5
1    4
2    3
EOD

The commands I tried so far which all end up in error messages:

plot '<sort -k 1,2' $Data u 1:2

#--> Bad data on line 1 of file <sort -k 1,2

plot '<sort -k 1,2  $Data' u 1:2
plot '<sort -k 1,2 <$Data' u 1:2 

#--> warning: Skipping data file with no valid points
#--> x range is invalid

plot '<sort -k 1,2 '<$Data u 1:2

#--> Column number or datablock line expected

I don't want to write the datablock to a file first and read it again from file. I currently don't see how I would redirect the content of $Data to the standard input of sort. Is there any solution for Windows as well as for Linux?

Update:

When using @Ethan's suggested code, I get the following result. Mind the lines 2 5 and 2 3 which I expected (and Ethan has it) the other way round.

# Curve 0 of 1, 6 points
# Curve title: "$Data_1 using 1:2:1"
# x y type
 1  4  i
 1  6  i
 2  5  i
 2  3  i
 3  7  i
 4  8  i

Any idea why this is? I'm running gnuplot 5.4.1 on Win10.

Upvotes: 3

Views: 426

Answers (3)

Ethan
Ethan

Reputation: 15118

The syntax for sending $Data to stdin of the sort utility is set print "| sort"; print $Data. But that won't do what you want. Instead let's perform the double sort inside gnuplot.

$Data <<EOD
1    6
4    8
3    7
2    5
1    4
2    3
EOD

set table $Data_1
plot $Data using 1:2:2 smooth zsort with points
set table $Data_2
plot $Data_1 using 1:2:1 smooth zsort with points
unset table
print $Data_2

# Curve 0 of 1, 6 points
# Curve title: "$Data_1 using 1:2:1"
# x y type
 1  4  i
 1  6  i
 2  3  i
 2  5  i
 3  7  i
 4  8  i

Upvotes: 1

Ethan
Ethan

Reputation: 15118

I am going to back up and suggest that you reconsider your initial restriction against using a temporary file. The most straightforward solution is this:

   set print "| sort -k 1,2 > sorted.dat"
   print $Data
   unset print
   plot 'sorted.dat'

If you explain why you don't want to use a temp file, maybe there is an answer to that question independent of the sorting issue. If the concern is the name of the temp file, then perhaps something like this:

  tempfile = system("mktemp")
  set print "| sort -k 1,2 > ".tempfile
  print $Data
  unset print
  plot tempfile with points

Upvotes: 1

theozh
theozh

Reputation: 25843

It wouldn't be gnuplot if there wasn't a workaround. Well, a bit cumbersome but it seems to work. Apparently, smooth zsort sorts each subblock separately. Hence, after the first sort you "simply" need to split your data into sub-blocks whenever the value in the first column changes.

  1. sort by the first column
  2. insert an empty line before the value in the first column changes
  3. sort by the second column
  4. plot it into a table to remove empty lines again

Code: (edit: with graphical representation it's easier to illustrate the undesired behaviour of zsort (under Windows only))

### sorting datablock, "bug": Windows zsort does not preserve order
reset session

# create some random test data 
set print $Data
    do for [i=1:100] {
        print sprintf("%g %g", int(rand(0)*10), int(rand(0)*10))
    }
set print

# order not preserving (only under Windows)
set table $Data1
    plot $Data  u 1:2:2 smooth zsort
set table $Data2
    plot $Data1  u 1:2:1 smooth zsort
unset table

# order preserving (even under Windows, but cumbersome)
set table $Data3
    plot $Data  u 1:2:1 smooth zsort
unset table
set print $Data4
    do for [i=1:|$Data3|] {
        print $Data3[i]
        if (i<|$Data3|) { if (word($Data3[i],1) ne word($Data3[i+1],1)) { print "" } }
    }
set print
set table $Data5
    plot $Data4 u 1:2:2 smooth zsort
set table $Data6
    plot $Data5 u 1:2 w table
unset table

set key out
set rmargin 20
set multiplot layout 3,1
    plot $Data  w lp pt 7 lc "black"     ti "Random"
    plot $Data2 w lp pt 7 lc "red"       ti "zsort"
    plot $Data6 w lp pt 7 lc "web-green" ti "Workaround"
unset multiplot
### end of code

Result:

enter image description here

Upvotes: 1

Related Questions