Search code examples
gnuplotoctave

Directly use gnuplot from octave?


I generally find Octave to be the easiest-to-use tool for data evaluation, but cumbersome for data-visualization.

On the other hand I find Gnuplot to be the easiest-to-use tool for data-visualization because of

  • its very focused nature,
  • its strong library of demo examples, and
  • its comprehensive interactive help features.

These advantages are sabotaged by putting any language-wrapper between gnuplot and the user, but pure gnuplot (intentionally) lacks capabilities for doing any non-trivial preprocessing (e.g. numerical calculus).

Octave can use gnuplot as a backend, but in order to preserve the advantages I would prefer directly using gnuplot commands, say:

dx = 0.1;
x = 0:dx:2*pi;
y = sin(x);
y2 = cumsum(y)*dx;
outputFileName = "sin.pdf"

# Contains mockup syntax:
gp set term pdfcairo size 30cm,20cm noenhanced
gp set output '${outputFileName}'
gp plot ${x,y} using 1:2 with lines title "The sin(x) function",         \
gp      ${x,y2} using 1:2 with lines title "Integrated sin(x) function", \
gp      cos(x) title "The cos(x) function"
gprun

Writing a basic implementation of this "gp" utility would be easy enough, though variable interpolation would have to be replaced by explicit gp(["set output '" outputFileName "'"]) at the cost of readability. Not so easy however would be the creation of the ${x,y} table file.

Is there any straight-forward way to obtain similar functionality?


Ironically, some much older versions of octave (up until around 2005, 2006) had this capability (gset, graw, ...) but had them demoted to an internal implementation detail. In some older discussions I find references to e.g. __graw__, which also doesn't exist anymore, and some outdated documentation sites mention gplot, which still exists but with an entirely different purpose.


Solution

  • Honestly, I think you're overthinking it. Creating a temporary script and running it is often even more straightforward and portable than cumbersome libraries (e.g. see my previous similar answer here for an sqlite example )

    Using that approach below works well for me, is very readable in my opinion, and does not result in unnecessary files (at least not visibly on your workspace).

    dx = 0.1;
    x  = 0 : dx : 2 * pi;
    y  = sin( x );
    y2 = cumsum( y ) * dx;
    
    outputFileName = "sin.pdf"
    
    % Create Gnuplot Script 
    GPScriptName = tempname();   gp = fopen( GPScriptName, 'w');
    
    fdisp( gp, 'set term pdfcairo size 30cm,20cm noenhanced'                         );
    fdisp( gp, sprintf( 'set output "%s"', outputFileName )                          );
    fdisp( gp, 'plot "-" using 1:2 with lines title "The sin(x) function", \'        );
    fdisp( gp, '     "-" using 1:2 with lines title "Integrated sin(x) function", \' );
    fdisp( gp, '     cos(x)                   title "The cos(x) function"'           );
    fdisp( gp, [ x(:), y(:)  ]                                                       );
    fdisp( gp, 'e'                                                                   );
    fdisp( gp, [ x(:), y2(:) ]                                                       );
    fdisp( gp, 'e'                                                                   );
    fdisp( gp, ';'                                                                   );
    
    fclose( gp )
    
    % Run script with Gnuplot
    Cmd = sprintf( 'gnuplot --persist "%s"',  GPScriptName );
    [Status, Output] = system( Cmd );
    

    I used 'inline' data here, so that I could dump it straight in the script (as suggested here), but if you prefer, you could use the same logic to fdisp them to a separate temporary Data file, and make your Gnuplot script read from that; also you may or may not handle status errors and delete the temp files after the operation (like I did in the linked sqlite example) if you're worried about producing lots of temporary files and taking up space ... but in practice it typically doesn't matter.

    I think this approach is fine and gives you more control ... but, if you insist, it should be trivial to wrap those fdisp calls into a gp function, and the system call into a gprun function ...