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

    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)
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    p2D = false;
    caller = _caller;
}

void CPS_Plotter::set_labels(const std::string& _xlabel, const std::string& _ylabel)
{
    xlabel = _xlabel;
    ylabel = _ylabel;
Wuttke, Joachim's avatar
Wuttke, Joachim committed
}

void CPS_Plotter::start_frame2D(
    const std::string& _caller, const CAxis& _X, const CAxis& _Z, const CAxis& _Y)
Wuttke, Joachim's avatar
Wuttke, Joachim committed
{
    p2D = true;
    caller = _caller;
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    X = &_X;
    Z = &_Z;
    Y = &_Y;
    ps_snum = 0;
    ps_Doc = "";
    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 += ps_data_block(X, Y, xp, yp, dyp);
Wuttke, Joachim's avatar
Wuttke, Joachim committed
void CPS_Plotter::main_line(const string& line)
{
    ps_accu += line + "\n";
}

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

Wuttke, Joachim's avatar
Wuttke, Joachim committed
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;
Wuttke, Joachim's avatar
Wuttke, Joachim committed
}
Wuttke, Joachim's avatar
Wuttke, Joachim committed
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 << "\n%% output created by " << caller << "\n\n";
    if (!p2D) {
        fs << ps_coord(X);
        fs << ps_coord(Y);
        fs << "\n";
        fs << ps_axis(X) + ps_horiz(xlabel);
        fs << ps_axis(Y) + ps_verti(ylabel);
        fs << "\n";
    }
Wuttke, Joachim's avatar
Wuttke, Joachim committed
//**************************************************************************************************
//  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);
        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";
Wuttke, Joachim's avatar
Wuttke, Joachim committed
        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"));
    string ps_coord(const CAxis* A)
        return str(format("%1i %g %g %cSetCoord\n")
                   % A->logflag % A->inf % A->sup % A->name);
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    }
    string ps_axis(const CAxis* A)
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    {
        string ret = "% " + A->name + " axis:\n";
Wuttke, Joachim's avatar
Wuttke, Joachim committed
        if (A->logflag && A->inf <= 0)
            throw "BUG: log incompatible with limits " + A->to_s();
        ret += ps_ticktack(A);
Wuttke, Joachim's avatar
Wuttke, Joachim committed
        return ret;
    }

    string ps_horiz(const string& label)
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    {
        return
Wuttke, Joachim's avatar
Wuttke, Joachim committed
            " 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";
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    }
    string ps_verti(const string& label)
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    {
        return
Wuttke, Joachim's avatar
Wuttke, Joachim committed
            " 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)
Wuttke, Joachim's avatar
Wuttke, Joachim committed
    {
            " 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;
Wuttke, Joachim's avatar
Wuttke, Joachim committed
        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]);
Wuttke, Joachim's avatar
Wuttke, Joachim committed
        ret += "\n";
        return ret;
    }

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