//************************************************************************************************** //* FRIDA: fast reliable interactive data analysis //* (C) Joachim Wuttke 1990-, v2(C++) 2001- //* http://apps.jcns.fz-juelich.de/frida //************************************************************************************************** //! \file gnuplotter.cpp //! \brief Implements class CPS_Plotter. #include <cmath> #include <fstream> #include <iostream> #include <boost/format.hpp> #include "../trivia/file_ops.hpp" #include "../trivia/string_convs.hpp" #include "axis.hpp" #include "ps_plotter.hpp" using std::string; using std::vector; using boost::format; namespace { string ps_ticktack( const vector<double>& Tacks, const int ntpt, const double* ticklim, const CAxis* A); string ps_coord(const CAxis* A, const char a); string ps_axis(const CAxis* A, const string& label, const char a); string ps_horiz(); string ps_verti(); string ps_colorscale(); string ps_slice_header( bool as_line, int slice_no, int style_no, const vector<string>& zentries, const string& xco, const string& yco); string ps_data_block( const CAxis* X, const CAxis* Y, const vector<double>& xp, const vector<double>& yp, const vector<double>& dyp); string ps_footer( const string& fname, const string& doc_lines); } void CPS_Plotter::start_frame1D( const string& caller, const CAxis& _X, const CAxis& _Y, const string& xlabel, const string& ylabel) { p2D = false; X = &_X; Y = &_Y; ps_snum = 0; ps_Doc = ""; ps_accu = "\n%% output created by " + caller + "\n\n"; ps_accu += ps_coord(X, 'x'); ps_accu += ps_coord(Y, 'y'); ps_accu += "\n"; ps_accu += ps_axis(X, xlabel, 'x') + ps_horiz(); ps_accu += ps_axis(Y, ylabel, 'y') + ps_verti(); ps_accu += "\n"; } void CPS_Plotter::start_frame2D( const std::string& caller, const CAxis& _X, const CAxis& _Z, const CAxis& _Y) { p2D = true; X = &_X; Z = &_Z; Y = &_Y; ps_snum = 0; ps_Doc = ""; ps_accu = "\n%% output created by " + caller + "\n\n"; ps_accu += ps_coord(X, 'x'); ps_accu += ps_coord(Z, 'y'); ps_accu += ps_coord(Y, 'h'); ps_accu += "\n"; } void CPS_Plotter::close_frame2D( const CAxis& _X, const CAxis& _Z, const CAxis& _Y, const std::string& xlabel, const std::string& zlabel, const std::string& ylabel) { ps_accu += "/linsetTic {white 1 setline} def\n"; ps_accu += "/linsetTac {white 1.3 setline} def\n\n"; ps_accu += ps_axis(X, xlabel, 'x') + ps_horiz(); ps_accu += ps_axis(Z, zlabel, 'y') + ps_verti(); ps_accu += ps_axis(Y, ylabel, 'h') + ps_colorscale(); } void CPS_Plotter::add_spec( bool as_line, bool new_slice, int style_no, const vector<double>& xp, const vector<double>& yp, const vector<double>& dyp, const vector<string>& zentries, const string& xco, const string& yco, const string& info) { // Postscript copy: if (new_slice) ps_accu += ps_slice_header(as_line, ++ps_snum, style_no, zentries, xco, yco); else ps_accu += "\n"; ps_accu += ps_data_block(X, Y, xp, yp, dyp); } void CPS_Plotter::main_line(const string& line) { ps_accu += line + "\n"; } void CPS_Plotter::doc_line(const string& line) { ps_Doc += line + "\n"; } void CPS_Plotter::copy_header( const string& fname, const string& mode, const bool withDefs, std::map<const string, string>& settings) { // copy headers to output file string cmd; if (mode=="append") { if (!triv::file_exists(fname)) throw "Cannot append graphic: file " + fname + " not found"; cmd = "cat " + settings.at("ps_continuation") + " >> " + fname; } else { if (mode=="create") { if (triv::file_exists(fname)) throw "File " + fname + " already exists. " + "Use command suffix '!' to overwrite"; } else if (mode=="overwrite") { } else throw "BUG: unexpected mode"; cmd = "cat "; if (withDefs) cmd += settings.at("ps_definitions") + " "; cmd += settings.at(string("ps_setup") + (p2D ? "2" : "1") + "D") + " > " + fname; } triv::system(cmd); } void CPS_Plotter::write_data(const string& fname) { // append specific output to output file: if (!triv::file_exists(fname)) throw "BUG: after copying headers, graphic output file " + fname + " still doesn't exist"; std::fstream fs(fname, std::fstream::out | std::fstream::app); fs << ps_accu; fs << ps_footer(fname, ps_Doc); fs.close(); } //************************************************************************************************** // static functions //************************************************************************************************** namespace { //! Format ticks and tacks for postscript file. string ps_ticktack( const vector<double>& Tacks, const int ntpt, const double* ticklim, const CAxis* A) { string ret; int ntack = Tacks.size(); if (ntack > 0) { ret += "[\n"; if (A->logflag && (Tacks[0] < 1e-3 || Tacks[ntack - 1] > 1e3)) { for (int i = 0; i < ntack; i++) ret += str(format(" %9.6f {(10)(%i)sp()} %%{(%g)}\n") % A->pc(Tacks[i]) % (int)(log10(Tacks[i])) % (float)Tacks[i]); } else { for (int i = 0; i < ntack; i++) ret += str(format(" %9.6f {(%g)}\n") % A->pc(Tacks[i]) % (float)Tacks[i]); } ret += " ] SetTacVec\n"; } ret += str(format("%g %g %i %i SetTicVec%s\n") % A->pc(ticklim[0]) % A->pc(ticklim[1]) % (ntack + 2) % ntpt % (A->logflag ? "Log" : "Lin")); return ret; } string ps_coord(const CAxis* A, const char a) { return str(format("%1i %12.4g %12.4g %cSetCoord\n") % A->logflag % A->inf % A->sup % a); } string ps_axis(const CAxis* A, const string& label, const char a) { string ret; int ntpt; double ticklim[2]; vector<double> Tacks; ret += "% " + string(1,a) + " axis:\n"; if (A->logflag && A->inf <= 0) throw "BUG: log incompatible with limits " + A->str(); A->calc_ticks(Tacks, &ntpt, ticklim); ret += ps_ticktack(Tacks, ntpt, ticklim, A); ret += "{(" + label + ")}\n"; return ret; } string ps_horiz() { return " 0 10 0 0 0 90 OneAxx Axx Tic Tac xNumL %% low x axis\n" " 0 10 0 10 0 270 OneAxx Axx Tic Tac %% top x axis\n" "xCL\n\n"; } string ps_verti() { return " 0 10 0 0 90 0 OneAxx Axx Tic Tac yNumL %% left y axis\n" " 0 10 10 0 90 180 OneAxx Axx Tic Tac %% right y axis\n" "yCL\n\n"; } string ps_colorscale() { return "ColorLegend\n" " hxlow hxhig 0 0 0 90 OneAxx Axx %% low x line\n" " hxlow hxhig 0 10 0 90 OneAxx Axx %% low x line\n" " 0 10 hxlow 0 90 0 OneAxx Tic Tac Axx %% left y axis\n" " 0 10 hxhig 0 90 180 OneAxx Tic Tac Axx yNumH %% right y axis\n" "hxhig YCH\n\n"; } string ps_slice_header( bool as_line, int slice_no, int style_no, const vector<string>& zentries, const string& xco, const string& yco) { string ret; ret += str(format("%3u [") % slice_no); for (string zentry: zentries) ret += " " + zentry; ret += " ] zValues\n"; ret += str(format("%2i %cstyle %% (%s -> %s)\n") % style_no % (as_line ? 'c' : 'p') % xco % yco); return ret; } string ps_data_block( const CAxis* X, const CAxis* Y, const vector<double>& xp, const vector<double>& yp, const vector<double>& dyp) { string ret; int np = xp.size(); for (int i = 0; i < np; i++) ret += str(format("%8.5f %8.5f %8.5f 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]); ret += "\n"; return ret; } string ps_footer(const string& fname, const string& doc_lines) { return "{ black 0 -3 13 1.65 NewList\n" + doc_lines + " {(plot -> " + fname + ")} TxLine\n" + "} oooinfo 1 eq { exec } { pop } ifelse\n\n" + "EndFrame\n"; } } // anonymous namespace