1
0
mirror of https://github.com/aportelli/LatAnalyze.git synced 2024-11-10 08:55:37 +00:00
LatAnalyze/latan/Plot.cpp

341 lines
9.9 KiB
C++
Raw Normal View History

/*
* Plot.cpp, part of LatAnalyze 3
*
* Copyright (C) 2013 - 2014 Antonin Portelli
*
* LatAnalyze 3 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LatAnalyze 3 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
*/
#include <latan/Plot.hpp>
#include <latan/includes.hpp>
2014-03-03 12:41:48 +00:00
#include <latan/Mat.hpp>
using namespace std;
using namespace Latan;
/******************************************************************************
2014-03-03 12:41:48 +00:00
* Plot objects *
******************************************************************************/
2014-03-03 12:41:48 +00:00
// PlotObject access ///////////////////////////////////////////////////////////
const string & PlotObject::getCommand(void) const
{
return command_;
}
void PlotObject::setCommand(const string &command)
{
command_ = command;
}
2014-03-03 12:41:48 +00:00
string PlotObject::popTmpFile(void)
{
string res = tmpFileName_.top();
tmpFileName_.pop();
return res;
}
void PlotObject::pushTmpFile(const std::string &fileName)
{
tmpFileName_.push(fileName);
}
// PlotObject test /////////////////////////////////////////////////////////////
bool PlotObject::gotTmpFile(void) const
{
return !tmpFileName_.empty();
}
// PlotCommand constructor /////////////////////////////////////////////////////
PlotCommand::PlotCommand(const string &command)
: command_(command)
{}
2014-03-03 12:41:48 +00:00
// PlotData constructor ////////////////////////////////////////////////////////
PlotData::PlotData(const XYStatData &data, const int i, const int j)
: data_(data)
, i_(i)
, j_(j)
{
2014-03-03 12:41:48 +00:00
DMat d(data_.getNData(), 4);
char tmpFileName[MAX_PATH_LENGTH];
int fd;
FILE *tmpFile;
string usingCmd;
d.col(0) = data_.x(i_, _);
d.col(2) = data_.y(j_, _);
d.col(1) = data_.xxVar(i_, i_).diagonal().array().sqrt();
d.col(3) = data_.yyVar(i_, i_).diagonal().array().sqrt();
usingCmd = (data_.isXExact(i_)) ? "u 1:3:4 w yerr" : "u 1:2:3:4 w xyerr";
strcpy(tmpFileName, "./latan_plot_tmp.XXXXXX.dat");
fd = mkstemps(tmpFileName, 4);
if (fd == -1)
{
LATAN_ERROR(System, "impossible to create a temporary file from template "
+ strFrom(tmpFileName));
}
tmpFile = fdopen(fd, "w");
for (Index r = 0; r < data_.getNData(); ++r)
{
fprintf(tmpFile, "%e %e %e %e\n", d(r, 0), d(r, 1), d(r, 2), d(r, 3));
}
fclose(tmpFile);
pushTmpFile(tmpFileName);
setCommand("'" + string(tmpFileName) + "' " + usingCmd);
}
/******************************************************************************
* Plot modifiers *
******************************************************************************/
// Color constructor ///////////////////////////////////////////////////////////
Color::Color(const string &color)
: color_(color)
{}
// Color modifier //////////////////////////////////////////////////////////////
void Color::operator()(PlotOptions &option) const
{
option.lineColor = color_;
}
// LogScale constructor ////////////////////////////////////////////////////////
LogScale::LogScale(const Axis axis)
: axis_(axis)
{}
// Logscale modifier ///////////////////////////////////////////////////////////
void LogScale::operator()(PlotOptions &option) const
{
option.scaleMode[static_cast<int>(axis_)] |= Plot::Scale::log;
}
// PlotRange constructor ////////////////////////////////////////////////////////
PlotRange::PlotRange(const Axis axis, const double min, const double max)
: axis_(axis)
, min_(min)
, max_(max)
{}
// PlotRange modifier ///////////////////////////////////////////////////////////
void PlotRange::operator()(PlotOptions &option) const
{
int a = static_cast<int>(axis_);
option.scaleMode[a] |= Plot::Scale::manual;
option.scale[a].min = min_;
option.scale[a].max = max_;
}
/******************************************************************************
* Plot implementation *
******************************************************************************/
// destructor //////////////////////////////////////////////////////////////////
Plot::~Plot(void)
{
while (!tmpFileName_.empty())
{
if (remove(tmpFileName_.top().c_str()))
{
LATAN_ERROR(System, "impossible to remove temporary file '" +
tmpFileName_.top() + "'");
}
tmpFileName_.pop();
}
}
// plot objects ////////////////////////////////////////////////////////////////
2014-03-03 12:41:48 +00:00
Plot & Plot::operator<<(PlotObject &&command)
{
string commandStr;
while (command.gotTmpFile())
{
tmpFileName_.push(command.popTmpFile());
}
commandStr = command.getCommand();
if (!options_.lineColor.empty())
{
commandStr += " lc " + options_.lineColor;
options_.lineColor = "";
}
plotCommand_.push_back(commandStr);
return *this;
}
Plot & Plot::operator<<(PlotModifier &&modifier)
{
2014-03-03 12:41:48 +00:00
modifier(options_);
return *this;
}
// find gnuplot ////////////////////////////////////////////////////////////////
void Plot::getProgramPath(void)
{
int i, j, lg;
char *path;
2014-02-12 18:33:33 +00:00
static char buf[MAX_PATH_LENGTH];
/* Trivial case: try in CWD */
sprintf(buf,"./%s", gnuplotBin_.c_str()) ;
if (access(buf, X_OK) == 0)
{
sprintf(buf,".");
gnuplotPath_ = buf;
}
/* Try out in all paths given in the PATH variable */
else
{
buf[0] = 0;
path = getenv("PATH") ;
if (path)
{
for (i=0;path[i];)
{
for (j=i;(path[j])&&(path[j]!=':');j++);
lg = j - i;
strncpy(buf,path + i,(size_t)(lg));
if (lg == 0)
{
buf[lg++] = '.';
}
buf[lg++] = '/';
strcpy(buf + lg, gnuplotBin_.c_str());
if (access(buf, X_OK) == 0)
{
/* Found it! */
break ;
}
buf[0] = 0;
i = j;
if (path[i] == ':') i++ ;
}
}
else
{
LATAN_ERROR(System, "PATH variable not set");
}
/* If the buffer is still empty, the command was not found */
if (buf[0] == 0)
{
LATAN_ERROR(System, "cannot find gnuplot in $PATH");
}
/* Otherwise truncate the command name to yield path only */
lg = (int)(strlen(buf) - 1);
while (buf[lg]!='/')
{
buf[lg] = 0;
lg--;
}
buf[lg] = 0;
gnuplotPath_ = buf;
}
}
// plot parsing and output /////////////////////////////////////////////////////
void Plot::display(void)
{
std::string command;
FILE *gnuplotPipe;
if (!getenv("DISPLAY"))
{
LATAN_ERROR(System, "cannot find DISPLAY variable: is it set ?");
}
getProgramPath();
command = gnuplotPath_ + "/" + gnuplotBin_ + " " + gnuplotArgs_;
gnuplotPipe = popen(command.c_str(), "w");
if (!gnuplotPipe)
{
LATAN_ERROR(System, "error starting gnuplot (command was '" + command
+ "')");
}
commandBuffer_.str("");
commandBuffer_ << *this;
fprintf(gnuplotPipe, "%s", commandBuffer_.str().c_str());
if (pclose(gnuplotPipe) == -1)
{
LATAN_ERROR(System, "problem closing communication to gnuplot");
}
}
ostream & Latan::operator<<(ostream &out, const Plot &plot)
{
std::string begin, end;
2014-03-03 12:41:48 +00:00
int x = static_cast<int>(Axis::x), y = static_cast<int>(Axis::y);
2014-03-03 12:41:48 +00:00
if (!plot.options_.terminal.empty())
{
2014-03-03 12:41:48 +00:00
out << "set term " << plot.options_.terminal << endl;
}
2014-03-03 12:41:48 +00:00
if (!plot.options_.output.empty())
{
2014-03-03 12:41:48 +00:00
out << "set output '" << plot.options_.terminal << "'" << endl;
}
2014-03-03 12:41:48 +00:00
if (plot.options_.scaleMode[x] & Plot::Scale::manual)
{
2014-03-03 12:41:48 +00:00
out << "xMin = " << plot.options_.scale[x].min << endl;
out << "xMax = " << plot.options_.scale[x].max << endl;
}
2014-03-03 12:41:48 +00:00
if (plot.options_.scaleMode[y] & Plot::Scale::manual)
{
2014-03-03 12:41:48 +00:00
out << "yMin = " << plot.options_.scale[y].min << endl;
out << "yMax = " << plot.options_.scale[y].max << endl;
}
2014-03-03 12:41:48 +00:00
if (!plot.options_.title.empty())
{
2014-03-03 12:41:48 +00:00
out << "set title '" << plot.options_.title << "'" << endl;
}
2014-03-03 12:41:48 +00:00
if (plot.options_.scaleMode[x] & Plot::Scale::manual)
{
out << "set xrange [xMin:xMax]" << endl;
}
2014-03-03 12:41:48 +00:00
if (plot.options_.scaleMode[y] & Plot::Scale::manual)
{
out << "set yrange [yMin:yMax]" << endl;
}
2014-03-03 12:41:48 +00:00
if (plot.options_.scaleMode[x] & Plot::Scale::log)
{
out << "set log x" << endl;
}
2014-03-03 12:41:48 +00:00
if (plot.options_.scaleMode[y] & Plot::Scale::log)
{
out << "set log y" << endl;
}
2014-03-03 12:41:48 +00:00
if (!plot.options_.label[x].empty())
{
2014-03-03 12:41:48 +00:00
out << "set xlabel '" << plot.options_.label[x] << "'" << endl;
}
2014-03-03 12:41:48 +00:00
if (!plot.options_.label[y].empty())
{
2014-03-03 12:41:48 +00:00
out << "set ylabel '" << plot.options_.label[y] << "'" << endl;
}
for (unsigned int i = 0; i < plot.headCommand_.size(); ++i)
{
out << plot.headCommand_[i] << endl;
}
for (unsigned int i = 0; i < plot.plotCommand_.size(); ++i)
{
begin = (i == 0) ? "plot " : " ";
end = (i == plot.plotCommand_.size() - 1) ? "" : ",\\";
out << begin << plot.plotCommand_[i] << end << endl;
}
return out;
}