Hermes2D  3.0
graph.cpp
1 // This file is part of Hermes2D.
2 //
3 // Hermes2D is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // Hermes2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Hermes2D. If not, see <http://www.gnu.org/licenses/>.
15 
16 #include "global.h"
17 #include "graph.h"
18 namespace Hermes
19 {
20  namespace Hermes2D
21  {
22  Graph::Graph(const char* title, const char* x_axis_name, const char* y_axis_name)
23  {
24  set_captions(title, x_axis_name, y_axis_name);
25  logx = logy = false;
26  legend = grid = true;
27  }
28 
29  void Graph::set_log_x(bool log)
30  {
31  logx = log;
32  }
33 
34  void Graph::set_log_y(bool log)
35  {
36  logy = log;
37  }
38 
39  void Graph::show_legend(bool show)
40  {
41  legend = show;
42  }
43 
44  void Graph::show_grid(bool show)
45  {
46  grid = show;
47  }
48 
49  void Graph::set_captions(const char* title, const char* x_axis_name, const char* y_axis_name)
50  {
51  this->title = title ? title : "";
52  xname = x_axis_name ? x_axis_name : "";
53  yname = y_axis_name ? y_axis_name : "";
54  }
55 
56  int Graph::add_row(const char* name, const char* color, const char* line, const char* marker)
57  {
58  Row row;
59  if (name == nullptr) name = "";
60  row.name = name;
61  row.color = "k";
62  row.line = "-";
63  row.marker = "";
64 
65  rows.push_back(row);
66  set_row_style(rows.size() - 1, color, line, marker);
67  return rows.size() - 1;
68  }
69 
70  void Graph::set_row_style(int row, const char* color, const char* line, const char* marker)
71  {
72  if (!rows.size()) add_row(nullptr);
73  rows[row].color = color;
74  rows[row].line = line;
75  rows[row].marker = marker;
76  }
77 
78  void Graph::add_values(int row, double x, double y)
79  {
80  if (!rows.size()) add_row(nullptr);
81  // this is to avoid problems with plotting in log-log scale
82  if (fabs(x) < Hermes::HermesSqrtEpsilon) return;
83  // (sometimes the CPU time was zero and plotting crashed)
84  if (row < 0 || row >= (int)rows.size()) throw Hermes::Exceptions::Exception("Invalid row number.");
85  Values xy = { x, y };
86  rows[row].data.push_back(xy);
87  }
88 
89  void Graph::add_values(double x, double y)
90  {
91  int row = 0;
92  if (!rows.size()) add_row(nullptr);
93  // this is to avoid problems with plotting in log-log scale
94  if (fabs(x) < Hermes::HermesSqrtEpsilon) return;
95  // (sometimes the CPU time was zero and plotting crashed)
96  Values xy = { x, y };
97  rows[row].data.push_back(xy);
98  }
99 
100  void Graph::add_values(int row, int n, double* x, double* y)
101  {
102  for (int i = 0; i < n; i++)
103  add_values(row, x[i], y[i]);
104  }
105 
106  void Graph::add_values(int row, int n, double2* xy)
107  {
108  for (int i = 0; i < n; i++)
109  add_values(row, xy[i][0], xy[i][1]);
110  }
111 
112  void Graph::save_numbered(const char* filename, int number)
113  {
114  char buffer[1000];
115  sprintf(buffer, filename, number);
116  save(buffer);
117  }
118 
119  void SimpleGraph::save(const char* filename)
120  {
121  if (!rows.size()) throw Hermes::Exceptions::Exception("No data rows defined.");
122 
123  FILE* f = fopen(filename, "w");
124  if (f == nullptr) throw Hermes::Exceptions::Exception("Error writing to %s.", filename);
125 
126  for (unsigned int i = 0; i < rows.size(); i++)
127  {
128  int rsize = rows[i].data.size();
129  for (int j = 0; j < rsize; j++)
130  fprintf(f, "%.14g %.14g\n", rows[i].data[j].x, rows[i].data[j].y);
131  }
132 
133  fclose(f);
134 
135  this->info("Graph saved to file '%s'.", filename);
136  }
137 
138  void MatlabGraph::save(const char* filename)
139  {
140  int j, k;
141 
142  if (!rows.size()) throw Hermes::Exceptions::Exception("No data rows defined.");
143 
144  FILE* f = fopen(filename, "w");
145  if (f == nullptr) throw Hermes::Exceptions::Exception("Error writing to %s", filename);
146 
147  if (!logx && !logy)
148  fprintf(f, "plot(");
149  else if (logx && !logy)
150  fprintf(f, "semilogx(");
151  else if (!logx && logy)
152  fprintf(f, "semilogy(");
153  else
154  fprintf(f, "loglog(");
155 
156  for (unsigned int i = 0; i < rows.size(); i++)
157  {
158  fprintf(f, "[");
159  int rsize = rows[i].data.size();
160  for (k = 0; k < 2; k++)
161  {
162  for (j = 0; j < rsize; j++)
163  {
164  fprintf(f, "%.14g", k ? rows[i].data[j].y : rows[i].data[j].x);
165  if (j < rsize - 1) fprintf(f, ", ");
166  }
167  fprintf(f, (!k ? "],[" : "], '"));
168  }
169  fprintf(f, "%s%s%s'", rows[i].color.c_str(), rows[i].line.c_str(), rows[i].marker.c_str());
170  if (i < rows.size() - 1) fprintf(f, ", ");
171  }
172  fprintf(f, ");\n");
173 
174  if (title.length()) fprintf(f, "title('%s');\n", title.c_str());
175  if (xname.length()) fprintf(f, "xlabel('%s');\n", xname.c_str());
176  if (yname.length()) fprintf(f, "ylabel('%s');\n", yname.c_str());
177 
178  if (legend && (rows.size() > 1 || rows[0].name.length()))
179  {
180  fprintf(f, "legend(");
181  for (unsigned int i = 0; i < rows.size(); i++)
182  {
183  fprintf(f, "'%s'", rows[i].name.c_str());
184  if (i < rows.size() - 1) fprintf(f, ", ");
185  }
186  fprintf(f, ");\n");
187  }
188  else
189  fprintf(f, "legend off;\n");
190 
191  fprintf(f, "grid %s;\n", grid ? "on" : "off");
192 
193  fclose(f);
194 
195  this->info("Graph saved. Run the file '%s' in Matlab.", filename);
196  }
197 
198  static void get_style_types(std::string line, std::string mark, std::string col, int& lt, int& pt, int& ct)
199  {
200  if (line == "-")
201  // solid
202  lt = 1;
203  else if (line == ":")
204  // dotted
205  lt = 4;
206  else if (line == "-.")
207  // dash dot
208  lt = 5;
209  else if (line == "--")
210  // dashed
211  lt = 2;
212  else
213  lt = 1;
214 
215  // full circle
216  if (mark == ".") pt = 7;
217  // empty circle
218  else if (mark == "o") pt = 6;
219  // full circle
220  else if (mark == "O") pt = 7;
221  // cross
222  else if (mark == "x") pt = 2;
223  // cross
224  else if (mark == "+") pt = 1;
225  // star
226  else if (mark == "*") pt = 3;
227  // empty square
228  else if (mark == "s") pt = 4;
229  // full square
230  else if (mark == "S") pt = 5;
231  // empty diamond
232  else if (mark == "d") pt = 10;
233  // full diamond
234  else if (mark == "D") pt = 11;
235  // empty triangle down
236  else if (mark == "v") pt = 12;
237  // full triangle down
238  else if (mark == "V") pt = 13;
239  // full triangle up
240  else if (mark == "^") pt = 9;
241  // empty triangle down
242  else if (mark == "<") pt = 12;
243  // empty triangle up
244  else if (mark == ">") pt = 8;
245  // empty pentagon
246  else if (mark == "p") pt = 14;
247  // full pentagon
248  else if (mark == "P") pt = 15;
249  else pt = 0;
250 
251  // black
252  if (col == "k") ct = -1;
253  // blue
254  else if (col == "b") ct = 3;
255  // green
256  else if (col == "g") ct = 2;
257  // cyan
258  else if (col == "c") ct = 5;
259  // magenta
260  else if (col == "m") ct = 4;
261  // yellow
262  else if (col == "y") ct = 6;
263  // red
264  else if (col == "r") ct = 1;
265  else ct = -1;
266  }
267 
268  void GnuplotGraph::set_legend_pos(const char* posspec)
269  {
271  legend_pos = posspec;
272  if (legend_pos.length() && !legend) legend = true;
273  }
274 
275  void GnuplotGraph::save(const char* filename)
276  {
277  int j;
278 
279  if (!rows.size()) throw Hermes::Exceptions::Exception("No data rows defined.");
280 
281  FILE* f = fopen(filename, "w");
282  if (f == nullptr) throw Hermes::Exceptions::Exception("Error writing to %s", filename);
283 
284  fprintf(f, "%s", terminal_str.c_str());
285 
286  int len = strlen(filename);
287  char* outname = malloc_with_check<char>(len + 10);
288  strcpy(outname, filename);
289  char* slash = strrchr(outname, '/');
290  if (slash != nullptr) strcpy(outname, ++slash);
291  char* dot = strrchr(outname, '.');
292  if (dot != nullptr && dot > outname) *dot = 0;
293  strcat(outname, ".eps");
294 
295  fprintf(f, "set output '%s'\n", (char*)outname);
296  free_with_check(outname);
297 
298  fprintf(f, "set size 0.8, 0.8\n");
299 
300  if (logx && !logy)
301  fprintf(f, "set logscale x\n");
302  else if (!logx && logy)
303  fprintf(f, "set logscale y\n");
304  else if (logx && logy)
305  {
306  fprintf(f, "set logscale x\n");
307  fprintf(f, "set logscale y\n");
308  }
309 
310  if (grid) fprintf(f, "set grid\n");
311 
312  if (title.length()) fprintf(f, "set title '%s'\n", title.c_str());
313  if (xname.length()) fprintf(f, "set xlabel '%s'\n", xname.c_str());
314  if (yname.length()) fprintf(f, "set ylabel '%s'\n", yname.c_str());
315  if (legend && legend_pos.length()) fprintf(f, "set key %s\n", legend_pos.c_str());
316 
317  fprintf(f, "plot");
318  for (unsigned int i = 0; i < rows.size(); i++)
319  {
320  int ct, lt, pt;
321  get_style_types(rows[i].line, rows[i].marker, rows[i].color, lt, pt, ct);
322 
323  if (lt == 0)
324  fprintf(f, " '-' w p pointtype %d", pt);
325  else if (ct < 0)
326  fprintf(f, " '-' w lp linewidth %g linetype %d pointtype %d", this->lw, lt, pt);
327  else
328  fprintf(f, " '-' w lp linewidth %g linecolor %d linetype %d pointtype %d", this->lw, ct, lt, pt);
329 
330  if (legend)
331  fprintf(f, " title '%s' ", rows[i].name.c_str());
332  else
333  fprintf(f, " notitle ");
334 
335  if (i < rows.size() - 1) fprintf(f, ",\\\n ");
336  }
337  fprintf(f, "\n");
338 
339  for (unsigned int i = 0; i < rows.size(); i++)
340  {
341  int rsize = rows[i].data.size();
342  for (j = 0; j < rsize; j++)
343  fprintf(f, "%.14g %.14g\n", rows[i].data[j].x, rows[i].data[j].y);
344  fprintf(f, "e\n");
345  }
346 
347  fprintf(f, "set terminal x11\n");
348  fclose(f);
349 
350  this->info("Graph saved. Process the file '%s' with gnuplot.", filename);
351  }
352 
353  PNGGraph::PNGGraph(const char* title, const char* x_axis_name, const char* y_axis_name, const double lines_width,
354  double plot_width, double plot_height) : GnuplotGraph(title, x_axis_name, y_axis_name, lines_width)
355  {
356  std::stringstream sstm;
357  sstm << "set terminal png font arial 12 size " << plot_width << "," << plot_height << " crop enhanced\n";
358  terminal_str = sstm.str();
359  }
360  }
361 }
Definition: adapt.h:24
Common definitions for Hermes2D.
::xsd::cxx::tree::buffer< char > buffer
Binary buffer type.
::xsd::cxx::tree::name< char, token > name
C++ type corresponding to the Name XML Schema built-in type.
::xsd::cxx::tree::string< char, simple_type > string
C++ type corresponding to the string XML Schema built-in type.
void set_legend_pos(const char *posspec)
Definition: graph.cpp:268