Skip to content
Snippets Groups Projects
ps_plotter.cpp 7.5 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;

namespace {
    string ps_ticktack(
        const vector<double>& Tacks, const int ntpt, const double* ticklim, const CAxis* A);
    string ps_frame(
        const CAxis* X, const CAxis* Y, const string& xlabel, const string& ylabel);
    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_frame(
    const string& caller, const CAxis& _X, const CAxis& _Y,
    const string& xlabel, const string& ylabel)
    ps_snum = 0;
    ps_Doc = "";
    ps_accu = "\n%% output created by " + caller + "\n\n";
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    ps_accu += ps_frame(X, Y, xlabel, 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 += ps_data_block(X, Y, xp, yp, dyp);
}

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;
Wuttke, Joachim's avatar
Wuttke, Joachim committed
//**************************************************************************************************
//  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 += str(format("%g %g %i %i SetTicVec%s\n")
                   % A->pc(ticklim[0])
                   % A->pc(ticklim[1])
                   % (ntack + 2)
                   % ntpt
                   % (A->logflag ? "Log" : "Lin"));
    string ps_frame(
        const CAxis* X, const CAxis* Y, const string& xlabel, const string& ylabel)
    {
        string ret;
        ret += str(format("%1i %g %g xSetCoord\n") % X->logflag % X->inf % X->sup);
        ret += str(format("%1i %g %g ySetCoord\n") % Y->logflag % Y->inf % Y->sup);

        int ntpt;
        double ticklim[2];
        vector<double> Tacks;
        ret += "\n";
        ret += "/xPlotFrame {\n";
        if (X->logflag && X->inf <= 0)
            throw "BUG: x log incompatible with limits " + X->str();
        X->calc_ticks(Tacks, &ntpt, ticklim);
        ret += ps_ticktack(Tacks, ntpt, ticklim, X);
        ret += "  {(" + xlabel + ")}\n";
        ret +=
            "   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";

        ret += "/yPlotFrame {\n";
        if (Y->logflag && Y->inf <= 0)
            throw "BUG: y log incompatible with limits " + Y->str();
        Y->calc_ticks(Tacks, &ntpt, ticklim);
        ret += ps_ticktack(Tacks, ntpt, ticklim, Y);
        ret += "  {(" + ylabel + ")}\n";
        ret +=
            "   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"
            "} def\n\n"
            "plotbefore\n\n";
        return ret;
    }

    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("\n%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]);
        return ret;
    }

    string ps_footer(const string& fname, const string& doc_lines)
    {
        return "\n{ black 0 -3 13 1.65 NewList\n"
            + "  {(plot -> " + fname + ")} TxLine\n"
            + "} oooinfo 1 eq { exec } { pop } ifelse\n\n"