Hermes2D  2.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 == NULL) 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(NULL);
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(NULL);
81  if(fabs(x) < 1e-12) return; // this is to avoid problems with plotting in log-log scale
82  // (sometimes the CPU time was zero and plotting crashed)
83  if(row < 0 || row >= (int)rows.size()) throw Hermes::Exceptions::Exception("Invalid row number.");
84  Values xy = { x, y };
85  rows[row].data.push_back(xy);
86  }
87 
88  void Graph::add_values(double x, double y)
89  {
90  int row = 0;
91  if(!rows.size()) add_row(NULL);
92  if(fabs(x) < 1e-12 ) return; // this is to avoid problems with plotting in log-log scale
93  // (sometimes the CPU time was zero and plotting crashed)
94  Values xy = { x, y };
95  rows[row].data.push_back(xy);
96  }
97 
98  void Graph::add_values(int row, int n, double* x, double* y)
99  {
100  for (int i = 0; i < n; i++)
101  add_values(row, x[i], y[i]);
102  }
103 
104  void Graph::add_values(int row, int n, double2* xy)
105  {
106  for (int i = 0; i < n; i++)
107  add_values(row, xy[i][0], xy[i][1]);
108  }
109 
110  void Graph::save_numbered(const char* filename, int number)
111  {
112  char buffer[1000];
113  sprintf(buffer, filename, number);
114  save(buffer);
115  }
116 
117  void SimpleGraph::save(const char* filename)
118  {
119  if(!rows.size()) throw Hermes::Exceptions::Exception("No data rows defined.");
120 
121  FILE* f = fopen(filename, "w");
122  if(f == NULL) throw Hermes::Exceptions::Exception("Error writing to %s.", filename);
123 
124  for (unsigned int i = 0; i < rows.size(); i++)
125  {
126  int rsize = rows[i].data.size();
127  for (int j = 0; j < rsize; j++)
128  fprintf(f, "%.14g %.14g\n", rows[i].data[j].x, rows[i].data[j].y);
129  }
130 
131  fclose(f);
132 
133  this->info("Graph saved to file '%s'.", filename);
134  }
135 
136  void MatlabGraph::save(const char* filename)
137  {
138  int j, k;
139 
140  if(!rows.size()) throw Hermes::Exceptions::Exception("No data rows defined.");
141 
142  FILE* f = fopen(filename, "w");
143  if(f == NULL) throw Hermes::Exceptions::Exception("Error writing to %s", filename);
144 
145  if(!logx && !logy)
146  fprintf(f, "plot(");
147  else if(logx && !logy)
148  fprintf(f, "semilogx(");
149  else if(!logx && logy)
150  fprintf(f, "semilogy(");
151  else
152  fprintf(f, "loglog(");
153 
154  for (unsigned int i = 0; i < rows.size(); i++)
155  {
156  fprintf(f, "[");
157  int rsize = rows[i].data.size();
158  for (k = 0; k < 2; k++)
159  {
160  for (j = 0; j < rsize; j++)
161  {
162  fprintf(f, "%.14g", k ? rows[i].data[j].y : rows[i].data[j].x);
163  if(j < rsize-1) fprintf(f, ", ");
164  }
165  fprintf(f, (!k ? "],[" : "], '"));
166  }
167  fprintf(f, "%s%s%s'", rows[i].color.c_str(), rows[i].line.c_str(), rows[i].marker.c_str());
168  if(i < rows.size()-1) fprintf(f, ", ");
169  }
170  fprintf(f, ");\n");
171 
172  if(title.length()) fprintf(f, "title('%s');\n", title.c_str());
173  if(xname.length()) fprintf(f, "xlabel('%s');\n", xname.c_str());
174  if(yname.length()) fprintf(f, "ylabel('%s');\n", yname.c_str());
175 
176  if(legend && (rows.size() > 1 || rows[0].name.length()))
177  {
178  fprintf(f, "legend(");
179  for (unsigned int i = 0; i < rows.size(); i++)
180  {
181  fprintf(f, "'%s'", rows[i].name.c_str());
182  if(i < rows.size()-1) fprintf(f, ", ");
183  }
184  fprintf(f, ");\n");
185  }
186  else
187  fprintf(f, "legend off;\n");
188 
189  fprintf(f, "grid %s;\n", grid ? "on" : "off");
190 
191  fclose(f);
192 
193  this->info("Graph saved. Run the file '%s' in Matlab.", filename);
194  }
195 
196  static void get_style_types(std::string line, std::string mark, std::string col, int& lt, int& pt, int& ct)
197  {
198  if(line == "-")
199  lt = 1; // solid
200  else if(line == ":")
201  lt = 4; // dotted
202  else if(line == "-.")
203  lt = 5; // dash dot
204  else if(line == "--")
205  lt = 2; // dashed
206  else
207  lt = 1;
208 
209  if(mark == ".") pt = 7; // full circle
210  else if(mark == "o") pt = 6; // empty circle
211  else if(mark == "O") pt = 7; // full circle
212  else if(mark == "x") pt = 2; // cross
213  else if(mark == "+") pt = 1; // cross
214  else if(mark == "*") pt = 3; // star
215  else if(mark == "s") pt = 4; // empty square
216  else if(mark == "S") pt = 5; // full square
217  else if(mark == "d") pt = 10; // empty diamond
218  else if(mark == "D") pt = 11; // full diamond
219  else if(mark == "v") pt = 12; // empty triangle down
220  else if(mark == "V") pt = 13; // full triangle down
221  else if(mark == "^") pt = 9; // full triangle up
222  else if(mark == "<") pt = 12; // empty triangle down
223  else if(mark == ">") pt = 8; // empty triangle up
224  else if(mark == "p") pt = 14; // empty pentagon
225  else if(mark == "P") pt = 15; // full pentagon
226  else pt = 0;
227 
228  if(col == "k") ct = -1; // black
229  else if(col == "b") ct = 3; // blue
230  else if(col == "g") ct = 2; // green
231  else if(col == "c") ct = 5; // cyan
232  else if(col == "m") ct = 4; // magenta
233  else if(col == "y") ct = 6; // yellow
234  else if(col == "r") ct = 1; // red
235  else ct = -1;
236  }
237 
238  void GnuplotGraph::set_legend_pos(const char* posspec)
239  {
241  legend_pos = posspec;
242  if(legend_pos.length() && !legend) legend = true;
243  }
244 
245  void GnuplotGraph::save(const char* filename)
246  {
247  int j;
248 
249  if(!rows.size()) throw Hermes::Exceptions::Exception("No data rows defined.");
250 
251  FILE* f = fopen(filename, "w");
252  if(f == NULL) throw Hermes::Exceptions::Exception("Error writing to %s", filename);
253 
254  fprintf(f, "%s", terminal_str.c_str());
255 
256  int len = strlen(filename);
257  char* outname = new char[len + 10];
258  strcpy(outname, filename);
259  char* slash = strrchr(outname, '/');
260  if(slash != NULL) strcpy(outname, ++slash);
261  char* dot = strrchr(outname, '.');
262  if(dot != NULL && dot > outname) *dot = 0;
263  strcat(outname, ".eps");
264 
265  fprintf(f, "set output '%s'\n", (char*)outname);
266 
267  fprintf(f, "set size 0.8, 0.8\n");
268 
269  if(logx && !logy)
270  fprintf(f, "set logscale x\n");
271  else if(!logx && logy)
272  fprintf(f, "set logscale y\n");
273  else if(logx && logy)
274  {
275  fprintf(f, "set logscale x\n");
276  fprintf(f, "set logscale y\n");
277  }
278 
279  if(grid) fprintf(f, "set grid\n");
280 
281  if(title.length()) fprintf(f, "set title '%s'\n", title.c_str());
282  if(xname.length()) fprintf(f, "set xlabel '%s'\n", xname.c_str());
283  if(yname.length()) fprintf(f, "set ylabel '%s'\n", yname.c_str());
284  if(legend && legend_pos.length()) fprintf(f, "set key %s\n", legend_pos.c_str());
285 
286  fprintf(f, "plot");
287  for (unsigned int i = 0; i < rows.size(); i++)
288  {
289  int ct, lt, pt;
290  get_style_types(rows[i].line, rows[i].marker, rows[i].color, lt, pt, ct);
291 
292  if(lt == 0)
293  fprintf(f, " '-' w p pointtype %d", pt);
294  else if(ct < 0)
295  fprintf(f, " '-' w lp linewidth %g linetype %d pointtype %d", this->lw, lt, pt);
296  else
297  fprintf(f, " '-' w lp linewidth %g linecolor %d linetype %d pointtype %d", this->lw, ct, lt, pt);
298 
299  if(legend)
300  fprintf(f, " title '%s' ", rows[i].name.c_str());
301  else
302  fprintf(f, " notitle ");
303 
304  if(i < rows.size() - 1) fprintf(f, ",\\\n ");
305  }
306  fprintf(f,"\n");
307 
308  for (unsigned int i = 0; i < rows.size(); i++)
309  {
310  int rsize = rows[i].data.size();
311  for (j = 0; j < rsize; j++)
312  fprintf(f, "%.14g %.14g\n", rows[i].data[j].x, rows[i].data[j].y);
313  fprintf(f, "e\n");
314  }
315 
316  fprintf(f, "set terminal x11\n");
317  fclose(f);
318 
319  this->info("Graph saved. Process the file '%s' with gnuplot.", filename);
320  }
321 
322  PNGGraph::PNGGraph( const char* title, const char* x_axis_name, const char* y_axis_name, const double lines_width,
323  double plot_width, double plot_height )
324  {
325  std::stringstream sstm;
326  sstm << "set terminal png font arial 12 size " << plot_width << "," << plot_height << " crop enhanced\n";
327  GnuplotGraph(title, x_axis_name, y_axis_name, lines_width, sstm.str());
328  }
329  }
330 }