Newer
Older
//**************************************************************************************************
//* FRIDA: fast reliable interactive data analysis
//* (C) Joachim Wuttke 1990-, v2(C++) 2001-
//* http://apps.jcns.fz-juelich.de/frida
//**************************************************************************************************
//! \brief Collection NPlot of plot frames CPlot.
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <cstring>
#include "../trivia/file_ops.hpp"
using std::string;
using std::vector;
using std::cout;
static const int mLin = 80; // max num of chars in PostScript line
//! Constructor for plot window: setup for gnuplot and postscript.
CPlot::CPlot( int _iPlot, bool _logx, bool _logy ) :
iPlot( _iPlot ), X( "x", _logx ), Y( "y", _logy ),
maxpoints(20000), with_errors(true), equipoints(49), refine(true)
// Create a named pipe (FIFO) that will transmit our commands to Gnuplot.
string fn_fifo = string("/tmp/gnuplot-") + getenv( "LOGNAME" );
if (mkfifo( fn_fifo.c_str(), 0666 ))
throw "SYSTEM ERROR cannot make fifo "+fn_fifo+": will not be able to print";
// Check that Gnuplot supports X11.
string out = triv::system_read( "gnuplot -e 'help X11' 2>&1 < /dev/null" );
if ( out.substr(0,5)=="Sorry" || out.length()<80 ) {
cout << "Gnuplot seems not to support X11\n";
triv::system( "gnuplot -title "+S(iPlot)+" -noraise < "+fn_fifo+"&" );
// (we use 'open' instead of 'fopen' or 'ofstream', because we need non-blocking mode).
if ( ( gp_fifo = open( fn_fifo.c_str(), O_WRONLY ) )==-1 )
throw "SYSTEM ERROR: cannot open fifo "+fn_fifo+" ("+strerror(errno)+")";
fcntl( gp_fifo, F_SETFL, O_NONBLOCK );
//! Clear plot frame and buffer.
void CPlot::clear_frame()
// reset buffers for postscript output
string cmd;
ps_accu.clear();
ps_accu.push_back( "\n%% output created by frida2\n");
ps_snum = 0;
ps_pnum = 0;
ps_cnum = 0;
ps_Doc.clear();
//! Change one setup parameter per command.
void CPlot::set_aux( const string& cmd )
if ( cmd=="gxl" ) {
X.set_log( !X.logflag );
printf( "set x %s\n", X.logflag ? "log" : "lin" ); }
X.set_log( true );
X.set_log( false );
Y.set_log( !Y.logflag );
printf( "set y %s\n", Y.logflag ? "log" : "lin" ); }
Y.set_log( true );
Y.set_log( false );
X.force = !X.force;
printf( "force x %s\n", X.force ? "on" : "off" ); }
else if ( cmd=="gxf+" )
X.force = true;
X.force = false;
else if ( cmd=="gyf" ) {
Y.force = !Y.force;
printf( "force y %s\n", Y.force ? "on" : "off" ); }
else if ( cmd=="gyf+" )
Y.force = true;
else if ( cmd=="ge" )
with_errors = !with_errors;
else if ( cmd=="ge+" )
with_errors = true;
else if ( cmd=="ge-" )
with_errors = false;
//! Plot coordinate frame (axes, ticks, labels).
void CPlot::plot_frame( const string& xlabel, const string& ylabel )
if (X.logflag) whichlog += "x";
if (Y.logflag) whichlog += "y";
char outlin[ mLin ];
snprintf( outlin, mLin, "\n%i %g %g xSetCoord\n",
snprintf( outlin, mLin, "%i %g %g ySetCoord\n",
snprintf( outlin, mLin, "%% %i %g %g %i zSetCoord\n\n",
int ntpt;
double ticklim[2];
vector<double> Tacks;
if ( X.logflag && X.inf<= 0 )
throw "BUG: x log incompatible with limits " + X.str();
X.calc_ticks( Tacks, &ntpt, ticklim );
ps_ticktack( Tacks, ntpt, ticklim, &X);
snprintf( outlin, mLin-4, " {(%s", xlabel.c_str() );
ps_accu.push_back( " 0 10 0 0 0 90 "
"OneAxx Axx Tic Tac xNumL %% low x axis\n" );
ps_accu.push_back( " 0 10 0 10 0 270 "
"OneAxx Axx Tic Tac %% top x axis\n" );
ps_accu.push_back( " xCL\n" );
if ( Y.logflag && Y.inf<= 0 )
throw "BUG: y log incompatible with limits " + Y.str();
Y.calc_ticks( Tacks, &ntpt, ticklim );
ps_ticktack( Tacks, ntpt, ticklim, &Y);
snprintf( outlin, mLin-4, " {(%s", ylabel.c_str() );
ps_accu.push_back( " 0 10 0 0 90 0 "
"OneAxx Axx Tic Tac yNumL %% left y axis\n" );
ps_accu.push_back( " 0 10 10 0 90 180 "
"OneAxx Axx Tic Tac %% right y axis\n" );
ps_accu.push_back( " yCL\n" );
ps_accu.push_back( "} def\n" );
ps_accu.push_back( "\n%% modeDD\nplotbefore\n" );
void CPlot::add_spec( bool as_line, bool new_style, int style_no,
const vector<double>& xp,
const vector<double>& yp, const vector<double>& dyp,
const vector<string>& z,
const string& xco,
const string& yco,
const string& info
static const int mColor = 6;
static int color[mColor] = { 0x880000, 0x008800, 0x000088,
0x006666, 0x660066, 0x666600 };
throw S("invalid call to CPLot::addSpec: no data points");
throw S("invalid call to CPLot::addSpec: x.size<>y.size");
// Prepare for live display, to be shown by showSpecs():
string gp_fnam = str( format( "/tmp/%s-%i-%03i.gnu" )
if (gp_fnames!="") gp_fnames += ", ";
gp_fnames += string("\"") + gp_fnam + "\" notitle";
gp_fnames += str( format( " with lines lt 1 lc rgb \"#%6x\"" )
if (!(gp_fd = fopen(gp_fnam.c_str(), "w")))
throw "cannot save gnuplot data to " + gp_fnam;
try {
for (int i=0; i<np; i++){
if( std::isinf(xp[i]) || std::isinf(yp[i]) )
throw "Data point number " + S(i) + " is invalid: x=" +
S(xp[i]) + ", y=" + S(yp[i]);
if( xp[i]<X.inf || xp[i]>X.sup )
throw "CPlot::addSpec: x["+S(i)+"]="+S(xp[i])+" out of range";
if( yp[i]<Y.inf || yp[i]>Y.sup )
throw "CPlot::addSpec: y["+S(i)+"]="+S(yp[i])+" out of range";
if( with_errors && dyp.size() )
fprintf(gp_fd, "%16.8g %16.8g %16.8g\n", xp[i], yp[i], dyp[i] );
else
fprintf(gp_fd, "%16.8g %16.8g\n", xp[i], yp[i]);
nout++;
}
} catch ( string &s ) {
fclose(gp_fd);
throw s;
} catch ( ... ) {
fclose(gp_fd);
throw "BUG: unexpected exception type";
char outlin[ mLin ];
if ( new_style ) {
snprintf( outlin, mLin, "\n%3u [", ++ps_snum );
ps_accu.push_back( outlin );
snprintf( outlin, mLin, " %s", z[i].c_str() );
ps_accu.push_back( outlin );
}
snprintf( outlin, mLin, " ] zValues\n" );
ps_accu.push_back( outlin );
if ( as_line )
snprintf( outlin, mLin, "%2i cstyle", style_no );
snprintf( outlin, mLin, "%2i pstyle", style_no );
ps_accu.push_back( outlin );
snprintf( outlin, mLin-2, " %% (%s -> %s)", xco.c_str(), yco.c_str() );
strncat( outlin, "\n", mLin );
} else {
ps_accu.push_back( "\n" );
"%6.3f %6.3f %6.3f t%c %% %13.7g wx %13.7g wy\n",
X.pc(xp[i]), Y.pc(yp[i]),
dyp.size() ? Y.pcerr(yp[i],dyp[i]) : 0,
i==0 ? 'i' : i==np-1 ? 'f' : ' ',
xp[i], yp[i] );
ps_accu.push_back( outlin );
}
void CPlot::show_specs()
gp_write( "plot " +
str( format( "[%12.8g:%12.8g] [%12.8g:%12.8g] " )
% X.inf % X.sup % Y.inf % Y.sup ) +
gp_fnames );
//! Add documentation line to postscript output.
void CPlot::doc_TxLine( const string& line )
ps_Doc.push_back( " {("+line+")} TxLine" );
}
//! Add documentation line explaining a plot symbol to postscript output.
void CPlot::doc_PtTxLine( const string& line, int num )
{
ps_Doc.push_back( " " + S(num) + " {("+line+")} PtTxLine" );
}
//! Add documentation line explaining a curve style to postscript output.
void CPlot::doc_CvTxLine( const string& line, int num )
{
ps_Doc.push_back( " " + S(num) + " {("+line+")} CvTxLine" );
//! Write buffered plot to postscript file.
void CPlot::write_postscript(
const string& ps_outdir, const string& ps_head, const string& ps_dict )
// construct output file name:
FILE *pssav;
string cmd, outf;
outf = triv::wordexp_unique(
ps_outdir + str( format( "l%i" ) % ++ps_fnum ) + "." + ( ps_dict=="" ? "psa" : "ps" ) );
// copy headers to output file:
cmd = string("cat ") +
ps_dict + " " + // ps_dict may be ""
ps_head + " > " +
outf + "\n";
// append specific output to output file:
if ( !(pssav = fopen( outf.c_str(), "a+" )) )
throw "cannot append contents to file " + outf;

Wuttke, Joachim
committed
// fprintf does not work here because output line may contain "%"
}
// additional output (do not append this to ps_accu to allow
// further incrementation of ps_accu):
fprintf( pssav, "\n{ black 0 -4 13 1.65 NewList\n" );
for ( string lin: ps_Doc )
fprintf( pssav, "} oooinfo 1 eq { exec } { pop } ifelse\n" );
fprintf( pssav,
"\n{(%s)} /filename exch def 10 -2.8 18 showfilename\n\n"
" EndFrame\n", outf.c_str() );
// output completed:
fclose(pssav);
//! Info line to characterize this plot window.
{
string ret;
ret = "x: " + X.info();
return ret;
}
//! Send one line to gnuplot fifo.
void CPlot::gp_write( const string& in )
// cout << "monitor gnuplot driver: '" << out << "'\n";
if( write( gp_fifo, out.c_str(), out.size() ) <= 0 )
//! Format ticks and tacks for postscript file.
void CPlot::ps_ticktack( const vector<double>& Tacks, int ntpt,
const double *ticklim, const CAxis *A )
char outlin[ mLin ];
if (ntack > 0 ) {
ps_accu.push_back( " [\n" );
if (A->logflag && ( Tacks[0]<1e-3 || Tacks[ntack-1]>1e3 )) {
for (i=0; i<ntack; i++) {
snprintf( outlin, mLin,
" %9.6f {(10)(%i)sp()} %%{(%g)}\n",
A->pc(Tacks[i]), (int)(log10(Tacks[i])), (float) Tacks[i]);
ps_accu.push_back( outlin );
}
} else {
for (i=0; i<ntack; i++) {
snprintf( outlin, mLin, " %9.6f {(%g)}\n",
A->pc(Tacks[i]), (float) Tacks[i]);
ps_accu.push_back( outlin );
}
snprintf( outlin, mLin, " %g %g %i %i SetTicVec%s\n",