//************************************************************************************************** //* 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 CAxis* A); string ps_coord(const CAxis* A); string ps_axis(const CAxis* A); string ps_horiz(const string& label); string ps_verti(const string& label); string ps_colorscale(const string& label); 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); ps_accu += ps_coord(Y); ps_accu += "\n"; ps_accu += ps_axis(X) + ps_horiz(xlabel); ps_accu += ps_axis(Y) + ps_verti(ylabel); 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); ps_accu += ps_coord(Z); ps_accu += ps_coord(Y); ps_accu += "\n%% 2D image begin\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 += "%% 2D image end\n\n"; ps_accu += "/linsetTic {white 1 setline} def\n"; ps_accu += "/linsetTac {white 1.3 setline} def\n\n"; ps_accu += ps_axis(X) + ps_horiz(xlabel); ps_accu += ps_axis(Z) + ps_verti(zlabel); ps_accu += ps_axis(Y) + ps_colorscale(ylabel); } 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 CAxis* A) { vector<double> Tacks; int ticks_per_tack; int ntacks4ticks; double ticklim[2]; A->calc_ticks(Tacks, ticks_per_tack, ntacks4ticks, ticklim); string ret; int ntack = Tacks.size(); ret += "[\n"; if (!ntack) ; // do nothing else if (A->logflag && (Tacks.front() < 1e-3 || Tacks.back() > 1e3)) { for (int i = 0; i < ntack; i++) ret += str(format(" %g w%s {(10)(%i)sp()} %%{(%g)}\n") % (float)Tacks[i] % A->name % (int)(log10(Tacks[i])) % (float)Tacks[i]); } else { for (int i = 0; i < ntack; i++) ret += str(format(" %g w%s {(%g)}\n") % (float)Tacks[i] % A->name % (float)Tacks[i]); } ret += " ] SetTacVec\n"; ret += str(format("%g w%s %g w%s %i %i SetTicVec%s\n") % (float)ticklim[0] % A->name % (float)ticklim[1] % A->name % ntacks4ticks % ticks_per_tack % (A->logflag ? "Log" : "Lin")); return ret; } string ps_coord(const CAxis* A) { return str(format("%1i %g %g %cSetCoord\n") % A->logflag % A->inf % A->sup % A->name); } string ps_axis(const CAxis* A) { string ret = "% " + A->name + " axis:\n"; if (A->logflag && A->inf <= 0) throw "BUG: log incompatible with limits " + A->str(); ret += ps_ticktack(A); return ret; } string ps_horiz(const string& label) { 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" "{(" + label + ")} xCL\n\n"; } string ps_verti(const string& label) { 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" "{(" + label + ")} yCL\n\n"; } string ps_colorscale(const string& label) { 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" "{(" + label + ")} 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