//**************************************************************************// //* FRIDA: fast reliable interactive data analysis *// //* dualplot.cpp: different mechanisms for screen and paper output *// //* (C) Joachim Wuttke 1990-, v2(C++) 2001- *// //* http://frida.sourceforge.net *// //**************************************************************************// #include <stdlib.h> #include <iostream> #include <math.h> #include "mystd.h" #include "range.h" #include "grid.h" #include "plotaux.h" #include "coord.h" #include "readln.h" #include "asi.h" #include "dualplot.h" // local set-up: #define GNUP // Gnuplot // #define PLUT // GNU plotutils (too low level; buffering problem) // #define PLPL // PlPlot (only Tek works, in X11 clipping problem) #define WUPS // my own postscript driver // local implementation: #ifdef GNUP #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #endif #ifdef PLUT #include <plotter.h> #endif #ifdef PLPL #include <plplot/plConfig.h> #include <plplot/plplotP.h> #endif #ifdef WUPS #define WUPS_GBUF "/tmp/rda.ps" #endif #define PLOTDTYP double #define PSMAX 10 #define LINSIZ 80 namespace NPlot { CAxis X, Y; uint maxpoints = 12000; #ifdef PLUT Plotter *plut; #endif #ifdef GNUP int gp_fifo; void gp_write(string); int gp_fno; string gp_fnames; #endif #ifdef WUPS uint ps_fnum; // file uint ps_snum; // scan uint ps_pnum; // scan with pstyle uint ps_cnum; // scan with cstyle void ps_ticktack(uint ntack, double *tack, int ntpt, double *ticklim, CAxis *A); vector<string> ps_Doc; vector<string> ps_accu; // future output is accumulated here char outlin[ LINSIZ ]; #endif }; void CAxis::Ask(const string& quest) { string def, in, in1, in2; CRange newR; while(1) { def = (log ? "log " : "") + R.str(); // out = quest + " [" + def + "] ?"; so gehts leider(?) nicht in = sask(quest.c_str(), def); if (in==def) return; mystd::string_extract_word(in, &in1, &in2); if (in1=="l") { SetLog(!log); in = in2; } else if (in1=="i") { SetLog(0); in = in2; } else if (in1=="g") { SetLog(1); in = in2; } if (in!="") { newR = CRange(in); if (!newR.valid) continue; if (log && newR.inf<=0) { printf("! log scale requires range above 0\n"); continue; } R = newR; return; } } } void CAxis::SetLog(const uint val) { if (log!=val) { log = val; CRange RX = AlternateR; AlternateR = R; R = RX; } } #ifdef WUPS double CAxis::pc(double v) // value -> plot-coordinate { return PSMAX * R.relval(log, v); } #endif void NPlot::Open(void) { #ifdef GNUP // Start gnuplot. Use input redirection so that gnuplot receives // commands from a gp_fifo which is created here. string fn_fifo = string("/tmp/gnuplot-") + getenv( "LOGNAME" ); system( ("rm -f "+fn_fifo).c_str() ); if (mkfifo( fn_fifo.c_str(), 0666 )) { printf("SEVERE SYSTEM ERROR cannot make fifo %s" " - will not be able to print\n", fn_fifo.c_str() ); return; } system( ("gnuplot -noraise < " + fn_fifo + " &").c_str() ); // we use open instead of fopen or ofstream, // because we need non-blocking mode. if (!(gp_fifo = open(fn_fifo.c_str(), O_WRONLY))) { printf("SEVERE SYSTEM ERROR cannot open gp_fifo" " - will not be able to print\n"); return; } fcntl(gp_fifo,F_SETFL,O_NONBLOCK); // gp_write(string("plot 1 2 3")); // test gp_write(string("set terminal x11")); #endif #ifdef PLUT // die folgenden Initialisierungen scheinen keinen Effekt zu haben: Plotter::parampl("VANISH_ON_DELETE", (void*)"no"); Plotter::parampl("DISPLAY", (void*)":0.0"); Plotter::parampl("USE_DOUBLE_BUFFERING", (void*)"no"); plut = new XPlotter(cin, cout, cerr); if (plut->openpl() < 0) { printf("SEVERE SYSTEM ERROR " "cannot open plotutils::Plotter::plut" " - will not be able to print\n"); return; } plut->fspace(-.08, -.08, 1.04, 1.04); #endif #ifdef PLPL plsdev("xwin"); // plsdev("xterm"); // plsdev("tk"); plscol0(0,255,255,255); plscol0(1,0,0,0); plSetOpt("np", ""); // no pause between plots // plSetOpt("geometry", "600x400+340+5"); // plSetOpt("debug", ""); cout << "DEBUG P1\n"; plinit(); cout << "DEBUG P2\n"; // plfont(2); // pltext(); // back to Tektronix text window cout << "DEBUG P3\n"; #endif #ifdef WUPS ps_fnum=0; #endif } void NPlot::Close(void) { #ifdef PLPL cout << "DEBUG PEND\n"; plend(); #endif } void NPlot::Clear(void) { // cout << "DEBUG dp Clear beg\n"; #ifdef GNUP gp_fno = 0; gp_fnames = string(""); #endif #ifdef PLUT #endif #ifdef PLPL // new pl window: // plgra(); // go to Tektronix graph window pladv(0); plvpor(0.15, 0.85, 0.1, 0.9); #endif #ifdef WUPS // new wups file: 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(); #endif } void NPlot::Multiask(void) { maxpoints = iask("Max # points in plot", maxpoints); X.force = bask("Force x points into frame", X.force); Y.force = bask("Force y points into frame", Y.force); } void NPlot::Box() { #ifdef GNUP gp_write( "set nologscale" ); string whichlog=""; if (X.log) whichlog += "x"; if (Y.log) whichlog += "y"; if (whichlog!="") gp_write( "set logscale " + whichlog ); #endif #ifdef PLUT plut->flinewidth(0.001); plut->pencolorname("black"); plut->fbox(0., 0., 1., 1.); plut->fbox(0., 0., 1., 1.); plut->flushpl(); #endif #ifdef PLPL plwind(X.R.inf, X.R.sup, Y.R.inf, Y.R.sup); plcol0(1); plbox("bcnst", 0.0, 0, "bcnstv", 0.0, 0); // plbox("bcfghlnst", 0.0, 0, "bcghnstv", 0.0, 0); // draw labels: /* plcol0(1); // plmtex("b", 3.2, 0.5, 0.5, "Frequency"); // plmtex("t", 2.0, 0.5, 0.5, "Single Pole Low-Pass Filter"); plcol0(2); // plmtex("l", 5.0, 0.5, 0.5, "Amplitude (dB)"); */ #endif #ifdef WUPS // wups: snprintf(outlin, LINSIZ, "\n%d %f %f xSetCoord\n", X.log, X.R.inf, X.R.sup); ps_accu.push_back( outlin ); snprintf(outlin, LINSIZ, "%d %f %f ySetCoord\n", Y.log, Y.R.inf, Y.R.sup); ps_accu.push_back( outlin ); snprintf(outlin, LINSIZ, "%% %d %f %f %d zSetCoord\n\n", 0, 0., 0., 0); ps_accu.push_back( outlin ); int ntack, ntpt; double *tack, ticklim[2]; ps_accu.push_back( "\n/xPlotFrame {" ); if(plotaux::calc_ticks(X.log, X.R.inf, X.R.sup, &ntack, &tack, &ntpt, ticklim)) { printf("PROGRAM ERROR/ Ticks\n"); return; } ps_ticktack(ntack, tack, ntpt, ticklim, &X); free(tack); snprintf(outlin, LINSIZ, " {(%s)}\n", X.C.ps_str().c_str()); ps_accu.push_back( outlin ); ps_accu.push_back( " 0 10 0 0 0 90 " "OneAxx Axx Tic xTacL xNumL %% low x axis\n" ); ps_accu.push_back( " 0 10 0 10 0 270 " "OneAxx Axx Tic xTacH %% top x axis\n" ); ps_accu.push_back( " xCL\n" ); ps_accu.push_back( "} def\n" ); ps_accu.push_back( "\n/yPlotFrame {" ); if(plotaux::calc_ticks(Y.log, Y.R.inf, Y.R.sup, &ntack, &tack, &ntpt, ticklim)) { printf("PROGRAM ERROR/ Ticks\n"); return; } ps_ticktack(ntack, tack, ntpt, ticklim, &Y); free(tack); snprintf(outlin, LINSIZ, " {(%s)}\n", Y.C.ps_str().c_str()); ps_accu.push_back( outlin ); ps_accu.push_back( " 0 10 0 0 90 0 " "OneAxx Axx Tic yTacL yNumL %% left y axis\n" ); ps_accu.push_back( " 0 10 10 0 90 180 " "OneAxx Axx Tic yTacH % yNumH %% right yaxis\n" ); ps_accu.push_back( " yCL\n" ); ps_accu.push_back( "} def\n" ); ps_accu.push_back( "\n%% modeDD\nplotbefore\n" ); #endif } void NPlot::Line(const int lstyle, const CGrid x, const vector<double> y, const vector<double>* z, const string xco, const string yco) { PLOTDTYP *xp, *yp; uint np=0, nxl=0, nxh=0, nyl=0, nyh=0; uint n=x.size(); if (n!=y.size()) { printf("PROG ERR NPLot::Line x.size<>y.size\n"); return; } xp = (PLOTDTYP *) malloc(sizeof(PLOTDTYP)*n); yp = (PLOTDTYP *) malloc(sizeof(PLOTDTYP)*n); for (uint i=0; i<n; i++) { if(!X.force && !X.R.contained(x[i])) { if (x[i]<=X.R.inf) nxl++; if (x[i]>=X.R.sup) nxh++; continue; } if(!Y.force && !Y.R.contained(y[i])) { if (y[i]<=Y.R.inf) nyl++; if (y[i]>=Y.R.sup) nyh++; continue; } if(np==maxpoints && np<n) { Tekx(); printf("reached maxpoints at %g\n", x[i]); } xp[np] = x[i]; yp[np] = y[i]; np++; if(np>maxpoints) i += maxpoints; } if (np==0) { Tekx(); printf("no points in data range:\n" "of %d points are\n %d left and %d right of the x range," "\n %d below and %d above of the y range\n", n, nxl, nxh, nyl, nyh); return; } #ifdef GNUP // save to file: char gp_fnam[40]; sprintf( gp_fnam, "/tmp/%s-%03d.gnu", getenv("LOGNAME"), gp_fno++); if (gp_fnames!="") gp_fnames += ", "; gp_fnames += string("\"") + gp_fnam + "\"" + // string(" title \"") + xco + string (" -> ") // + yco + string ("\""); " notitle"; if (lstyle<0) gp_fnames += " with lines"; FILE *gp_fd; if (!(gp_fd = fopen(gp_fnam, "w"))) { printf( "cannot save gnuplot data to %s", gp_fnam ); return; } for (uint i=0; i<np; i++) fprintf(gp_fd, "%20.12g %20.12g\n", xp[i], yp[i]); fclose(gp_fd); // plot command: char aux[80]; sprintf(aux, "[%20.12g:%20.12g] [%20.12g:%20.12g] ", X.R.inf, X.R.sup, Y.R.inf, Y.R.sup); gp_write(string("plot ") + aux + gp_fnames); #endif #ifdef PLUT #endif #ifdef PLPL plcol0(9); plpoin(np, xp, yp, 1); #endif #ifdef WUPS snprintf( outlin, LINSIZ, "\n%3u [", ++ps_snum); ps_accu.push_back( outlin ); for (uint i=0; i<z->size(); i++){ snprintf( outlin, LINSIZ, " %12g", (*z)[i]); ps_accu.push_back( outlin ); } snprintf( outlin, LINSIZ, " ] zValues\n"); ps_accu.push_back( outlin ); if (lstyle>=0) snprintf( outlin, LINSIZ, "%2d pstyle", ++ps_pnum); else snprintf( outlin, LINSIZ, "%2d cstyle", 1); ps_accu.push_back( outlin ); snprintf( outlin, LINSIZ, " %% (%s -> %s)\n", xco.c_str(), yco.c_str()); ps_accu.push_back( outlin ); for (uint i=0; i<np; i++) { snprintf( outlin, LINSIZ, "%7.3f%7.3f%7.3f t%c %% %14.7g wx %14.7g wy\n", X.pc(xp[i]), Y.pc(yp[i]), 0.0, i==0 ? 'i' : i==np-1 ? 'f' : ' ', xp[i], yp[i]); ps_accu.push_back( outlin ); } #endif free(xp); free(yp); } void NPlot::Doc (vector<string> lDoc) { #ifdef WUPS for (uint i=0; i<lDoc.size(); i++) ps_Doc.push_back(lDoc[i]); #endif } void NPlot::Save( bool full_outfile ) { #ifdef WUPS string ps_outdir, ps_head, ps_dict; // read configuration parameters: if ( NRead::wofmac("\\psdir", &ps_outdir) ) { printf("! please define \\psdir\n"); return; } if ( NRead::wofmac("\\pshead", &ps_head) ) { printf("! please define \\pshead\n"); return; } if ( full_outfile && NRead::wofmac("\\psdict", &ps_dict)) { printf("! please define \\psdict\n"); return; } // construct output file name: FILE *pssav; char outf[20]; string flong, cmd; while(1) { if (ps_fnum>=999) { printf ("graph file number overflow\n"); return; } sprintf(outf, "%sl%d.%s", ps_outdir.c_str(), ++ps_fnum, full_outfile ? "ps" : "psa" ); if (!(pssav = mystd::glob_fopen(outf, "", "", "r"))) break; // legal exit fclose(pssav); } printf("save plot in %s\n", outf); // copy headers to output file: cmd = string("cat ") + ( full_outfile ? ps_dict : "" ) + " " + ps_head + " > " + outf + "\n"; if (system(cmd.c_str())) { printf ("cannot copy to %s\n", outf); return; } // a redundant check of existence of the outfile: if (!(pssav = mystd::glob_fopen(outf, "", "", "r", &flong))) { printf("have not created file %s\n", outf); return; } fclose(pssav); // append specific output to output file: if (!(pssav = fopen(flong.c_str(), "a+"))) { printf ("cannot write (append) to file %s\n", flong.c_str()); return; } for( uint i=0; i<ps_accu.size(); ++i ){ fprintf( pssav, ps_accu[i].c_str() ); } // additional output (do not append this to ps_accu to allow // further incrementation of ps_accu): fprintf(pssav, "\nblack 0 -4 13 newlist\n"); for (uint i=0; i<ps_Doc.size(); i++) fprintf(pssav, "{(%s)} infline\n", ps_Doc[i].c_str()); fprintf(pssav, "\n{(%s)} /filename exch def 10 -2.8 18 showfilename\n\n" "EndFrame\n", outf); // output completed: fclose(pssav); #else cout << "graphic save desactivated\n"; #endif #ifdef PLPL // plend(); // TEST #endif } void NPlot::Tekx(void) { #ifdef PLPL // pltext(); // back to Tektronix text window #endif } void NPlot::Dialog(void) { #ifdef GNUP string cmd; cout << "entering mygnuplot - to leave, type q\n"; while(1) { cmd = sask("mygnuplot> "); if (cmd.substr(0,1)=="q") return; gp_write(cmd); } #else cout << "Graphic dialog is implemented only for Gnuplot\n"; #endif } #ifdef GNUP void NPlot::gp_write(string in) { // cout << "DEBUG gp_write " << in << "\n"; string out = in + "\n"; write(gp_fifo, out.c_str(), out.size()); } #endif #ifdef WUPS void NPlot::ps_ticktack(uint ntack, double *tack, int ntpt, double *ticklim, CAxis *A) { uint i; ps_accu.push_back( "[\n" ); if (A->log && ( tack[0]<1e-3 || tack[ntack-1]>1e3 )) { for (i=0; i<ntack; i++) { snprintf( outlin, LINSIZ, " %9.6f {(10)(%d)sp()} %%{(%g)}\n", A->pc(tack[i]), mystd::nint(log10(tack[i])), (float) tack[i]); ps_accu.push_back( outlin ); } } else { for (i=0; i<ntack; i++) { snprintf( outlin, LINSIZ, " %9.6f {(%g)}\n", A->pc(tack[i]), (float) tack[i]); ps_accu.push_back( outlin ); } } ps_accu.push_back( " ] SetTacVec\n" ); snprintf( outlin, LINSIZ, " %g %g %d %d SetTicVec%s\n", A->pc(ticklim[0]), A->pc(ticklim[1]), ntack+2, ntpt, (A->log? "Log" : "Lin")); ps_accu.push_back( outlin ); } #endif