00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "gnuplot.h"
00022 #include "ns3/assert.h"
00023 #include <ostream>
00024 #include <stdexcept>
00025
00026 namespace ns3 {
00027
00028
00029
00030 struct GnuplotDataset::Data
00031 {
00032
00033
00034 unsigned int m_references;
00035
00036 std::string m_title;
00037 std::string m_extra;
00038
00039
00040
00041
00042 Data(const std::string& title);
00043
00044
00045 virtual ~Data();
00046
00047
00048
00049
00050 virtual std::string GetCommand() const = 0;
00051
00052
00053
00054
00055
00056
00057 virtual void PrintExpression(std::ostream &os) const = 0;
00058
00059
00060
00061
00062
00063 virtual void PrintDatafile(std::ostream &os) const = 0;
00064 };
00065
00066 GnuplotDataset::Data::Data(const std::string& title)
00067 : m_references(1),
00068 m_title(title),
00069 m_extra(m_defaultExtra)
00070 {
00071 }
00072
00073 GnuplotDataset::Data::~Data()
00074 {
00075 }
00076
00077
00078
00079 std::string GnuplotDataset::m_defaultExtra = "";
00080
00081 GnuplotDataset::GnuplotDataset (struct Data* data)
00082 : m_data(data)
00083 {
00084 }
00085
00086 GnuplotDataset::GnuplotDataset (const GnuplotDataset& original)
00087 : m_data(original.m_data)
00088 {
00089 ++m_data->m_references;
00090 }
00091
00092 GnuplotDataset::~GnuplotDataset()
00093 {
00094 if (--m_data->m_references == 0)
00095 delete m_data;
00096 }
00097
00098 GnuplotDataset& GnuplotDataset::operator= (const GnuplotDataset& original)
00099 {
00100 if (this != &original)
00101 {
00102 if (--m_data->m_references == 0)
00103 delete m_data;
00104
00105 m_data = original.m_data;
00106 ++m_data->m_references;
00107 }
00108 return *this;
00109 }
00110
00111 void
00112 GnuplotDataset::SetTitle (const std::string& title)
00113 {
00114 m_data->m_title = title;
00115 }
00116
00117 void
00118 GnuplotDataset::SetDefaultExtra (const std::string& extra)
00119 {
00120 m_defaultExtra = extra;
00121 }
00122 void
00123 GnuplotDataset::SetExtra (const std::string& extra)
00124 {
00125 m_data->m_extra = extra;
00126 }
00127
00128
00129
00130 struct Gnuplot2dDataset::Data2d : public GnuplotDataset::Data
00131 {
00132
00133
00134 enum Style m_style;
00135 enum ErrorBars m_errorBars;
00136
00137 PointSet m_pointset;
00138
00139
00140
00141
00142 Data2d(const std::string& title);
00143
00144 virtual std::string GetCommand() const;
00145 virtual void PrintExpression(std::ostream &os) const;
00146 virtual void PrintDatafile(std::ostream &os) const;
00147 };
00148
00149 Gnuplot2dDataset::Data2d::Data2d(const std::string& title)
00150 : Data(title),
00151 m_style(m_defaultStyle),
00152 m_errorBars(m_defaultErrorBars)
00153 {
00154 }
00155
00156 std::string
00157 Gnuplot2dDataset::Data2d::GetCommand() const
00158 {
00159 return "plot";
00160 }
00161
00162 void
00163 Gnuplot2dDataset::Data2d::PrintExpression(std::ostream &os) const
00164 {
00165 os << "'-' ";
00166
00167 if (m_title.size())
00168 os << " title '" << m_title << "'";
00169
00170 switch (m_style) {
00171 case LINES:
00172 os << " with lines";
00173 break;
00174 case POINTS:
00175 switch (m_errorBars)
00176 {
00177 case NONE:
00178 os << " with points";
00179 break;
00180 case X:
00181 os << " with xerrorbars";
00182 break;
00183 case Y:
00184 os << " with yerrorbars";
00185 break;
00186 case XY:
00187 os << " with xyerrorbars";
00188 break;
00189 }
00190 break;
00191 case LINES_POINTS:
00192 switch (m_errorBars)
00193 {
00194 case NONE:
00195 os << " with linespoints";
00196 break;
00197 case X:
00198 os << " with errorlines";
00199 break;
00200 case Y:
00201 os << " with yerrorlines";
00202 break;
00203 case XY:
00204 os << " with xyerrorlines";
00205 break;
00206 }
00207 break;
00208 case DOTS:
00209 os << " with dots";
00210 break;
00211 case IMPULSES:
00212 os << " with impulses";
00213 break;
00214 case STEPS:
00215 os << " with steps";
00216 break;
00217 case FSTEPS:
00218 os << " with fsteps";
00219 break;
00220 case HISTEPS:
00221 os << " with histeps";
00222 break;
00223 }
00224
00225 if (m_extra.size())
00226 os << " " << m_extra;
00227 }
00228
00229 void
00230 Gnuplot2dDataset::Data2d::PrintDatafile(std::ostream &os) const
00231 {
00232 for (PointSet::const_iterator i = m_pointset.begin ();
00233 i != m_pointset.end (); ++i)
00234 {
00235 if (i->empty) {
00236 os << std::endl;
00237 continue;
00238 }
00239
00240 switch (m_errorBars) {
00241 case NONE:
00242 os << i->x << " " << i->y << std::endl;
00243 break;
00244 case X:
00245 os << i->x << " " << i->y << " " << i->dx << std::endl;
00246 break;
00247 case Y:
00248 os << i->x << " " << i->y << " " << i->dy << std::endl;
00249 break;
00250 case XY:
00251 os << i->x << " " << i->y << " " << i->dx << " " << i->dy << std::endl;
00252 break;
00253 }
00254 }
00255 os << "e" << std::endl;
00256 }
00257
00258
00259
00260 enum Gnuplot2dDataset::Style Gnuplot2dDataset::m_defaultStyle = LINES;
00261 enum Gnuplot2dDataset::ErrorBars Gnuplot2dDataset::m_defaultErrorBars = NONE;
00262
00263 Gnuplot2dDataset::Gnuplot2dDataset (const std::string& title)
00264 : GnuplotDataset( new Data2d(title) )
00265 {
00266 }
00267
00268 void
00269 Gnuplot2dDataset::SetDefaultStyle (enum Style style)
00270 {
00271 m_defaultStyle = style;
00272 }
00273 void
00274 Gnuplot2dDataset::SetStyle (enum Style style)
00275 {
00276 reinterpret_cast<Data2d*>(m_data)->m_style = style;
00277 }
00278
00279 void
00280 Gnuplot2dDataset::SetDefaultErrorBars (enum ErrorBars errorBars)
00281 {
00282 m_defaultErrorBars = errorBars;
00283 }
00284 void
00285 Gnuplot2dDataset::SetErrorBars (enum ErrorBars errorBars)
00286 {
00287 reinterpret_cast<Data2d*>(m_data)->m_errorBars = errorBars;
00288 }
00289
00290 void
00291 Gnuplot2dDataset::Add (double x, double y)
00292 {
00293 NS_ASSERT (reinterpret_cast<Data2d*>(m_data)->m_errorBars == NONE);
00294
00295 struct Point data;
00296 data.empty = false;
00297 data.x = x;
00298 data.y = y;
00299 data.dx = 0.0;
00300 data.dy = 0.0;
00301 reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
00302 }
00303
00304 void
00305 Gnuplot2dDataset::Add (double x, double y, double errorDelta)
00306 {
00307 NS_ASSERT ( reinterpret_cast<Data2d*>(m_data)->m_errorBars == X ||
00308 reinterpret_cast<Data2d*>(m_data)->m_errorBars == Y );
00309
00310 struct Point data;
00311 data.empty = false;
00312 data.x = x;
00313 data.y = y;
00314 data.dx = errorDelta;
00315 data.dy = errorDelta;
00316 reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
00317 }
00318
00319 void
00320 Gnuplot2dDataset::Add (double x, double y, double minY, double maxY)
00321 {
00322 NS_ASSERT ( reinterpret_cast<Data2d*>(m_data)->m_errorBars == X ||
00323 reinterpret_cast<Data2d*>(m_data)->m_errorBars == Y );
00324
00325 struct Point data;
00326 data.empty = false;
00327 data.x = x;
00328 data.y = y;
00329 data.dx = minY;
00330 data.dy = maxY;
00331 reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
00332 }
00333
00334 void
00335 Gnuplot2dDataset::AddEmptyLine()
00336 {
00337 struct Point data;
00338 data.empty = true;
00339 reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
00340 }
00341
00342
00343
00344 struct Gnuplot2dFunction::Function2d : public GnuplotDataset::Data
00345 {
00346
00347
00348 std::string m_function;
00349
00350
00351
00352
00353 Function2d(const std::string& title, const std::string& function);
00354
00355 virtual std::string GetCommand() const;
00356 virtual void PrintExpression(std::ostream &os) const;
00357 virtual void PrintDatafile(std::ostream &os) const;
00358 };
00359
00360 Gnuplot2dFunction::Function2d::Function2d(const std::string& title, const std::string& function)
00361 : Data(title),
00362 m_function(function)
00363 {
00364 }
00365
00366 std::string
00367 Gnuplot2dFunction::Function2d::GetCommand() const
00368 {
00369 return "plot";
00370 }
00371
00372 void
00373 Gnuplot2dFunction::Function2d::PrintExpression(std::ostream &os) const
00374 {
00375 os << m_function;
00376
00377 if (m_title.size())
00378 os << " title '" << m_title << "'";
00379
00380 if (m_extra.size())
00381 os << " " << m_extra;
00382 }
00383
00384 void
00385 Gnuplot2dFunction::Function2d::PrintDatafile(std::ostream &os) const
00386 {
00387 }
00388
00389
00390
00391 Gnuplot2dFunction::Gnuplot2dFunction (const std::string& title, const std::string& function)
00392 : GnuplotDataset( new Function2d(title, function) )
00393 {
00394 }
00395
00396 void
00397 Gnuplot2dFunction::SetFunction (const std::string& function)
00398 {
00399 reinterpret_cast<Function2d*>(m_data)->m_function = function;
00400 }
00401
00402
00403
00404 struct Gnuplot3dDataset::Data3d : public GnuplotDataset::Data
00405 {
00406
00407
00408 std::string m_style;
00409
00410 PointSet m_pointset;
00411
00412
00413
00414
00415 Data3d(const std::string& title);
00416
00417 virtual std::string GetCommand() const;
00418 virtual void PrintExpression(std::ostream &os) const;
00419 virtual void PrintDatafile(std::ostream &os) const;
00420 };
00421
00422 Gnuplot3dDataset::Data3d::Data3d(const std::string& title)
00423 : Data(title),
00424 m_style(m_defaultStyle)
00425 {
00426 }
00427
00428 std::string
00429 Gnuplot3dDataset::Data3d::GetCommand() const
00430 {
00431 return "splot";
00432 }
00433
00434 void
00435 Gnuplot3dDataset::Data3d::PrintExpression(std::ostream &os) const
00436 {
00437 os << "'-' ";
00438
00439 if (m_style.size())
00440 os << " " << m_style;
00441
00442 if (m_title.size())
00443 os << " title '" << m_title << "'";
00444
00445 if (m_extra.size())
00446 os << " " << m_extra;
00447 }
00448
00449 void
00450 Gnuplot3dDataset::Data3d::PrintDatafile(std::ostream &os) const
00451 {
00452 for (PointSet::const_iterator i = m_pointset.begin ();
00453 i != m_pointset.end (); ++i)
00454 {
00455 if (i->empty) {
00456 os << std::endl;
00457 continue;
00458 }
00459
00460 os << i->x << " " << i->y << " " << i->z << std::endl;
00461 }
00462 os << "e" << std::endl;
00463 }
00464
00465
00466
00467 std::string Gnuplot3dDataset::m_defaultStyle = "";
00468
00469 Gnuplot3dDataset::Gnuplot3dDataset (const std::string& title)
00470 : GnuplotDataset( new Data3d(title) )
00471 {
00472 }
00473
00474 void
00475 Gnuplot3dDataset::SetDefaultStyle (const std::string& style)
00476 {
00477 m_defaultStyle = style;
00478 }
00479 void
00480 Gnuplot3dDataset::SetStyle (const std::string& style)
00481 {
00482 reinterpret_cast<Data3d*>(m_data)->m_style = style;
00483 }
00484
00485 void
00486 Gnuplot3dDataset::Add (double x, double y, double z)
00487 {
00488 struct Point data;
00489 data.empty = false;
00490 data.x = x;
00491 data.y = y;
00492 data.z = z;
00493 reinterpret_cast<Data3d*>(m_data)->m_pointset.push_back (data);
00494 }
00495
00496 void
00497 Gnuplot3dDataset::AddEmptyLine()
00498 {
00499 struct Point data;
00500 data.empty = true;
00501 reinterpret_cast<Data3d*>(m_data)->m_pointset.push_back (data);
00502 }
00503
00504
00505
00506 struct Gnuplot3dFunction::Function3d : public GnuplotDataset::Data
00507 {
00508
00509
00510 std::string m_function;
00511
00512
00513
00514
00515 Function3d(const std::string& title, const std::string& function);
00516
00517 virtual std::string GetCommand() const;
00518 virtual void PrintExpression(std::ostream &os) const;
00519 virtual void PrintDatafile(std::ostream &os) const;
00520 };
00521
00522 Gnuplot3dFunction::Function3d::Function3d(const std::string& title, const std::string& function)
00523 : Data(title),
00524 m_function(function)
00525 {
00526 }
00527
00528 std::string
00529 Gnuplot3dFunction::Function3d::GetCommand() const
00530 {
00531 return "splot";
00532 }
00533
00534 void
00535 Gnuplot3dFunction::Function3d::PrintExpression(std::ostream &os) const
00536 {
00537 os << m_function;
00538
00539 if (m_title.size())
00540 os << " title '" << m_title << "'";
00541
00542 if (m_extra.size())
00543 os << " " << m_extra;
00544 }
00545
00546 void
00547 Gnuplot3dFunction::Function3d::PrintDatafile(std::ostream &os) const
00548 {
00549 }
00550
00551
00552
00553 Gnuplot3dFunction::Gnuplot3dFunction (const std::string& title, const std::string& function)
00554 : GnuplotDataset( new Function3d(title, function) )
00555 {
00556 }
00557
00558 void
00559 Gnuplot3dFunction::SetFunction (const std::string& function)
00560 {
00561 reinterpret_cast<Function3d*>(m_data)->m_function = function;
00562 }
00563
00564
00565
00566 Gnuplot::Gnuplot (const std::string& outputFilename, const std::string& title)
00567 : m_outputFilename(outputFilename),
00568 m_terminal( DetectTerminal(outputFilename) ),
00569 m_title(title)
00570 {
00571 }
00572
00573 std::string Gnuplot::DetectTerminal (const std::string& filename)
00574 {
00575 std::string::size_type dotpos = filename.rfind('.');
00576 if (dotpos == std::string::npos) return "";
00577
00578 if (filename.substr(dotpos) == ".png") {
00579 return "png";
00580 }
00581 else if (filename.substr(dotpos) == ".pdf") {
00582 return "pdf";
00583 }
00584
00585 return "";
00586 }
00587
00588 void
00589 Gnuplot::SetTerminal (const std::string& terminal)
00590 {
00591 m_terminal = terminal;
00592 }
00593
00594 void
00595 Gnuplot::SetTitle (const std::string& title)
00596 {
00597 m_title = title;
00598 }
00599
00600 void
00601 Gnuplot::SetLegend (const std::string& xLegend, const std::string& yLegend)
00602 {
00603 m_xLegend = xLegend;
00604 m_yLegend = yLegend;
00605 }
00606
00607 void
00608 Gnuplot::SetExtra (const std::string& extra)
00609 {
00610 m_extra = extra;
00611 }
00612
00613 void
00614 Gnuplot::AppendExtra (const std::string& extra)
00615 {
00616 m_extra += "\n";
00617 m_extra += extra;
00618 }
00619
00620 void
00621 Gnuplot::AddDataset (const GnuplotDataset& dataset)
00622 {
00623 m_datasets.push_back (dataset);
00624 }
00625
00626 void
00627 Gnuplot::GenerateOutput (std::ostream &os) const
00628 {
00629 if (m_terminal.size())
00630 os << "set terminal " << m_terminal << std::endl;
00631
00632 if (m_outputFilename.size())
00633 os << "set output '" << m_outputFilename << "'" << std::endl;
00634
00635 if (m_title.size())
00636 os << "set title '" << m_title << "'" << std::endl;
00637
00638 if (m_xLegend.size())
00639 os << "set xlabel '" << m_xLegend << "'" << std::endl;
00640
00641 if (m_yLegend.size())
00642 os << "set ylabel '" << m_yLegend << "'" << std::endl;
00643
00644 if (m_extra.size())
00645 os << m_extra << std::endl;
00646
00647 if (m_datasets.empty())
00648 return;
00649
00650
00651
00652
00653 std::string command = m_datasets.begin()->m_data->GetCommand();
00654
00655 for (Datasets::const_iterator i = m_datasets.begin () + 1;
00656 i != m_datasets.end (); ++i)
00657 {
00658 NS_ASSERT_MSG(command == i->m_data->GetCommand(),
00659 "Cannot mix 'plot' and 'splot' GnuplotDatasets.");
00660 }
00661
00662 os << command << " ";
00663
00664
00665
00666 for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end ();)
00667 {
00668 i->m_data->PrintExpression(os);
00669
00670 i++;
00671
00672 if (i != m_datasets.end ())
00673 {
00674 os << ", ";
00675 }
00676 }
00677 os << std::endl;
00678
00679
00680
00681 for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end (); i++)
00682 {
00683 i->m_data->PrintDatafile(os);
00684 }
00685 }
00686
00687
00688
00689 GnuplotCollection::GnuplotCollection (const std::string& outputFilename)
00690 : m_outputFilename(outputFilename),
00691 m_terminal( Gnuplot::DetectTerminal(outputFilename) )
00692 {
00693 }
00694
00695 void
00696 GnuplotCollection::SetTerminal (const std::string& terminal)
00697 {
00698 m_terminal = terminal;
00699 }
00700
00701 void
00702 GnuplotCollection::AddPlot (const Gnuplot& plot)
00703 {
00704 m_plots.push_back (plot);
00705 }
00706
00707 Gnuplot&
00708 GnuplotCollection::GetPlot(unsigned int id)
00709 {
00710 if (id >= m_plots.size())
00711 throw(std::range_error("Gnuplot id is out of range"));
00712 else
00713 return m_plots[id];
00714 }
00715
00716 void
00717 GnuplotCollection::GenerateOutput (std::ostream &os) const
00718 {
00719 if (m_terminal.size())
00720 os << "set terminal " << m_terminal << std::endl;
00721
00722 if (m_outputFilename.size())
00723 os << "set output '" << m_outputFilename << "'" << std::endl;
00724
00725 for (Plots::const_iterator i = m_plots.begin (); i != m_plots.end (); ++i)
00726 {
00727 i->GenerateOutput (os);
00728 }
00729 }
00730
00731
00732
00733 }