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)
{
X = &_X;
Y = &_Y;
ps_snum = 0;
ps_Doc = "";
ps_accu = "\n%% output created by " + caller + "\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 += ps_slice_header(as_line, ++ps_snum, style_no, zentries, xco, yco);
else
ps_accu += ps_data_block(X, Y, xp, yp, dyp);
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
}
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 << 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;
}
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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"
+ doc_lines
+ " {(plot -> " + fname + ")} TxLine\n"
+ "} oooinfo 1 eq { exec } { pop } ifelse\n\n"
+ "EndFrame\n";
}
} // anonymous namespace