PJSR: Example of graph generation with the integrated gnuplot utility

Juan Conejero

PixInsight Staff
Staff member
In a recent post on the Release Information forum board, I have described the new approximating surface splines implemented in the StarAlignment tool. To generate the 3-D graphs included in that post, I wrote a small script that automates execution of the gnuplot utility. I think this script can be interesting as an example for PI/PJSR developers, since it covers several important topics:

- Running external processes with the ExternalProcess core JavaScript object.

- Generation of a plain text file with tabular data and a script to control an external process.

- Using the integrated gnuplot utility, which is part of the standard PixInsight distribution on all platforms.

- Using the new SurfaceSpline core JavaScript object.

To test the script with the same data I used in my post, you can load this image:


and just run the script from the Script Editor. As you see, thanks to the integrated gnuplot utility PixInsight has really impressive graph generation capabilities.

JavaScript:
/*
* A script for testing the SurfaceSpline PJSR object.
*
* Copyright (C) 2013 Pleiades Astrophoto. All Rights Reserved.
* Written by Juan Conejero (PTeam)
*/

#include <pjsr/ProcessExitStatus.jsh>

/*
* Routine to execute an external process, including command line arguments.
*
* program              Executable file name. Can be followed by a series of
*                      command line arguments separated by spaces.
*
* maxRunningTimeSec    Maximum execution time in seconds (default=10)
*
* This routine shows a spin status indicator if the process takes more than
* 0.25 seconds to complete.
*/
function run( program, maxRunningTimeSec )
{
   if ( maxRunningTimeSec === undefined )
      maxRunningTimeSec = 10;
   var P = new ExternalProcess( program );
   if ( P.waitForStarted() )
   {
      processEvents();
      var n = 0;
      var nmax = Math.round( maxRunningTimeSec*1000/250 );
      for ( ; n < nmax && !P.waitForFinished( 250 ); ++n )
      {
         console.write( "<end>\b" + "-/|\\".charAt( n%4 ) );
         processEvents();
      }
      if ( n > 0 )
         console.writeln( "<end>\b" );
   }
   if ( P.exitStatus == ProcessExitStatus_Crash || P.exitCode != 0 )
   {
      var e = P.stderr;
      throw new ParseError( "Process failed:\n" + program +
                            ((e.length > 0) ? "\n" + e : ""), tokens, index );
   }
}

/*
* A SurfaceSpline test routine with SVG 3-D graphics generation using the
* integrated gnuplot utility.
*/
function Spline3DTest( image, gridStep )
{
   if ( gridStep === undefined )
      gridStep = 8;

   var xGridSize = Math.trunc( image.width/gridStep );
   var yGridSize = Math.trunc( image.height/gridStep );
   var N = xGridSize*yGridSize;
   if ( N < 9 )
      throw new Error( "I won't work with less than 9 data points." );
   if ( N > 2000 )
      throw new Error( "I won't work with more than 2000 data points." );

   /*
    * Interpolate data points
    */
   var X = new Vector( N );
   var Y = new Vector( N );
   var Z = new Vector( N );
   for ( var x = 0, n = 0; x < xGridSize; ++x )
   {
      for ( var y = 0; y < yGridSize; ++y, ++n )
      {
         var xn = x*gridStep;
         var yn = y*gridStep;
         X.at( n, xn );
         Y.at( n, yn );
         Z.at( n, image.interpolate( xn, yn ) );
      }
   }

   /*
    * Build an interpolating 2-D surface spline.
    */
   var S0 = new SurfaceSpline;
   S0.initialize( X, Y, Z );

   /*
    * Build some approximating 2-D surface splines.
    */
   var S1 = new SurfaceSpline;
   S1.smoothing = 0.05;
   S1.initialize( X, Y, Z );
   var S2 = new SurfaceSpline;
   S2.smoothing = 0.15;
   S2.initialize( X, Y, Z );
   var S3 = new SurfaceSpline;
   S3.smoothing = 0.35;
   S3.initialize( X, Y, Z );

   var tmpDir = File.systemTempDirectory;

   var datFilepath = tmpDir + "/spline.dat";
   var gnuFilePath = tmpDir + "/spline.gnu";
   var svgFilePath = [
      tmpDir + "/spline.svg",
      tmpDir + "/spline-smoothing-0.05.svg",
      tmpDir + "/spline-smoothing-0.15.svg",
      tmpDir + "/spline-smoothing-0.35.svg"
   ];

   /*
    * Generate the data table
    */
   var f = new File;
   f.createForWriting( datFilepath );
   for ( var i = 0; i < X.length; ++i )
      f.outTextLn( format( "%5d %5d %.4f %.4f %.4f %.4f %.4f",
                           X.at( i ), Y.at( i ), Z.at( i ),
                           S0.evaluate( X.at( i ), Y.at( i ) ),
                           S1.evaluate( X.at( i ), Y.at( i ) ),
                           S2.evaluate( X.at( i ), Y.at( i ) ),
                           S3.evaluate( X.at( i ), Y.at( i ) ) ) );
   f.close();

   /*
    * Generate the gnuplot script
    */
   f.createForWriting( gnuFilePath );
   f.outTextLn( "set terminal svg size 800,600 enhanced font 'helvetica,12'" );
   f.outTextLn( "set samples " + xGridSize.toString() + ", " + yGridSize.toString() );
   f.outTextLn( "set isosamples " + xGridSize.toString() + ", " + yGridSize.toString() );
   f.outTextLn( "set ticslevel 0" );
   f.outTextLn( "set dgrid3d " + xGridSize.toString() + ", " + yGridSize.toString() );
   f.outTextLn( "set hidden3d" );
   f.outTextLn( "set xrange [ 0 : " + image.width.toString() + " ]" );
   f.outTextLn( "set yrange [ 0 : " + image.height.toString() + " ]" );
   f.outTextLn( "set zrange [ 0.0 : 1.0 ]" );
   f.outTextLn( "set ytics offset 1" );
   f.outTextLn( "unset key" );
   f.outTextLn( "set title 'Interpolating 2-D Surface Spline' font 'helvetica,16'" );
   f.outTextLn( "set output '" + svgFilePath[0] + "'" );
   f.outTextLn( "splot '" + datFilepath + "' using 1:2:4 with lines lc rgbcolor '#E00000'" );
   f.outTextLn( "set title 'Approximating 2-D Surface Spline, s = 0.05' font 'helvetica,16'" );
   f.outTextLn( "set output '" + svgFilePath[1] + "'" );
   f.outTextLn( "splot '" + datFilepath + "' using 1:2:5 with lines lc rgbcolor '#E00000'" );
   f.outTextLn( "set title 'Approximating 2-D Surface Spline, s = 0.15' font 'helvetica,16'" );
   f.outTextLn( "set output '" + svgFilePath[2] + "'" );
   f.outTextLn( "splot '" + datFilepath + "' using 1:2:6 with lines lc rgbcolor '#E00000'" );
   f.outTextLn( "set title 'Approximating 2-D Surface Spline, s = 0.35' font 'helvetica,16'" );
   f.outTextLn( "set output '" + svgFilePath[3] + "'" );
   f.outTextLn( "splot '" + datFilepath + "' using 1:2:7 with lines lc rgbcolor '#E00000'" );
   f.close();

   /*
    * Run gnuplot
    */
   run( "\"" + getEnvironmentVariable( "PXI_BINDIR" ) + "/gnuplot\" \"" + gnuFilePath + "\"" );

   /*
    * Load the images
    */
   for ( var i = 0; i < svgFilePath.length; ++i )
      ImageWindow.open( svgFilePath[i] )[0].show();
}

var view = ImageWindow.activeWindow.currentView;
if ( view.isNull )
   throw new Error( "No active image." );

Spline3DTest( view.image, 6 );
 
Back
Top