sciplot  0.3.1
A modern C++ plotting library powered by gnuplot
Canvas.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 <variant>
30 #include <vector>
31 
32 // sciplot includes
33 #include <sciplot/Figure.hpp>
34 
35 namespace sciplot
36 {
37 
39 class Canvas
40 {
41  public:
43  Canvas(const std::initializer_list<std::initializer_list<Figure>>& figures);
44 
46  Canvas(const std::vector<std::vector<Figure>>& figures);
47 
50  Figure& get(int i, int j);
51 
54  auto autoclean(bool enable = true) -> void;
55 
58  auto defaultPalette(const std::string& name) -> Canvas&;
59 
61  auto size(std::size_t width, std::size_t height) -> Canvas&;
62 
64  auto fontName(std::string name) -> Canvas&;
65 
67  auto fontSize(std::size_t size) -> Canvas&;
68 
71  auto title(const std::string& title) -> Canvas&;
72 
74  auto saveplotdata() const -> void;
75 
78  auto show() const -> void;
79 
85  auto save(const std::string& filename) const -> void;
86 
88  auto cleanup() const -> void;
89 
90  private:
92  static std::size_t m_counter;
93 
96  std::size_t m_id = 0;
97 
99  bool m_autoclean = true;
100 
102  std::string m_defaultPalette;
103 
105  FontSpecs m_font;
106 
108  std::size_t m_width = 0;
109 
111  std::size_t m_height = 0;
112 
114  std::size_t m_layoutrows = 0;
115 
117  std::size_t m_layoutcols = 0;
118 
120  std::string m_title;
121 
123  std::string m_scriptfilename;
124 
126  std::vector<std::vector<Figure>> m_figures;
127 };
128 
129 // Initialize the counter of plot objects
130 inline std::size_t Canvas::m_counter = 0;
131 
132 inline Canvas::Canvas(const std::initializer_list<std::initializer_list<Figure>>& figures)
133  : m_id(m_counter++), m_scriptfilename("multishow" + internal::str(m_id) + ".plt")
134 {
135  m_layoutrows = figures.size();
136  m_layoutcols = 1;
137  for (const auto& row : figures)
138  m_layoutcols = std::max<decltype(m_layoutcols)>(m_layoutcols, row.size()); // m_layoutcols = max number of columns among all rows
139 
140  for (const auto& row : figures)
141  m_figures.emplace_back(row.begin(), row.end());
142 }
143 
144 inline Canvas::Canvas(const std::vector<std::vector<Figure>>& figures)
145  : m_id(m_counter++), m_scriptfilename("multishow" + internal::str(m_id) + ".plt"), m_figures(figures)
146 {
147  m_layoutrows = figures.size();
148  m_layoutcols = 1;
149  for (const auto& row : figures)
150  m_layoutcols = std::max<decltype(m_layoutcols)>(m_layoutcols, row.size()); // m_layoutcols = max number of columns among all rows
151 }
152 
153 inline Figure& Canvas::get(int i, int j)
154 {
155  return m_figures.at(j).at(i);
156 }
157 
158 inline auto Canvas::autoclean(bool enable) -> void
159 {
160  m_autoclean = enable;
161 }
162 
163 inline auto Canvas::defaultPalette(const std::string& name) -> Canvas&
164 {
165  m_defaultPalette = name;
166  return *this;
167 }
168 
169 inline auto Canvas::size(std::size_t width, std::size_t height) -> Canvas&
170 {
171  m_width = width;
172  m_height = height;
173  return *this;
174 }
175 
176 inline auto Canvas::fontName(std::string name) -> Canvas&
177 {
178  m_font.fontName(name);
179  return *this;
180 }
181 
182 inline auto Canvas::fontSize(std::size_t size) -> Canvas&
183 {
184  m_font.fontSize(size);
185  return *this;
186 }
187 
188 inline auto Canvas::title(const std::string& title) -> Canvas&
189 {
190  m_title = title;
191  return *this;
192 }
193 
194 inline auto Canvas::saveplotdata() const -> void
195 {
196  for (const auto& row : m_figures)
197  {
198  for (const auto& figure : row)
199  {
200  figure.saveplotdata();
201  }
202  }
203 }
204 
205 inline auto Canvas::show() const -> void
206 {
207  // Open script file and truncate it
208  std::ofstream script(m_scriptfilename);
209  // Add palette info. Use default palette if the user hasn't set one
210  gnuplot::palettecmd(script, m_defaultPalette.empty() ? internal::SCIPLOT_DEFAULT_PALETTE : m_defaultPalette);
211  // Add terminal info
212  auto width = m_width == 0 ? internal::DEFAULT_FIGURE_WIDTH : m_width;
213  auto height = m_height == 0 ? internal::DEFAULT_FIGURE_HEIGHT : m_height;
214  std::string size = gnuplot::canvasSizeStr(width, height, false);
215  gnuplot::showterminalcmd(script, size, m_font, m_title);
216  // Add the plot commands
217  for (const auto& row : m_figures)
218  {
219  for (const auto& figure : row)
220  {
221  // Add the plot commands
222  script << figure.repr();
223  }
224  }
225  // Add an empty line at the end and close the script to avoid crashes with gnuplot
226  script << std::endl;
227  script.close();
228  // save plot data to file(s)
229  saveplotdata();
230  // Show the figure
231  gnuplot::runscript(m_scriptfilename, true);
232  // remove the temporary files if user wants to
233  if (m_autoclean)
234  {
235  cleanup();
236  }
237 }
238 
239 inline auto Canvas::save(const std::string& filename) const -> void
240 {
241  // Clean the file name to prevent errors
242  auto cleanedfilename = gnuplot::cleanpath(filename);
243  // Get extension from file name
244  auto extension = cleanedfilename.substr(cleanedfilename.rfind(".") + 1);
245  // Open script file
246  std::ofstream script(m_scriptfilename);
247  // Add palette info. Use default palette if the user hasn't set one
248  gnuplot::palettecmd(script, m_defaultPalette.empty() ? internal::SCIPLOT_DEFAULT_PALETTE : m_defaultPalette);
249  // Add terminal info including output size
250  auto width = m_width == 0 ? internal::DEFAULT_FIGURE_WIDTH : m_width;
251  auto height = m_height == 0 ? internal::DEFAULT_FIGURE_HEIGHT : m_height;
252  std::string size = gnuplot::canvasSizeStr(width, height, extension == "pdf");
253  gnuplot::saveterminalcmd(script, extension, size, m_font);
254  // Add output command
255  gnuplot::outputcmd(script, cleanedfilename);
256  // Add the plot commands
257  for (const auto& row : m_figures)
258  {
259  for (const auto& figure : row)
260  {
261  // Add the plot commands
262  script << figure.repr();
263  }
264  }
265  // Unset the output
266  script << std::endl;
267  script << "set output";
268  // Add an empty line at the end and close the script to avoid crashes with gnuplot
269  script << std::endl;
270  script.close();
271  // save plot data to file(s)
272  saveplotdata();
273  // Save the figure as a file
274  gnuplot::runscript(m_scriptfilename, false);
275  // remove the temporary files if user wants to
276  if (m_autoclean)
277  {
278  cleanup();
279  }
280 }
281 
282 inline auto Canvas::cleanup() const -> void
283 {
284  std::remove(m_scriptfilename.c_str());
285  for (const auto& row : m_figures)
286  {
287  for (const auto& figure : row)
288  {
289  figure.cleanup();
290  }
291  }
292 }
293 
294 } // namespace sciplot
auto defaultPalette(const std::string &name) -> Canvas &
Set the default palette of colors for all plots that DO NOT have a palette set.
Definition: Canvas.hpp:163
auto size(std::size_t width, std::size_t height) -> Canvas &
Set the output size of the canvas (in unit of points, with 1 inch = 72 points).
Definition: Canvas.hpp:169
The class used to create multiple plots in one canvas. A container for plots.
Definition: Figure.hpp:73
auto autoclean(bool enable=true) -> void
Toggle automatic cleaning of temporary files (enabled by default).
Definition: Canvas.hpp:158
auto fontSize(std::size_t size) -> Canvas &
Set the font size for all the plots on the canvas (e.g., 10, 12, 16).
Definition: Canvas.hpp:182
auto title(const std::string &title) -> Canvas &
Set the title of the canvas.
Definition: Canvas.hpp:188
Canvas(const std::initializer_list< std::initializer_list< Figure >> &figures)
Construct a Canvas object with given figures.
Definition: Canvas.hpp:132
auto saveplotdata() const -> void
Write the current plot data of all figures to the data file(s).
Definition: Canvas.hpp:194
auto show() const -> void
Show the canvas in a pop-up window.
Definition: Canvas.hpp:205
auto cleanup() const -> void
Delete all files used to store plot data or scripts.
Definition: Canvas.hpp:282
The class used to create multiple figures in one canvas. A canvas can be show on screen or output to ...
Definition: Canvas.hpp:40
auto save(const std::string &filename) const -> void
Save the canvas to a file, with its extension defining the file format.
Definition: Canvas.hpp:239
The class used to specify font options.
Definition: FontSpecsOf.hpp:60
auto fontName(std::string name) -> Canvas &
Set the font name for all the plots on the canvas (e.g., Helvetica, Georgia, Times).
Definition: Canvas.hpp:176
Figure & get(int i, int j)
Get reference to figure object on canvas.
Definition: Canvas.hpp:153