UFJF - Machine Learning Toolkit  0.51.8
Visualization.hpp
Go to the documentation of this file.
1 
6 #ifndef VISUALIZATION_HPP
7 #define VISUALIZATION_HPP
8 #ifdef __unix__
9 #include <dirent.h>
10 #elif _WIN32
11 #include <windows.h>
12 #endif
13 #if __has_include(<filesystem>)
14 #include <filesystem>
15  namespace fs = std::filesystem;
16 #elif __has_include(<experimental/filesystem>)
17 #include <experimental/filesystem>
18  namespace fs = std::experimental::filesystem;
19 #else
20 error "Missing the <filesystem> header."
21 #endif
22 #define PLOT_FOLDER "plottemp"
23 #include <string>
24 #include <map>
25 #include <array>
26 #include <utility>
27 #include "ufjfmltk/visual/gnuplot_i.hpp"
28 #include "ufjfmltk/core/Data.hpp"
30 #include "ufjfmltk/core/Utils.hpp"
32 
34 namespace mltk::visualize{
38  template < typename T = double >
39  class Visualization {
40  // Attributes
41  private :
43  Data< T > *samples;
44  std::map<std::string, std::string> configs;
45  Gnuplot *g{nullptr};
46  std::string plot_folder;
47  std::vector<std::string> plot_folders;
48  std::vector<std::string> temp_fnames;
49  bool is_shared, keep_temp_files;
50  static size_t n_plots;
51 
52  struct AxisRange{
53  double min=0, max=0;
54  };
55 
56  using AxisRanges = std::array<AxisRange, 3>;
57 
62  std::vector<std::string> createTempFiles(std::string plot_folder="");
63 
69  bool valid_file(std::string file);
70 
75  std::vector<std::string> getTempFilesNames(bool append_path=false);
76 
80  void removeTempFiles();
81 
82  void configurePlot(const std::string& outname, const std::string& format, const std::string& title, bool save=false,
83  const std::string& x_label="", const std::string& y_label="", const std::string& z_label="");
84 
85  AxisRanges configureRange(double scale = 1.0, int x = -1, int y = -1, int z = -1);
86 
87  AxisRanges configureRange(double scale = 1.0, mltk::Point<double> x = mltk::Point<double>(), mltk::Point<double> y = mltk::Point<double>(), mltk::Point<double> z = mltk::Point<double>());
88 
89  std::string prepareScript(std::string cmd);
90 
91  std::vector<std::string> sortLabels(std::vector<std::string>& files, const std::string& type="scatter");
92 
93  std::string fetchConfigs();
94 
95  void create_plotfolder();
96 
97  // Operations
98  public :
99  explicit Visualization (bool shared_session=true, bool keep_temp_files=false);
100  explicit Visualization (Data<T> &sample, bool shared_session=true, bool keep_temp_files=false);
101 
102  /*********************************************
103  * Setters *
104  *********************************************/
105  void setTerminal(const std::string& terminal){ configs["terminal"] = terminal;}
111  void setSample (Data< T >& sample);
117  void setTitle (std::string title);
123  void setStyle (std::string style);
124 
125  std::string execute_command(const std::string& cmd, bool fetch_configs=true);
126 
138  std::string plot1DRegresion(int x=0, bool save=false, double scale = 1.0,
139  const std::string& title="",
140  const std::string& format="svg",
141  const std::string& x_label="x", const std::string& y_label="y");
142 
155  std::string plot1DRegresionHyperplane(int x, Solution s, bool save=false, double scale = 1.0,
156  const std::string& title="",
157  const std::string& format="svg",
158  const std::string& x_label="x", const std::string& y_label="y");
159 
172  std::string plot2D(int x = 0, int y=1, bool save=false, double scale = 1.0,
173  const std::string& title="",
174  const std::string& format="svg",
175  const std::string& x_label="x", const std::string& y_label="y");
176 
177  std::string plot2D(mltk::Point<double> x, mltk::Point<double> y, bool save=false, double scale = 1.0,
178  const std::string& title="",
179  const std::string& format="svg",
180  const std::string& x_label="x", const std::string& y_label="y");
181 
195  std::string plot2DwithHyperplane(int x, int y, Solution w, bool save=false, double scale = 1.0,
196  const std::string& title="",
197  const std::string& format="svg",
198  const std::string& x_label="x", const std::string& y_label="y");
199 
213  std::string plot2DRegresion(int x=0, int y=1, bool save=false, double scale = 1.0,
214  const std::string& title="",
215  const std::string& format="svg",
216  const std::string& x_label="x", const std::string& y_label="y",
217  const std::string& z_label="z");
218 
233  std::string plot2DRegresionHyperplane(int x, int y, Solution s, bool save=false, double scale = 1.0,
234  const std::string& title="",
235  const std::string& format="svg",
236  const std::string& x_label="x", const std::string& y_label="y",
237  const std::string& z_label="z");
238 
253  std::string plot3D(int x=0, int y=1, int z=2, bool save=false, double scale = 1.0,
254  const std::string& title="",
255  const std::string& format="svg",
256  const std::string& x_label="x", const std::string& y_label="y", const std::string& z_label="z");
257 
258  std::string plot3D(mltk::Point<double> x, mltk::Point<double> y, mltk::Point<double> z, bool save=false, double scale = 1.0,
259  const std::string& title="",
260  const std::string& format="svg",
261  const std::string& x_label="x", const std::string& y_label="y", const std::string& z_label="z");
277  std::string plot3DwithHyperplane(int x, int y, int z, Solution w, bool save=false, double scale = 1.0,
278  const std::string& title="",
279  const std::string& format="svg",
280  const std::string& x_label="x", const std::string& y_label="y",
281  const std::string& z_label="z");
282 
300  template<class Learner>
301  std::string plotDecisionSurface2D(Learner& learner, int x=0, int y=1, bool is_trained = true, size_t grid_dim = 50,
302  bool save=false,
303  double scale = 1.0,
304  const std::string& title="",
305  const std::string& format="svg",
306  const std::string& x_label="x", const std::string& y_label="y");
311  static void cmd(const std::string& command);
312  ~Visualization();
313  };
314 
315  /*********************************************
316  * Implementation *
317  *********************************************/
318 
319  template<typename T>
320  size_t Visualization<T>::n_plots=0;
321  template<typename T>
322  Visualization< T >::Visualization(bool shared_session, bool keep_temp_files):
323  is_shared(shared_session),
324  keep_temp_files(keep_temp_files) {
325 #ifdef _WIN32
326  shared_session = false;
327 #endif
328  configs["terminal"] = "wxt";
329  if(shared_session) g = new Gnuplot();
330  }
331 
332  template<typename T>
333  Visualization< T >::Visualization(Data<T> &sample, bool shared_session, bool keep_temp_files):
334  is_shared(shared_session),
335  keep_temp_files(keep_temp_files) {
336 #ifdef _WIN32
337  shared_session = false;
338 #endif
339  samples = &sample;
340  configs["terminal"] = "wxt";
341  if(shared_session) g = new Gnuplot();
342  create_plotfolder();
343  createTempFiles();
344  }
345 
346  template<typename T>
347  void Visualization<T>::create_plotfolder() {
348  do{
349  this->plot_folder = PLOT_FOLDER+std::to_string(n_plots)+"/";
350  if(std::find(plot_folders.begin(), plot_folders.end(), this->plot_folder) == plot_folders.end()) {
351  plot_folders.push_back(this->plot_folder);
352  }
353  n_plots++;
354  }while(fs::exists(this->plot_folder));
355  try {
356  fs::create_directory(this->plot_folder);
357  }
358  catch (fs::filesystem_error const& ex) {
359  std::cout
360  << "what(): " << ex.what() << '\n'
361  << "path1(): " << ex.path1() << '\n'
362  << "path2(): " << ex.path2() << '\n'
363  << "code().value(): " << ex.code().value() << '\n'
364  << "code().message(): " << ex.code().message() << '\n'
365  << "code().category(): " << ex.code().category().name() << '\n';
366  }
367  }
368 
369  template<typename T>
370  void Visualization< T >::setTitle(std::string title){
371  configs["title"] = std::move(title);
372  }
373 
374  template<typename T>
375  void Visualization< T >::setStyle(std::string style){
376  configs["style"] = std::move(style);
377  }
378 
379  template<typename T>
380  std::vector<std::string> Visualization< T >::createTempFiles(std::string plot_folder){
381  size_t i, j, k, size = samples->size(), dim = samples->dim();
382  std::vector<std::string> file_names;
383 
384  if(plot_folder.empty()) {
385  plot_folder = this->plot_folder;
386  }
387 
388  if(samples->isClassification()) {
389  std::vector<std::string> class_names = samples->classesNames();
390  std::vector<int> classes = samples->classes();
391  std::vector<std::ofstream> temp_files(class_names.size());
392 
393  for(i = 0; i < class_names.size(); i++){
394  std::string file_name = std::string(plot_folder)+class_names[i]+std::string(".plt");
395  temp_files[i].open(file_name);
396  if(!temp_files[i].is_open()){
397  std::cerr << "Error opening the file " + file_name + "." << std::endl;
398  }else{
399  file_names.push_back(file_name);
400  }
401  }
402  for (i = 0; i < size; i++) {
403  auto point = (*samples)(i);
404  auto class_pos = std::find(classes.begin(), classes.end(), point.Y()) - classes.begin();
405  auto class_name = class_names[class_pos];
406  int idx = 0;
407  for(const auto& x: point) {
408  if(idx < point.size()-1) {
409  temp_files[class_pos] << x << " ";
410  }else {
411  temp_files[class_pos] << x << std::endl;
412  }
413  idx++;
414  }
415  }
416 
417  for(i = 0; i < temp_files.size(); i++){
418  temp_files[i].close();
419  }
420  } else{
421  std::ofstream samples_file(std::string(plot_folder) + "samples.plt");
422 
423  for (i = 0; i < size; i++) {
424  for (j = 0; j < dim; j++) {
425  samples_file << (double) (samples->point(i)->X()[j]) << " ";
426  }
427  samples_file << (double) (samples->point(i)->Y()) << std::endl;
428  }
429 
430  samples_file.close();
431  std::string fname = (this->samples->name().empty())?"samples.plt":this->samples->name()+".plt";
432  file_names.emplace_back(std::string(plot_folder) + fname);
433  }
434  return file_names;
435  }
436 
437  template<typename T>
438  bool Visualization< T >::valid_file(std::string file){
439  int i = 0;
440  bool flag = false;
441  std::string ext;
442 
443  if(file.empty() || file.size() < 4)
444  return false;
445 
446  for(i = file.size()-1; i >= 0; i--){
447  if(file[i] == '.') break;
448  std::string f(1, file[i]);
449  ext = f + ext;
450  }
451 
452  for(std::string type : types){
453  if(type == ext) flag = true;
454  }
455 
456  return flag;
457  }
458 
459  template<typename T>
460  std::vector<std::string> Visualization< T >::getTempFilesNames(bool append_path){
461  std::vector<std::string> files;
462  auto path = std::string(plot_folder);
463 
464 #ifdef __unix__
465  DIR *dpdf;
466  struct dirent *epdf;
467 
468  dpdf = opendir(path.c_str());
469  if(dpdf != nullptr){
470  while((epdf = readdir(dpdf))){
471  std::string file = std::string(epdf->d_name);
472  if(valid_file(file) && !file.empty()){
473  files.push_back((append_path)?(path+file):file);
474  }
475  }
476  }else{
477  std::cout << "Folder not found!" << std::endl;
478  }
479 
480  closedir(dpdf);
481 #elif _WIN32
482  HANDLE hFind;
483  WIN32_FIND_DATA data;
484 
485  hFind = FindFirstFile((".\\"+plot_folder+"\\*.*").c_str(), &data);
486  if (hFind != INVALID_HANDLE_VALUE) {
487  do {
488  std::string file_name(data.cFileName);
489  if(valid_file(file_name) && !file_name.empty()){
490  files.push_back((append_path) ? (path + file_name) : file_name);
491  }
492  } while (FindNextFile(hFind, &data));
493  FindClose(hFind);
494  }
495 #else
496  std::cerr << "Can't remove temporary files, please remove manually. (Unsupported System)." << std::endl;
497 #endif
498 
499  return files;
500  }
501 
502  template<typename T>
503  void Visualization< T >::removeTempFiles(){
504  if(keep_temp_files) {
505  auto fname = this->plot_folder;
506  auto timestamp = mltk::utils::timestamp();
507  timestamp.erase(std::remove(timestamp.begin(), timestamp.end(), ':'));
508  fname.erase(std::remove(fname.begin(), fname.end(), '/'), fname.end());
509  try {
510  fs::rename(fname, fname + "_saved_" + timestamp);
511  }
512  catch (fs::filesystem_error const& ex) {
513  std::cout
514  << "what(): " << ex.what() << '\n'
515  << "path1(): " << ex.path1() << '\n'
516  << "path2(): " << ex.path2() << '\n'
517  << "code().value(): " << ex.code().value() << '\n'
518  << "code().message(): " << ex.code().message() << '\n'
519  << "code().category(): " << ex.code().category().name() << '\n';
520  }
521 
522  return;
523  }
524  std::string path;
525  std::vector<std::string> temps;
526 
527  temps = getTempFilesNames();
528 
529  for(const std::string& file : temps){
530  std::string _path = plot_folder + file;
531  if(fs::exists(_path)) fs::remove_all(_path);
532  }
533  if(fs::exists(plot_folder)) fs::remove_all(plot_folder);
534  if(!temp_fnames.empty()) {
535  for(const auto& file: temp_fnames) {
536  if(fs::exists(file)) {
537  fs::remove(file);
538  }
539  }
540  }
541  temp_fnames.clear();
542  }
543 
544  template<typename T>
545  std::string
546  Visualization<T>::plot1DRegresion(int x, bool save, double scale, const std::string &title, const std::string &format,
547  const std::string &x_label, const std::string &y_label) {
548  std::string dims = utils::itos(x+1) + ":" + utils::itos(2);
549  std::string cmd("plot ");
550  std::vector<std::string> temp_files_names;
551  size_t i;
552  std::string out_name = (this->samples->name().empty())?"2dplot_"+utils::itos(x)+"_regression":
553  this->samples->name()+"_2d_"+utils::itos(x)+"_regression";
554 
555  configureRange(scale, x);
556  configurePlot(out_name, format, title, save, x_label, y_label);
557 
558  temp_files_names = getTempFilesNames(true);
559  for(i = 0; i < temp_files_names.size() - 1; i++){
560  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " with points, ";
561  }
562  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " with points";
563 
564  cmd = execute_command(cmd);
565  return prepareScript(cmd);
566  }
567 
568  template<typename T>
569  std::string
570  Visualization<T>::plot1DRegresionHyperplane(int x, Solution s, bool save, double scale, const std::string &title,
571  const std::string &format, const std::string &x_label,
572  const std::string &y_label) {
573  std::string dims = utils::itos(x+1) + ":" + utils::itos(this->samples->dim()+1);
574  std::string fx, cmd;
575  std::vector<std::string> temp_files_names;
576  size_t i;
577  std::string out_name = (this->samples->name().empty())?"2dplot_"+utils::itos(x)+"_regression":
578  this->samples->name()+"_2d_"+utils::itos(x)+"_regression";
579 
580  configureRange(scale, x);
581  configurePlot(out_name, format, title, save, x_label, y_label);
582 
583  fx = "f(x) = " + utils::dtoa(s.w[x]) + "*x + " + utils::dtoa(s.bias);
584  cmd = fx + ";" + "plot ";
585 
586  temp_files_names = getTempFilesNames(true);
587  for(i = 0; i < temp_files_names.size() - 1; i++){
588  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " with points, ";
589  }
590  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " notitle with points, f(x) notitle with lines ls 1 lt rgb \"red\"";
591  cmd = fetchConfigs() + cmd;
592 
593  cmd = execute_command(cmd);
594  return prepareScript(cmd);
595  }
596 
597  template<typename T>
598  std::string Visualization< T >::plot2D(int x, int y, bool save, const double scale,
599  const std::string& title,
600  const std::string& format,
601  const std::string& x_label, const std::string& y_label){
602  std::string dims = utils::itos(x+1) + ":" + utils::itos(y+1);
603  std::string cmd("plot ");
604  std::vector<std::string> temp_files_names, class_names = samples->classesNames();
605  Point<int> classes = samples->classes();
606  size_t i;
607  std::string out_name = (this->samples->name().empty())?"2dplot_"+utils::itos(x)+"_"+utils::itos(y):
608  this->samples->name()+"_2d_"+utils::itos(x)+"_"+utils::itos(y);
609 
610  configureRange(scale, x, y);
611  configurePlot(out_name, format, title, save, x_label, y_label);
612 
613  temp_files_names = getTempFilesNames(true);
614  auto names = sortLabels(temp_files_names);
615  for(i = 0; i < temp_files_names.size() - 1; i++){
616  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " title \'" + names[i] + "\' with points, ";
617  }
618  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " title \'" + names[i] + "\' with points";
619 
620  cmd = execute_command(cmd);
621  return prepareScript(cmd);
622  }
623 
624  template<typename T>
625  std::string Visualization< T >::plot2D(mltk::Point<double> x, mltk::Point<double> y, bool save, const double scale,
626  const std::string& title,
627  const std::string& format,
628  const std::string& x_label, const std::string& y_label){
629  assert(x.size() == y.size() && "x and y must have the same size");
630  std::string cmd("plot ");
631  size_t i;
632  std::string out_name = (title.empty())?"2dplot_":"2dplot_"+title;
633 
634  configureRange(scale, x, y);
635  configurePlot(out_name, format, title, save, x_label, y_label);
636 
637  std::filesystem::path path{ "output" }; //creates TestingFolder object on C:
638  path /= out_name+".dat"; //put something into there
639  std::filesystem::create_directories(path.parent_path()); //add directories based on the object path (without this line it will not work)
640 
641  std::ofstream ofs(path);
642 
643  size_t size = x.size();
644 
645  for(int i = 0; i < size; i++){
646  ofs << x[i] << " " << y[i] << std::endl;
647  }
648 
649  ofs.close();
650 
651  cmd += "\'" + path.string() + "\' using 1:2 with linespoints";
652 
653  cmd = execute_command(cmd);
654  return prepareScript(cmd);
655 
656  }
657 
658  template<typename T>
659  std::string Visualization< T >::plot2DwithHyperplane(int x, int y, Solution s, bool save, const double scale,
660  const std::string& title,
661  const std::string& format,
662  const std::string& x_label, const std::string& y_label){
663  assert(samples->isClassification());
664  if(s.norm != s.norm) s.norm = 0.0;
665  std::string feats = utils::itos(x+1) + ":" + utils::itos(y+1);
666  std::string fx, gx, hx, cmd;
667  std::vector<std::string> temp_files_names, class_names = samples->classesNames();
668  size_t i;
669  std::string out_name = (this->samples->name().empty())?"2dplotsol_"+utils::itos(x)+"_"+utils::itos(y):
670  this->samples->name()+"_2dsol_"+utils::itos(x)+"_"+utils::itos(y);
671 
672  configureRange(scale, x, y);
673  configurePlot(out_name, format, title, save, x_label, y_label);
674 
675  if(s.margin == 0.0){
676  fx = "f(x) = " + utils::dtoa(-s.w[x]/s.w[y]) + "*x + " + utils::dtoa((s.bias)/-s.w[y]);
677  }else{
678  fx = "f(x) = " + utils::dtoa(-s.w[x]/s.w[y]) + "*x + " + utils::dtoa((s.bias)/-s.w[y]);
679  }
680  if(s.margin != 0) {
681  gx = "g(x) = " + utils::dtoa(-s.w[x]/s.w[y]) + "*x + " + utils::dtoa((s.bias + s.margin*s.norm)/-s.w[y]);
682  hx = "h(x) = " + utils::dtoa(-s.w[x]/s.w[y]) + "*x + " + utils::dtoa((s.bias - s.margin*s.norm)/-s.w[y]);
683  cmd = fx + ";"+ gx +";"+ hx +";plot ";
684  }else{
685  cmd = fx + ";plot ";
686  }
687  temp_files_names = getTempFilesNames(true);
688  auto names = sortLabels(temp_files_names);
689  for(i = 0; i < class_names.size() - 1; i++){
690  cmd += "\'" + temp_files_names[i] + "\' using " + feats + " title \'" + names[i] + "\' with points, ";
691  }
692  if(s.margin != 0) cmd += "\'" + temp_files_names[i] + "\' using " + feats + " title \'" + names[i] + "\' with points, f(x) notitle with lines ls 1, g(x) notitle with lines ls 2, h(x) notitle with lines ls 2";
693  else cmd += "\'" + temp_files_names[i] + "\' using " + feats + " title \'" + names[i] + "\' with points, f(x) title \'h(x)\' with lines ls 2";
694  std::cout << cmd << std::endl;
695 
696  cmd = execute_command(cmd);
697  return prepareScript(cmd);
698  }
699 
700 
701  template<typename T>
702  std::string Visualization<T>::plot2DRegresion(int x, int y, bool save, double scale, const std::string &title,
703  const std::string &format, const std::string &x_label,
704  const std::string &y_label, const std::string &z_label) {
705  std::string dims = utils::itos(x+1) + ":" + utils::itos(y+1) + ":" + utils::itos(this->samples->dim()+1);
706  std::string fx, cmd("splot ");
707  std::vector<std::string> temp_files_names;
708  size_t i;
709  std::string out_name = (this->samples->name().empty())?"2dplot_"+utils::itos(x)+"_regression":
710  this->samples->name()+"_2d_"+utils::itos(x)+"_regression";
711 
712  configureRange(scale, x);
713  configurePlot(out_name, format, title, save, x_label, y_label, z_label);
714 
715  temp_files_names = getTempFilesNames(true);
716  for(i = 0; i < temp_files_names.size() - 1; i++){
717  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " with points, ";
718  }
719  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " notitle with points";
720  cmd = execute_command(cmd);
721  return prepareScript(cmd);
722  }
723 
724  template<typename T>
725  std::string Visualization<T>::plot2DRegresionHyperplane(int x, int y, Solution s, bool save, double scale,
726  const std::string &title, const std::string &format,
727  const std::string &x_label, const std::string &y_label,
728  const std::string &z_label) {
729  std::string dims = utils::itos(x+1) + ":" + utils::itos(y+1) + ":" + utils::itos(this->samples->dim()+1);
730  std::string fxy, cmd;
731  std::vector<std::string> temp_files_names;
732  size_t i;
733  std::string out_name = (this->samples->name().empty())?"2dplot_"+utils::itos(x)+"_regression":
734  this->samples->name()+"_2d_"+utils::itos(x)+"_regression";
735 
736  configureRange(scale, x);
737  configurePlot(out_name, format, title, save, x_label, y_label, z_label);
738 
739  fxy = "f(x,y) = "+utils::dtoa(s.w[x])+"*x + "+utils::dtoa(s.w[y])+"*y + "+utils::dtoa(s.bias);
740  cmd = fxy + "; splot ";
741 
742  temp_files_names = getTempFilesNames(true);
743  for(i = 0; i < temp_files_names.size() - 1; i++){
744  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " with points, ";
745  }
746  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " notitle with points, f(x,y) notitle with lines ls 1 lt rgb \"red\"";
747  cmd = execute_command(cmd);
748  return prepareScript(cmd);
749  }
750 
751  template<typename T>
752  std::string Visualization< T >::plot3D(int x, int y, int z, bool save, const double scale,
753  const std::string& title,
754  const std::string& format,
755  const std::string& x_label, const std::string& y_label, const std::string& z_label){
756  std::string dims = utils::itos(x+1) + ":" + utils::itos(y+1) + ":" + utils::itos(z+1);
757  std::string cmd("splot ");
758  std::vector<std::string> temp_files_names, class_names = samples->classesNames();
759  size_t i;
760  std::string out_name = (this->samples->name().empty())?"3dplot_"+utils::itos(x)+"_"+utils::itos(y)+"_"+utils::itos(z):
761  this->samples->name()+"_3d_"+utils::itos(x)+"_"+utils::itos(y)+"_"+utils::itos(z);
762 
763  configureRange(scale, x, y, z);
764  configurePlot(out_name, format, title, save, x_label, y_label, z_label);
765 
766  temp_files_names = getTempFilesNames(true);
767  auto names = sortLabels(temp_files_names);
768  for(i = 0; i < class_names.size() - 1; i++){
769  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " title \'" + names[i] + "\' with points, ";
770  }
771  cmd += "\'" + temp_files_names[i] + "\' using " + dims + " title \'" + names[i] + "\' with points";
772  cmd = execute_command(cmd);
773  return prepareScript(cmd);
774  }
775 
776  template<typename T>
777  std::string Visualization< T >::plot3D(mltk::Point<double> x, mltk::Point<double> y, mltk::Point<double> z, bool save, const double scale,
778  const std::string& title,
779  const std::string& format,
780  const std::string& x_label, const std::string& y_label, const std::string& z_label){
781  assert(x.size() == y.size() && y.size() == z.size() && "x and y must have the same size");
782  std::string cmd("splot ");
783  size_t i;
784  std::string out_name = (title.empty())?"3dplot_":"3dplot_"+title;
785 
786  configureRange(scale, x, y);
787  configurePlot(out_name, format, title, save, x_label, y_label);
788 
789  std::filesystem::path path{ "output" }; //creates TestingFolder object on C:
790  path /= out_name+".dat"; //put something into there
791  std::filesystem::create_directories(path.parent_path()); //add directories based on the object path (without this line it will not work)
792 
793  std::ofstream ofs(path);
794 
795  size_t size = x.size();
796 
797  for(int i = 0; i < size; i++){
798  ofs << x[i] << " " << y[i] << " " << z[i] << std::endl;
799  }
800 
801  ofs.close();
802 
803  cmd += "\'" + path.string() + "\' using 1:2:3 with points";
804 
805  cmd = execute_command(cmd);
806  return prepareScript(cmd);
807  }
808 
809  template<typename T>
810  std::string Visualization< T >::plot3DwithHyperplane(int x, int y, int z, Solution s, bool save, const double scale,
811  const std::string& title,
812  const std::string& format,
813  const std::string& x_label, const std::string& y_label,
814  const std::string& z_label){
815  assert(samples->isClassification());
816  std::string feats = utils::itos(x+1) + ":" + utils::itos(y+1) + ":" + utils::itos(z+1);
817  std::string fxy, gxy, hxy, cmd;
818  std::vector<std::string> temp_files_names, class_names = samples->classesNames();
819  size_t i;
820  std::string out_name = (this->samples->name().empty())?"3dplotsol_"+utils::itos(x)+"_"+utils::itos(y)+"_"+utils::itos(z):
821  this->samples->name()+"_3dsol_"+utils::itos(x)+"_"+utils::itos(y)+"_"+utils::itos(z);
822 
823  configureRange(scale, x, y, z);
824  configurePlot(out_name, format, title, save, x_label, y_label, z_label);
825 
826  gxy = "g(x,y) = "+utils::dtoa(-s.w[x]/s.w[z])+"*x + "+utils::dtoa(-s.w[y]/s.w[z])+"*y + "+utils::dtoa((s.bias + s.margin * s.norm)/-s.w[z]);
827  fxy = "f(x,y) = "+utils::dtoa(-s.w[x]/s.w[z])+"*x + "+utils::dtoa(-s.w[y]/s.w[z])+"*y + "+utils::dtoa(s.bias/-s.w[z]);
828  hxy = "h(x,y) = "+utils::dtoa(-s.w[x]/s.w[z])+"*x + "+utils::dtoa(-s.w[y]/s.w[z])+"*y + "+utils::dtoa((s.bias - s.margin * s.norm)/-s.w[z]);
829  cmd = gxy + ";" + fxy + ";" + hxy + "; splot ";
830 
831  temp_files_names = getTempFilesNames(true);
832  auto names = sortLabels(temp_files_names);
833  for(i = 0; i < class_names.size() - 1; i++){
834  cmd += "\'" + temp_files_names[i] + "\' using " + feats + " title \'" + names[i] + "\' with points, ";
835  }
836  cmd += "\'" + temp_files_names[i] + "\' using " + feats + " title \'" + names[i] + "\' with points, ";
837  cmd += "g(x,y) notitle with lines ls 1 lt rgb \"red\",";
838  cmd += "f(x,y) notitle with lines ls 1,";
839  cmd += "h(x,y) notitle with lines ls 1 lt rgb \"red\";";
840  execute_command(cmd);
841  return prepareScript(cmd);
842  }
843 
844  template<typename T>
845  template<class Learner>
846  std::string Visualization< T >::plotDecisionSurface2D(Learner& learner, int x, int y, bool is_trained, size_t grid_dim,
847  bool save, const double scale, const std::string& title, const std::string& format,
848  const std::string& x_label, const std::string& y_label){
849  assert(samples->isClassification());
850  configurePlot("contour_"+this->samples->name()+"_"+mltk::utils::timestamp(), format, title, save,
851  x_label, y_label);
852  AxisRanges axis_ranges = configureRange(scale, x, y);
853  mltk::Point<int> classes(this->samples->classes());
854  mltk::Point xx = mltk::linspace(axis_ranges[0].min, axis_ranges[0].max, grid_dim);
855  mltk::Point yy = mltk::linspace(axis_ranges[1].min, axis_ranges[1].max, grid_dim);
856  mltk::Data grid(grid_dim, grid_dim,0);
857  auto data_copy = this->samples->selectFeatures({size_t(x+1), size_t(y+1)});
858  auto timestamp = mltk::utils::timestamp();
859  timestamp.erase(std::remove(timestamp.begin(), timestamp.end(), ':'), timestamp.end());
860 
861  learner.setSamples(data_copy);
862  if(!is_trained) learner.train();
863 
864  std::string data_fname = this->plot_folder+data_copy.name()+"_"+ timestamp +".dat";
865  std::ofstream data_file(data_fname);
866  if(!data_file.is_open()){
867  std::cerr << "Error opening file (" << data_fname << ")" << std::endl;
868  return "";
869  }
870  for(int i = 0; i < grid.size(); i++){
871  int j;
872  for(j = 0; j < grid.dim(); j++){
873  grid(i)[j] = learner.evaluate(mltk::Point({xx[i], yy[j]}));
874  data_file << xx[i] << " " << yy[j] << " " << std::to_string(grid(i)[j]) << std::endl;
875  }
876  data_file << std::endl;
877  }
878  data_file.close();
879 
880  std::string dims = utils::itos(1) + ":" + utils::itos(2)+":(0)";
881  std::string scatter_cmd;
882  std::vector<std::string> temp_files_names, class_names = this->samples->classesNames();
883  std::vector<std::ofstream> classes_files(classes.size());
884 
885  for(int i = 0; i < classes_files.size(); i++){
886  std::string fname = this->plot_folder+class_names[i]+"_data"+ timestamp +".dat";
887  classes_files[i].open(fname);
888  if (!classes_files[i].is_open()) {
889  std::cerr << "Error opening file (" << fname << ")" << std::endl;
890  return "";
891  }
892  temp_files_names.push_back(fname);
893  }
894 
895  for(int i = 0; i < data_copy.size(); i++){
896  auto class_pos = std::find(classes.begin(), classes.end(), data_copy(i).Y()) - classes.begin();
897  classes_files[class_pos] << data_copy(i)[0] << " " << data_copy(i)[1] << " " << data_copy(i).Y() << std::endl;
898  }
899  for(auto & classes_file : classes_files){
900  classes_file.close();
901  }
902  auto names = sortLabels(temp_files_names, "decision");
903  for(int i = 0; i < temp_files_names.size(); i++){
904  if(i < classes_files.size()-1) {
905  scatter_cmd += "'" + temp_files_names[i] + "' title '"+ names[i] +"' with points,";
906  }else{
907  scatter_cmd += "'" + temp_files_names[i] + "' title '"+ names[i] +"' with points;";
908  }
909  }
910 
911  std::string cmd;
912  cmd += fetchConfigs();
913  cmd += "set pm3d map;";
914  cmd += "set pm3d interpolate 0,0;";
915  cmd += "set cbrange [" + std::to_string(mltk::min(classes)) +":" + std::to_string(mltk::max(classes)) + "];";
916  cmd += "set cbtics 1;";
917  cmd += "set palette rgbformulae 22,13,10;";
918  cmd += "splot '"+data_fname+"', " + scatter_cmd;
919  temp_files_names.push_back(data_fname);
920  cmd = execute_command(cmd, false);
921  temp_fnames.insert(temp_fnames.begin(), temp_files_names.begin(), temp_files_names.end());
922  return prepareScript(cmd);
923  }
924 
925  template<typename T>
927  this->samples = &sample;
928  if(fs::exists(plot_folder)) {
929  removeTempFiles();
930  }
931  create_plotfolder();
932  createTempFiles();
933  }
934 
935  template<typename T>
936  std::vector<std::string> Visualization<T>::sortLabels(std::vector<std::string> &files, const std::string& type) {
937  Point<int> classes = samples->classes();
938  auto class_names = samples->classesNames();
939  std::vector<std::string> names(files.size());
940  std::transform(files.begin(), files.end(), names.begin(), [type](std::string& path){
941  if(type == "decision") {
942  auto res = mltk::utils::tokenize(mltk::utils::tokenize(path, '_')[0], '/');
943  return mltk::utils::tokenize(mltk::utils::tokenize(path, '_')[0], '/')[1];
944  }else{
945  return mltk::utils::tokenize(mltk::utils::tokenize(path, '.')[0], '/')[1];
946  }
947  });
948  std::sort(names.begin(), names.end(),[&class_names, &classes](const auto& a, const auto& b){
949  auto aclass_pos = std::find(class_names.begin(), class_names.end(), a) - class_names.begin();
950  auto bclass_pos = std::find(class_names.begin(), class_names.end(), b) - class_names.begin();
951  return classes[aclass_pos] < classes[bclass_pos];
952  });
953  std::sort(files.begin(), files.end(), [&class_names, &classes, &type](const auto& a, const auto& b){
954  if(type == "decision") {
955  auto aclass_pos = std::find(class_names.begin(), class_names.end(),
956  mltk::utils::tokenize(mltk::utils::tokenize(a, '_')[0], '/')[1]) - class_names.begin();
957  auto bclass_pos = std::find(class_names.begin(), class_names.end(),
958  mltk::utils::tokenize(mltk::utils::tokenize(b, '_')[0], '/')[1]) - class_names.begin();
959  return classes[aclass_pos] < classes[bclass_pos];
960  }else{
961  auto aclass_pos = std::find(class_names.begin(), class_names.end(),
962  mltk::utils::tokenize(mltk::utils::tokenize(a, '.')[0], '/')[1]) - class_names.begin();
963  auto bclass_pos = std::find(class_names.begin(), class_names.end(),
964  mltk::utils::tokenize(mltk::utils::tokenize(b, '.')[0], '/')[1]) - class_names.begin();
965  return classes[aclass_pos] < classes[bclass_pos];
966  }
967  });
968  return names;
969  }
970 
971  template<typename T>
972  void
973  Visualization<T>::configurePlot(const std::string &outname, const std::string &format, const std::string &title, bool save,
974  const std::string& x_label, const std::string& y_label, const std::string& z_label) {
975  configs["save"] = (save)?"true":"false";
976  configs["output_name"] = outname;
977  configs["output_format"] = format;
978  configs["title"] = (title.empty())?"":title;
979  configs["x_label"] = (x_label.empty())?"":x_label;
980  configs["y_label"] = (y_label.empty())?"":y_label;
981  configs["z_label"] = (z_label.empty())?"":z_label;
982  }
983 
984  template<typename T>
985  std::string Visualization<T>::fetchConfigs() {
986  std::string confs;
987  if(configs["save"] == "true") {
988  confs += std::string("set terminal ") + configs["output_format"]+"; ";
989  confs += std::string("set output '") + configs["output_name"] +"." + configs["output_format"]+"'; ";
990  }else if(!configs["terminal"].empty()){
991  confs += std::string("set terminal ") + configs["terminal"]+";";
992  }else {
993  confs += std::string("set terminal x11;");
994  }
995  if(!configs["title"].empty()) {
996  confs += std::string("set title '") + configs["title"] + "';";
997  }
998  if(!configs["xrange"].empty()) {
999  confs += "set xrange " + configs["xrange"] + ";";
1000  configs["xrange"].clear();
1001  }
1002  if(!configs["yrange"].empty()) {
1003  confs += "set yrange " + configs["yrange"] + ";";
1004  configs["yrange"].clear();
1005  }
1006  if(!configs["zrange"].empty()) {
1007  confs += "set zrange " + configs["zrange"] + ";";
1008  configs["zrange"].clear();
1009  }
1010  if(!configs["x_label"].empty()) {
1011  confs += std::string("set xlabel '") + configs["x_label"] + "';";
1012  }
1013  if(!configs["y_label"].empty()) {
1014  confs += std::string("set ylabel '") + configs["y_label"] + "';";
1015  }
1016  if(!configs["z_label"].empty()) {
1017  confs += std::string("set zlabel '") + configs["z_label"] + "';";
1018  }
1019  return confs;
1020  }
1021 
1022  template<typename T>
1023  Visualization< T >::~Visualization(){
1024  this->samples = nullptr;
1025  delete g;
1026  g = nullptr;
1027  removeTempFiles();
1028  for(auto& pfolder: plot_folders) {
1029  try {
1030  if (fs::exists(pfolder)) {
1031  fs::remove_all(pfolder);
1032  }
1033  }
1034  catch (fs::filesystem_error const& ex) {
1035  std::cout
1036  << "what(): " << ex.what() << '\n'
1037  << "path1(): " << ex.path1() << '\n'
1038  << "path2(): " << ex.path2() << '\n'
1039  << "code().value(): " << ex.code().value() << '\n'
1040  << "code().message(): " << ex.code().message() << '\n'
1041  << "code().category(): " << ex.code().category().name() << '\n';
1042  }
1043  }
1044  plot_folders.clear();
1045  }
1046 
1047  template<typename T>
1048  void Visualization<T>::cmd(const std::string &command) {
1049  Gnuplot g;
1050 
1051  g.cmd(command);
1052  }
1053 
1054  template<typename T>
1055  typename Visualization<T>::AxisRanges Visualization<T>::configureRange(const double scale, const int x,
1056  const int y, const int z) {
1057  AxisRanges axis_ranges;
1058  if(x > -1) {
1059  auto _x = this->samples->getFeature(x);
1060  double x_min = mltk::min(_x), x_max = scale*mltk::max(_x);
1061  x_min += (x_min > 0)?(1.0-scale)*x_min:-(1.0-scale)*x_min;
1062  axis_ranges[0].min = std::round(x_min);
1063  axis_ranges[0].max = std::round(x_max);
1064  configs["xrange"] = "[" + std::to_string(axis_ranges[0].min) + ":" + std::to_string(axis_ranges[0].max) + "]";
1065  }
1066  if(y > -1) {
1067  auto _y = this->samples->getFeature(y);
1068  double y_min = mltk::min(_y), y_max = scale*mltk::max(_y);
1069  y_min += (y_min > 0)?(1.0-scale)*y_min:-(1.0-scale)*y_min;
1070  axis_ranges[1].min = std::round(y_min);
1071  axis_ranges[1].max = std::round(y_max);
1072  configs["yrange"] = "[" + std::to_string(axis_ranges[1].min) + ":" + std::to_string(axis_ranges[1].max) + "]";
1073  }
1074  if(z > -1) {
1075  auto _z = this->samples->getFeature(z);
1076  double z_min = mltk::min(_z), z_max = scale*mltk::max(_z);
1077  z_min += (z_min > 0)?(1.0-scale)*z_min:-(1.0-scale)*z_min;
1078  axis_ranges[2].min = std::round(z_min);
1079  axis_ranges[2].max = std::round(z_max);
1080  configs["zrange"] = "[" + std::to_string(axis_ranges[2].min) + ":" + std::to_string(axis_ranges[2].max) + "]";
1081  }
1082  return axis_ranges;
1083  }
1084 
1085  template<typename T>
1086  typename Visualization<T>::AxisRanges Visualization<T>::configureRange(const double scale, const mltk::Point<double> x,
1087  const mltk::Point<double> y, const mltk::Point<double> z) {
1088  AxisRanges axis_ranges;
1089  if(x.size() > 0) {
1090  auto _x = x;
1091  double x_min = mltk::min(_x), x_max = scale*mltk::max(_x);
1092  x_min += (x_min > 0)?(1.0-scale)*x_min:-(1.0-scale)*x_min;
1093  axis_ranges[0].min = std::round(x_min);
1094  axis_ranges[0].max = std::round(x_max);
1095  if(axis_ranges[0].min != axis_ranges[0].max) configs["xrange"] = "[" + std::to_string(axis_ranges[0].min) + ":" + std::to_string(axis_ranges[0].max) + "]";
1096  }
1097  if(y.size() > 0) {
1098  auto _y = y;
1099  double y_min = mltk::min(_y), y_max = scale*mltk::max(_y);
1100  y_min += (y_min > 0)?(1.0-scale)*y_min:-(1.0-scale)*y_min;
1101  axis_ranges[1].min = std::round(y_min);
1102  axis_ranges[1].max = std::round(y_max);
1103  if(axis_ranges[1].min != axis_ranges[1].max) configs["yrange"] = "[" + std::to_string(axis_ranges[1].min) + ":" + std::to_string(axis_ranges[1].max) + "]";
1104  }
1105  if(z.size() > 0) {
1106  auto _z = z;
1107  double z_min = mltk::min(_z), z_max = scale*mltk::max(_z);
1108  z_min += (z_min > 0)?(1.0-scale)*z_min:-(1.0-scale)*z_min;
1109  axis_ranges[2].min = std::round(z_min);
1110  axis_ranges[2].max = std::round(z_max);
1111  if(axis_ranges[2].min != axis_ranges[2].max) configs["zrange"] = "[" + std::to_string(axis_ranges[2].min) + ":" + std::to_string(axis_ranges[2].max) + "]";
1112  }
1113  return axis_ranges;
1114  }
1115 
1116  template<typename T>
1117  std::string Visualization<T>::prepareScript(std::string cmd) {
1118  std::replace(cmd.begin(), cmd.end(), ';', '\n');
1119  return cmd;
1120  }
1121 
1122  template<typename T>
1123  std::string Visualization<T>::execute_command(const std::string& _cmd, bool fetch_configs) {
1124  auto cmd = (fetch_configs)?fetchConfigs() + _cmd:_cmd;
1125 #ifdef __unix__
1126  if(is_shared) {
1127  g->cmd(cmd);
1128  }else {
1129  Gnuplot g_;
1130  g_.cmd(cmd);
1131  }
1132 #elif _WIN32
1133  cmd = "set terminal windows; " + cmd;
1134  cmd = "echo " + cmd + " | gnuplot -persist";
1135  system(cmd.c_str());
1136 #endif
1137  return cmd;
1138  }
1139 }
1140 #endif
Definition: gnuplot_i.hpp:70
Gnuplot & cmd(const std::string &cmdstr)
send a command to gnuplot
Definition: gnuplot_i.cpp:891
size_t size() const
Returns the size of the dataset.
Definition: Data.hpp:208
size_t dim() const
Returns the dimension of the dataset.
Definition: Data.hpp:213
Definition: Learner.hpp:18
virtual void setSamples(const Data< T > &data)
setSamples Set the samples used by the Learner.
Definition: Learner.hpp:150
virtual bool train()=0
Function that execute the training phase of a Learner.
virtual double evaluate(const Point< T > &p, bool raw_value=false)=0
Returns the class of a feature point based on the trained Learner.
std::size_t size() const
Returns the dimension of the point.
Definition: Point.hpp:133
Definition: Solution.hpp:13
double bias
Bias of the solution.
Definition: Solution.hpp:23
double norm
Norm of the solution.
Definition: Solution.hpp:29
mltk::Point< double > w
Weights vector.
Definition: Solution.hpp:17
double margin
Margin generated from the classifier that generated the solution.
Definition: Solution.hpp:27
Class for data visualization.
Definition: Visualization.hpp:39
std::string plot2DwithHyperplane(int x, int y, Solution w, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y")
Plot the data in 2D with the hyperplane in solution generated by a classifier.
Definition: Visualization.hpp:659
std::string plot3D(int x=0, int y=1, int z=2, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y", const std::string &z_label="z")
Plot the selected features in 3D.
Definition: Visualization.hpp:752
void setStyle(std::string style)
Set plot style. (points, lines, etc.)
Definition: Visualization.hpp:375
std::string plot2D(int x=0, int y=1, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y")
Plot the selected features in 2D.
Definition: Visualization.hpp:598
static void cmd(const std::string &command)
Execute a script on gnuplot.
Definition: Visualization.hpp:1048
std::string plot1DRegresion(int x=0, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y")
Plot the data as a regression dataset with points values in the y-axis.
Definition: Visualization.hpp:546
std::string plotDecisionSurface2D(Learner &learner, int x=0, int y=1, bool is_trained=true, size_t grid_dim=50, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y")
Plot the decision boundary of a classifier with the data points above it.
Definition: Visualization.hpp:846
std::string plot3DwithHyperplane(int x, int y, int z, Solution w, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y", const std::string &z_label="z")
Plot the data in 2D with separated by the hyperplane in the solution.
Definition: Visualization.hpp:810
std::string plot2DRegresion(int x=0, int y=1, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y", const std::string &z_label="z")
Plot the data as a regression dataset with points values in the z-axis.
Definition: Visualization.hpp:702
void setSample(Data< T > &sample)
Set sample to be visualized.
Definition: Visualization.hpp:926
std::string plot2DRegresionHyperplane(int x, int y, Solution s, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y", const std::string &z_label="z")
Plot the data as a regression dataset with points values in the z-axis alongside with a regressor sol...
Definition: Visualization.hpp:725
std::string plot1DRegresionHyperplane(int x, Solution s, bool save=false, double scale=1.0, const std::string &title="", const std::string &format="svg", const std::string &x_label="x", const std::string &y_label="y")
Plot the data as a regression dataset with points values in the y-axis alongside with a regressor sol...
Definition: Visualization.hpp:570
void setTitle(std::string title)
Set plot title.
Definition: Visualization.hpp:370
Namespace for data visualization methods.
Definition: Visualization.hpp:34
T min(const Point< T, R > &p)
Returns the min value of the point.
Definition: Point.hpp:557
T max(const Point< T, R > &p)
Returns the max value of the point.
Definition: Point.hpp:544