Skip to content
Snippets Groups Projects
ps_plotter.cpp 5.67 KiB
Newer Older
//**************************************************************************************************
//*  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 <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;

void CPS_Plotter::clear()
{
    ps_accu = "\n%% output created by frida2\n";
    ps_snum = 0;
    ps_Doc = "";
}

void CPS_Plotter::plot_frame(
    const CAxis& _X, const CAxis& _Y, const string& xlabel, const string& ylabel)
{
    X = &_X;
    Y = &_Y;

Wuttke, Joachim's avatar
Wuttke, Joachim committed
    ps_accu += "\n";
    ps_accu += str(format("%1i %g %g xSetCoord\n") % X->logflag % X->inf % X->sup);
    ps_accu += str(format("%1i %g %g ySetCoord\n") % Y->logflag % Y->inf % Y->sup);

    int ntpt;
    double ticklim[2];
    vector<double> Tacks;
    ps_accu += "\n";
    ps_accu += "/xPlotFrame {\n";
    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);
    ps_accu += "  {(" + xlabel + ")}\n";
    ps_accu +=
        "   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"
        "} def\n\n";

    ps_accu += "/yPlotFrame {\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);
    ps_accu += "  {(" + ylabel + ")}\n";
    ps_accu +=
        "   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"
Wuttke, Joachim's avatar
Wuttke, Joachim committed
        "} def\n\n"
        "plotbefore\n\n";
}

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 += str(format("\n%3u [") % ++ps_snum);
        for (string zentry: zentries)
            ps_accu += " " + zentry;
        ps_accu += " ] zValues\n";
        ps_accu += str(format("%2i %cstyle %% (%s -> %s)\n")
                       % style_no
                       % (as_line ? 'c' : 'p')
                       % xco
                       % yco);
    } else {
        ps_accu += "\n";
    }
    int np = xp.size();
    for (int i = 0; i < np; i++)
        ps_accu += 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]);
}

void CPS_Plotter::doc_line(const string& line)
{
    ps_Doc += line + "\n";
}

void CPS_Plotter::write_postscript(
    const string& mode, const string& fname, const string& ps_outdir,
    const string& ps_head, const string& ps_cont, const string& ps_dict)
{
    // 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 " + ps_cont + " >> " + fname;
    } else {
        if (mode=="create") {
            if (triv::file_exists(fname))
                throw "File " + fname + " already exists. Use "
                    + (ps_dict=="" ? "gf!" : "gp!") + " to overwrite";
        } else if (mode=="overwrite") {
        } else
            throw "BUG: unexpected mode";
        cmd = "cat " + ps_dict + " " + ps_head + " > " + fname;
    }
    triv::system(cmd);

    // 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 << "\n{ black 0 -4 13 1.65 NewList\n";
    fs << ps_Doc;
    fs << "} oooinfo 1 eq { exec } { pop } ifelse\n";
    fs << "\n{(" << fname << ")}  /filename exch def 10 -2.8 18 showfilename\n\n";
    fs << " EndFrame\n",
    fs.close();
}



//! Format ticks and tacks for postscript file.

void CPS_Plotter::ps_ticktack(
    const vector<double>& Tacks, int ntpt, const double* ticklim, const CAxis* A)
{
    int ntack = Tacks.size();
    if (ntack > 0) {
        ps_accu += "  [\n";
        if (A->logflag && (Tacks[0] < 1e-3 || Tacks[ntack - 1] > 1e3)) {
            for (int i = 0; i < ntack; i++)
                ps_accu += 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++)
                ps_accu += str(format("   %9.6f {(%g)}\n")
                               % A->pc(Tacks[i])
                               % (float)Tacks[i]);
        }
        ps_accu += "  ] SetTacVec\n";
    }
    ps_accu += str(format("%g %g %i %i SetTicVec%s\n")
                   % A->pc(ticklim[0])
                   % A->pc(ticklim[1])
                   % (ntack + 2)
                   % ntpt
                   % (A->logflag ? "Log" : "Lin"));
}