sciplot  0.3.1
A modern C++ plotting library powered by gnuplot
Figure.hpp
1 // sciplot - a modern C++ scientific plotting library powered by gnuplot
2 // https://github.com/sciplot/sciplot
3 //
4 // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
5 //
6 // Copyright (c) 2018-2022 Allan Leal, Bim Overbohm
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in all
16 // copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 // SOFTWARE.
25 
26 #pragma once
27 
28 // C++ includes
29 #include <typeinfo>
30 #include <variant>
31 #include <vector>
32 
33 // sciplot includes
34 #include <sciplot/Plot2D.hpp>
35 #include <sciplot/Plot3D.hpp>
36 #include <sciplot/specs/FontSpecsOf.hpp>
37 #include <sciplot/specs/LayoutSpecs.hpp>
38 
39 namespace sciplot
40 {
41 
43 using PlotVariant = std::variant<Plot2D, Plot3D>;
44 
45 template <typename... Ts>
46 struct Overload : Ts...
47 {
48  using Ts::operator()...;
49 };
50 template <class... Ts>
51 Overload(Ts...) -> Overload<Ts...>;
52 
53 static constexpr auto SavePlotVisitor = Overload{
54  [](const Plot2D& p)
55  { p.savePlotData(); },
56  [](const Plot3D& p)
57  { p.savePlotData(); }};
58 
59 static constexpr auto ReprPlotVisitor = Overload{
60  [](const Plot2D& p)
61  { return p.repr(); },
62  [](const Plot3D& p)
63  { return p.repr(); }};
64 
65 static constexpr auto CleanupPlotVisitor = Overload{
66  [](const Plot2D& p)
67  { p.cleanup(); },
68  [](const Plot3D& p)
69  { p.cleanup(); }};
70 
72 class Figure
73 {
74  public:
76  Figure(const std::initializer_list<std::initializer_list<PlotVariant>>& plots);
77 
79  Figure(const std::vector<std::vector<PlotVariant>>& plots);
80 
83  Plot& get(int i, int j);
84 
87  template <typename T>
88  T& get(int i, int j);
89 
92  auto palette(const std::string& name) -> Figure&;
93 
95  auto layout() -> LayoutSpecs&;
96 
98  auto fontName(std::string name) -> Figure&;
99 
101  auto fontSize(std::size_t size) -> Figure&;
102 
104  auto title(const std::string& title) -> Figure&;
105 
107  auto saveplotdata() const -> void;
108 
110  auto cleanup() const -> void;
111 
113  auto repr() const -> std::string;
114 
115  private:
117  static std::size_t m_counter;
118 
121  std::size_t m_id = 0;
122 
124  LayoutSpecs m_layout;
125 
127  std::size_t m_layoutrows = 0;
129  std::size_t m_layoutcols = 0;
130 
132  std::string m_title;
133 
135  std::vector<std::vector<PlotVariant>> m_plots;
136 };
137 
138 // Initialize the counter of plot objects
139 inline std::size_t Figure::m_counter = 0;
140 
141 inline Figure::Figure(const std::initializer_list<std::initializer_list<PlotVariant>>& plots)
142  : m_id(m_counter++)
143 {
144  m_layoutrows = plots.size();
145  m_layoutcols = 1;
146  for (const auto& row : plots)
147  m_layoutcols = std::max<decltype(m_layoutcols)>(m_layoutcols, row.size()); // m_layoutcols = max number of columns among all rows
148 
149  for (const auto& row : plots)
150  m_plots.emplace_back(row.begin(), row.end());
151 }
152 
153 inline Figure::Figure(const std::vector<std::vector<PlotVariant>>& plots)
154  : m_id(m_counter++), m_plots(plots)
155 {
156  m_layoutrows = plots.size();
157  m_layoutcols = 1;
158  for (const auto& row : plots)
159  m_layoutcols = std::max<decltype(m_layoutcols)>(m_layoutcols, row.size()); // m_layoutcols = max number of columns among all rows
160 }
161 
162 inline Plot& Figure::get(int i, int j)
163 {
164  auto& plot = m_plots.at(j).at(i);
165  if (std::holds_alternative<Plot2D>(plot))
166  {
167  return std::get<Plot2D>(plot);
168  }
169  else if (std::holds_alternative<Plot3D>(plot))
170  {
171  return std::get<Plot3D>(plot);
172  }
173  throw std::runtime_error("Unknown plot type / Empty variant");
174 }
175 
176 template <>
177 inline Plot2D& Figure::get(int i, int j)
178 {
179  return std::get<Plot2D>(m_plots.at(j).at(i));
180 }
181 
182 template <>
183 inline Plot3D& Figure::get(int i, int j)
184 {
185  return std::get<Plot3D>(m_plots.at(j).at(i));
186 }
187 
188 inline auto Figure::palette(const std::string& name) -> Figure&
189 {
190  for (auto& row : m_plots)
191  {
192  for (auto& plot : row)
193  {
194  if (std::holds_alternative<Plot2D>(plot))
195  {
196  std::get<Plot2D>(plot).palette(name);
197  }
198  else if (std::holds_alternative<Plot3D>(plot))
199  {
200  std::get<Plot3D>(plot).palette(name);
201  }
202  }
203  }
204  return *this;
205 }
206 
207 inline auto Figure::layout() -> LayoutSpecs&
208 {
209  return m_layout;
210 }
211 
212 inline auto Figure::title(const std::string& title) -> Figure&
213 {
214  m_title = title;
215  return *this;
216 }
217 
218 inline auto Figure::repr() const -> std::string
219 {
220  std::stringstream script;
221  // Add multiplot commands
222  if (m_layoutrows > 1 || m_layoutcols > 1)
223  {
224  gnuplot::multiplotcmd(script, m_layoutrows, m_layoutcols, m_title);
225  }
226  script << m_layout << std::endl;
227  for (const auto& row : m_plots)
228  {
229  for (const auto& plot : row)
230  {
231  script << std::visit(ReprPlotVisitor, plot);
232  }
233  }
234  // Close multiplot
235  if (m_layoutrows > 1 || m_layoutcols > 1)
236  {
237  script << "unset multiplot" << std::endl;
238  }
239  return script.str();
240 }
241 
242 inline auto Figure::saveplotdata() const -> void
243 {
244  for (const auto& row : m_plots)
245  {
246  for (const auto& plot : row)
247  {
248  std::visit(SavePlotVisitor, plot);
249  }
250  }
251 }
252 
253 inline auto Figure::cleanup() const -> void
254 {
255  for (const auto& row : m_plots)
256  {
257  for (const auto& plot : row)
258  {
259  std::visit(CleanupPlotVisitor, plot);
260  }
261  }
262 }
263 
264 } // namespace sciplot
T & get(int i, int j)
Get reference to specific plot object (2D / 3D) in figure.
The class used to create multiple plots in one canvas. A container for plots.
Definition: Figure.hpp:73
auto fontSize(std::size_t size) -> Figure &
Set the font size for all the plots in the figure (e.g., 10, 12, 16).
auto title(const std::string &title) -> Figure &
Set the title of the figure.
Definition: Figure.hpp:212
Figure(const std::initializer_list< std::initializer_list< PlotVariant >> &plots)
Construct a Figure object with given plots.
Definition: Figure.hpp:141
auto palette(const std::string &name) -> Figure &
Set the palette of colors for all plots in the figure.
Definition: Figure.hpp:188
auto saveplotdata() const -> void
Write the current plot data of all plots to the data file(s).
Definition: Figure.hpp:242
auto layout() -> LayoutSpecs &
Set the layout of the figure inside the canvas and return a reference to the corresponding specs obje...
Definition: Figure.hpp:207
Definition: Figure.hpp:47
auto fontName(std::string name) -> Figure &
Set the font name for all the plots in the figure (e.g., Helvetica, Georgia, Times).
The class used to create a plot containing graphical elements.
Definition: Plot.hpp:57
The class used to create a plot containing graphical elements.
Definition: Plot2D.hpp:58
Plot & get(int i, int j)
Get reference to generic plot object in figure.
Definition: Figure.hpp:162
auto repr() const -> std::string
Convert this figure into a gnuplot formatted string.
Definition: Figure.hpp:218
auto cleanup() const -> void
Delete all files used to store plot data or scripts.
Definition: Figure.hpp:253
The class used to specify layout options.
Definition: LayoutSpecs.hpp:87