OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
 
Loading...
Searching...
No Matches
GoogleChart.hpp
1/*
2 * GoogleChart.hpp
3 *
4 * Created on: Jan 9, 2016
5 * Author: i-bird
6 */
7
8#ifndef OPENFPM_DATA_SRC_PLOT_GOOGLECHART_HPP_
9#define OPENFPM_DATA_SRC_PLOT_GOOGLECHART_HPP_
10
11#include <fstream>
12#include "Vector/map_vector.hpp"
13#include <cmath>
14
15#define GGRAPH_COLUMS 1
16#define GGRAPH_POINTS 2
17
18#define GC_ZOOM std::string("explorer: {actions: ['dragToZoom', 'rightClickToReset'],axis: 'horizontal,vertical',keepInBounds: true, maxZoomIn: 128.0}")
19#define GC_X_LOG std::string("hAxis: { logScale: true }")
20#define GC_Y_LOG std::string("vAxis: { logScale: true }")
21
26{
28 std::string title;
30 std::string yAxis;
32 std::string xAxis;
33
38 std::string stype;
39
43 std::string stypeext;
44
46 size_t width=900;
47
49 size_t heigh=500;
50
53 bool isStacked = false;
54
56 size_t lineWidth = 4;
57
60 std::string intervalsext;
61
64 std::string intervalext;
65
67 std::string more;
68
70 std::string curveType = "function";
71
73 bool barWD = false;
74
83 {
84 title = opt.title;
85 yAxis = opt.yAxis;
86 xAxis = opt.xAxis;
87 stype = opt.stype;
88 stypeext = opt.stypeext;
89 width=opt.width;
90 heigh=opt.heigh;
91
92 lineWidth = opt.lineWidth;
94 more = opt.more;
95
96 return *this;
97 }
98};
99
103struct GGraph
104{
106 size_t type;
107
109 std::string data;
110
112 std::string option;
113
115 std::string view;
116
119};
120
122
123const std::string begin_data ="<html>\n\
124 <head>\n\
125 <script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>\n\
126 <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js\"></script>\n\
127 <script type=\"text/javascript\">\n\
128 google.charts.load('current', {'packages':['corechart']});\n\
129 google.charts.setOnLoadCallback(drawVisualization);\n\
130\n\
131function exportToSVG(i)\n\
132{\n\
133var e = document.getElementById('chart_div'+i);\n\
134var svg = e.getElementsByTagName('svg')[0].parentNode.innerHTML;\n\
135var pos = svg.lastIndexOf(\"</svg>\");\n\
136pos += 6;\n\
137svg = svg.substring(0,4) + \" xmlns='http://www.w3.org/2000/svg' xmlns:xlink= 'http://www.w3.org/1999/xlink' \" + svg.substring(4,pos);\n\
138svgData = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);\n\
139$(this).attr({'href': svgData,'target': '_blank'});\n\
140}\n\
141\n\
142 function drawVisualization() {\n";
143
144const std::string end_data="]);\n\n";
145
146const std::string begin_div = "}</script>\n\
147</head>\n\
148<body>\n";
149
150const std::string div_end = "</body>\n\
151</html>\n";
152
153const std::string saving_javascript = "function save(i)\n\
154 var e = document.getElementById('chart_')\n\
155 e.getElementsByTagName('svg')[0].parentNode.innerHTML";
156
157template<typename T>
159{
160 static bool check(const T & n)
161 {
162 return false;
163 }
164};
165
166template<>
167struct check_nan<float>
168{
169 static bool check(const float & n)
170 {
171 return std::isnan(n);
172 }
173};
174
175template<>
176struct check_nan<double>
177{
178 static bool check(const double & n)
179 {
180 return std::isnan(n);
181 }
182};
183
185
216{
217 template<typename arg_0, typename ... args>
219 {
220 typedef typename arg_0::value_type type;
221 };
222
225
228
230 bool holes = false;
231
239 template<typename X, typename ... Xs>
240 void recursive_sort(X & x,X & y,Xs& ... xy)
241 {
242 struct srt_xy
243 {
244 typename X::value_type x;
245 unsigned int id;
246
247 bool operator<(const srt_xy & tmp) const
248 {
249 return x < tmp.x;
250 }
251 };
252
254 X y_tmp;
255
256 reord.resize(x.size());
257 y_tmp.resize(x.size());
258
259 for (size_t i = 0 ; i < x.size() ; i++)
260 {
261 reord.get(i).x = x.get(i);
262 reord.get(i).id = i;
263 }
264
265 reord.sort();
266
267 // reorder x and y
268
269 for (size_t i = 0 ; i < x.size() ; i++)
270 {
271 x.get(i) = reord.get(i).x;
272 y_tmp.get(i) = y.get(reord.get(i).id);
273 }
274
275 y_tmp.swap(y);
276
277 // sort x
278
279 recursive_sort(xy ...);
280 }
281
284 {}
285
294 template<typename X, typename ... Xs>
295 bool isNext(size_t * counters,X & x,X & y,Xs& ... xy)
296 {
297 if (counters[0] < x.size())
298 {
299 return true;
300 }
301 return isNext(&counters[1],xy ...);
302 }
303
309 bool isNext(size_t * counters)
310 {
311 return false;
312 }
313
314
323 template<typename T, typename X, typename ... Xs>
324 T get_low(size_t * counters,X & x,X & y,Xs& ... xy)
325 {
326 if (sizeof...(Xs) != 0)
327 {
328 T low1;
329 if (counters[0] >= x.size())
330 {low1 = std::numeric_limits<typename X::value_type>::infinity();}
331 else
332 {low1 = x.get(counters[0]);}
333
334 T low2 = get_low<T>(&counters[1],xy ...);
335 return (low1 < low2)?low1:low2;
336 }
337
338 if (counters[0] >= x.size())
339 {return std::numeric_limits<typename X::value_type>::infinity();}
340 return x.get(counters[0]);
341 }
342
348 template<typename T>
349 T get_low(size_t * counters)
350 {
351 return 0.0;
352 }
353
361 template<typename X, typename ... Xs>
362 void get_point(typename X::value_type low,
363 typename X::value_type * point,
364 size_t * counters,
365 X & x,
366 X & y,
367 Xs& ... xy)
368 {
369 if (counters[0] < x.size() && low == x.get(counters[0]))
370 {
371 point[0] = y.get(counters[0]);
372 counters[0]++;
373 }
374 else
375 {
376 point[0] = std::numeric_limits<typename X::value_type>::quiet_NaN();
377 }
378
379 get_point(low,&point[1],&counters[1],xy...);
380 }
381
389 template<typename T>
390 void get_point(T low,
391 T * point,
392 size_t * counters)
393 {
394 return;
395 }
396
404 template<typename ... Xs>
405 bool get_v(typename get_value_type<Xs...>::type & x,
406 typename get_value_type<Xs...>::type * point,
407 size_t * counters,
408 Xs& ... xy)
409 {
410 // if exist the next element
411 if (isNext(counters,xy...) == false)
412 {return false;}
413
414 // get lowest x
415 typename get_value_type<Xs...>::type low = get_low<typename get_value_type<Xs...>::type>(counters,xy...);
416
417 x = low;
418
419 get_point(low,point,counters,xy...);
420
421 return true;
422 }
423
438 template<typename X, typename Y> std::string get_points_plot_data(const openfpm::vector<X> & x, const openfpm::vector<Y> & y, const openfpm::vector<std::string> & yn, const GCoptions & opt, size_t i)
439 {
440 std::stringstream data;
441
442 size_t interval = 0;
443
444 // we require that the number of x elements are the same as y elements
445
446 if (x.size() != y.size())
447 {std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " vector x and the vector y must have the same number of elements " << x.size() << "!=" << y.size() << "\n";}
448
449 // Google chart visualization
450 data << "var data" << i << " = new google.visualization.DataTable();\n";
451 if (std::is_same<X,typename std::string>::value == true)
452 data << "data" << i << ".addColumn(" << "'string'" << "," << "'" << opt.xAxis <<"');\n";
453 else
454 data << "data" << i << ".addColumn(" << "'number'" << "," << "'" << opt.xAxis <<"');\n";
455
456 for (size_t j = 0 ; j < y.last().size() ; j++)
457 {
458 if (yn.get(j) == std::string("interval"))
459 {
460 data << "data" << i << ".addColumn({id:'i" << interval/2 << "', type:'number', role:'interval'});\n";
461 interval++;
462 }
463 else
464 data << "data" << i << ".addColumn(" << "'number'" << "," << "'" << yn.get(j) <<"');\n";
465 }
466
467 data << "data" << i << ".addRows([\n";
468 for (size_t i = 0 ; i < y.size() && x.size() ; i++)
469 {
470
471 for (size_t j = 0 ; j < y.get(i).size()+1 ; j++)
472 {
473 // the first is x
474 if (j == 0)
475 {
476 if (std::is_same<X,typename std::string>::value == true)
477 data << "['" << x.get(i) << "'";
478 else
479 data << "[" << x.get(i);
480 }
481 else
482 {
483 if (check_nan<typename Y::value_type>::check(y.get(i).get(j-1)) == false)
484 {
485 data << "," << y.get(i).get(j-1);
486 }
487 else
488 {
489 holes = true;
490 data << "," << "null";
491 }
492 }
493 }
494 data << "],\n";
495 }
496
497 return data.str();
498 }
499
507 std::string get_view_bar_option(const GCoptions & opt, size_t n_col)
508 {
509 if (opt.barWD == false)
510 return std::string();
511
512 std::stringstream str;
513
514 str << "[0" << std::endl;
515
516 for (size_t i = 1 ; i < n_col ; i++)
517 {
518 str << "," << i << ",{ calc: \"stringify\"," << std::endl;
519 str << "sourceColumn: " << i << "," << std::endl;
520 str << "type: \"string\"," << std::endl;
521 str << "role: \"annotation\" }"<< std::endl;
522 }
523
524 str << "]" << std::endl;
525
526 return str.str();
527 }
528
529 std::string get_colums_bar_option(const GCoptions & opt)
530 {
531 std::stringstream str;
532 str << "title : '" << opt.title << "'";
533 str << ",\nvAxis: {title: '" << opt.yAxis << "'}";
534 str << ",\nhAxis: {title: '" << opt.xAxis << "'}";
535 str << ",\nseriesType: '" << opt.stype << "'";
536 if (opt.stypeext.size() != 0)
537 str << ",\nseries: " << opt.stypeext;
538 if (opt.more.size() != 0)
539 str << ",\n" <<opt.more;
540
541 return str.str();
542 }
543
544 std::string get_points_plot_option(const GCoptions & opt)
545 {
546 std::stringstream str;
547 str << "title : '" << opt.title << "'";
548 str << ",\nvAxis: {title: '" << opt.yAxis << "'}";
549 str << ",\nhAxis: {title: '" << opt.xAxis << "'}";
550 str << ",\ncurveType: '"<< opt.curveType << "'";
551
552 str << ",\nlineWidth: " << opt.lineWidth;
553 if (opt.intervalsext.size() != 0)
554 str << ",\nintervals: " << opt.intervalsext;
555 else
556 str << ",\nintervals: " << "{ 'style':'area' }";
557
558 if (opt.intervalext.size() != 0)
559 str << ",\ninterval: " << opt.intervalext << "\n";
560
561 if (opt.more.size() != 0)
562 str << ",\n" << opt.more;
563
564 return str.str();
565 }
566
574 void addData(std::ofstream & of, size_t i, const std::string & data)
575 {
576
577 of << data;
578 of << "]);\n";
579 }
580
588 void addOption(std::ofstream & of, size_t i, const std::string & opt)
589 {
590 of << "var options";
591 of << i;
592 of << "= {\n";
593 if (holes == true)
594 {of << "interpolateNulls : true,\n";}
595 of << opt;
596 of << "};\n";
597 }
598
606 void addView(std::ofstream & of, size_t i, std::string view)
607 {
608 if (view.size() == 0)
609 return;
610
611 of << "var view" << i << " = new google.visualization.DataView(data" << i << ");" << std::endl;
612 of << "view"<< i << ".setColumns(";
613 of << view << ");" << std::endl;
614 }
615
623 void addDrawDiv(std::ofstream & of, size_t i, bool draw_view)
624 {
625 of << "$(\"#export_svg" << i << "\").on(\"click\", function (event) {exportToSVG.apply(this,[" << i << "]);});\n";
626 of << "var chart = new google.visualization.ComboChart(document.getElementById('chart_div";
627 of << i;
628 of << "'));" << std::endl;
629 if (draw_view == true)
630 {
631 of << "chart.draw(data";
632 of << i;
633 }
634 else
635 {
636 of << "chart.draw(view";
637 of << i;
638 }
639 of << ", options";
640 of << i;
641 of << ");\n";
642 }
643
651 void addDiv(std::ofstream & of, size_t i, const GCoptions & gc)
652 {
653 of << "<a href=\"#\" download=\"graph1.svg\" id=\"export_svg" << i << "\"><button>Export data into svg</button></a>";
654 of << "<div id=\"chart_div";
655 of << i;
656 of << "\" style=\"width: ";
657 of << gc.width;
658 of << "px; height: ";
659 of << gc.heigh;
660 of << "px;\"></div>\n";
661 }
662
663public:
664
666 {
667 injectHTML.add();
668 }
669
676 template<typename Y> void AddHistGraph(openfpm::vector<Y> & y)
677 {
679 x.resize(y.size());
680
681 AddHistGraph<std::string,Y>(x,y);
682 }
683
692 template<typename X, typename Y> void AddHistGraph(openfpm::vector<X> & x, openfpm::vector<Y> & y)
693 {
694 GCoptions opt;
695
697
698 if (y.size() != 0)
699 yn.resize(y.get(0).size());
700
701 AddHistGraph<X,Y,std::string>(x,y,yn,opt);
702 }
703
714 template<typename X, typename Y, typename Yn> void AddHistGraph(openfpm::vector<X> & x, openfpm::vector<Y> & y, openfpm::vector<Yn> & yn)
715 {
716 GCoptions opt;
717
718 AddHistGraph(x,y,yn,opt);
719 }
720
733 template<typename X, typename Y, typename Yn> void AddHistGraph(openfpm::vector<X> & x, openfpm::vector<Y> & y, openfpm::vector<Yn> & yn , const GCoptions & opt)
734 {
735 set_of_graphs.add();
736 injectHTML.add();
737
738 // Check that all the internal vector has the same number of elements
739
740 if (y.size() != 0)
741 {
742 size_t sz = y.get(0).size();
743 for (size_t i = 0; i < y.size() ; i++)
744 {
745 if (y.get(i).size() != sz)
746 std::cerr << __FILE__ << ":" << __LINE__ << " error all the elements in the y vector must have the same numbers, element " << i << ": " << y.get(i).size() << " " << " mismatch the numbers of elements at 0: " << sz << "/n";
747 }
748 }
749
750 set_of_graphs.last().type = GGRAPH_COLUMS;
751 set_of_graphs.last().data = get_points_plot_data(x,y,yn,opt,set_of_graphs.size()-1);
752 set_of_graphs.last().option = get_colums_bar_option(opt);
753 set_of_graphs.last().view = get_view_bar_option(opt,y.get(0).size());
754 set_of_graphs.last().opt = opt;
755 }
756
757
767 template<typename ... X> void AddLines(const openfpm::vector<std::string> & yn,
768 const GCoptions & opt,
769 X ... xy)
770 {
771 // first we sort the vectors
772 recursive_sort(xy ... );
773
774 size_t counters[sizeof...(X)];
775 memset(&counters,0,sizeof(counters));
776
777 typename get_value_type<X...>::type point[sizeof...(X)];
778 typename get_value_type<X...>::type xe;
779
780 openfpm::vector<typename get_value_type<X...>::type> x;
781
782 openfpm::vector<openfpm::vector<typename get_value_type<X...>::type>> y;
783
784
785 while (get_v(xe,point,counters,xy...))
786 {
787 y.add();
788 x.add(xe);
789
790 for (size_t i = 0 ; i < sizeof...(X)/2 ; i++)
791 {
792 y.last().add(point[i]);
793 }
794 }
795
796 AddLinesGraph(x,y,yn,opt);
797 }
798
819 template<typename X, typename Y> void AddLinesGraphT(openfpm::vector<X> & x, openfpm::vector<Y> & y , const GCoptions & opt)
820 {
822
823 if (y.size() == 0)
824 {
825 std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " vector y must be filled" << std::endl;
826 return;
827 }
828
829 for (size_t i = 0 ; i < y.last().size() ; i++)
830 yn.add(std::string("line") + std::to_string(i));
831
832 if (y.size() == 0)
833 return;
834
835 // number of points
836 size_t np = y.last().size();
837
838 for (size_t j = 0 ; j < y.size() ; j++)
839 {
840 if (y.get(j).size() != np)
841 std::cerr << __FILE__ << ":" << __LINE__ << " Error all the graph must have the same number of points " << np << "!=" << y.get(j).size() << std::endl;
842 }
843
845
846
847 // swap the vector
848 // Each vector is a graph
849 // It is different from the other call where each vector
850 // has multiple value for the same point
851 for (size_t i = 0 ; i < np ; i++)
852 {
853 swap.add();
854 for (size_t j = 0 ; j < y.size() ; j++)
855 {
856 swap.last().add(y.get(j).get(i));
857 }
858 }
859
860 AddLinesGraph(x,swap,yn,opt);
861 }
862
886 template<typename X, typename Y> void AddLinesGraph(openfpm::vector<X> & x, openfpm::vector<Y> & y , const GCoptions & opt)
887 {
889
890 if (y.size() == 0)
891 {
892 std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " vector y must be filled";
893 return;
894 }
895
896 for (size_t i = 0 ; i < y.last().size() ; i++)
897 yn.add(std::string("line") + std::to_string(i));
898
899 AddLinesGraph(x,y,yn,opt);
900 }
901
915 template<typename X, typename Y> void AddLinesGraph(openfpm::vector<X> & x, openfpm::vector<Y> & y , const openfpm::vector<std::string> & yn, const GCoptions & opt)
916 {
917 if (y.size() == 0)
918 {
919 std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " vector y must be filled\n";
920 return;
921 }
922
923 set_of_graphs.add();
924 injectHTML.add();
925
926 // Check that all the internal vectors has the same number of elements
927
928 if (y.size() != 0)
929 {
930 size_t sz = y.get(0).size();
931 for (size_t i = 0; i < y.size() ; i++)
932 {
933 if (y.get(i).size() != sz)
934 std::cerr << __FILE__ << ":" << __LINE__ << " error all the elements in the y vector must have the same numbers of elements " << y.get(i).size() << " != " << sz << "\n";
935 }
936 }
937
938 set_of_graphs.last().type = GGRAPH_POINTS;
939 set_of_graphs.last().data = get_points_plot_data(x,y,yn,opt,set_of_graphs.size()-1);
940 set_of_graphs.last().option = get_points_plot_option(opt);
941 set_of_graphs.last().opt = opt;
942 }
943
949 void addHTML(const std::string & html)
950 {
951 injectHTML.last() = html;
952 }
953
959 void write(std::string file)
960 {
961 // Open a file
962
963 std::ofstream of(file);
964
965 // Check if the file is open
966 if (of.is_open() == false)
967 {std::cerr << "Error cannot create the HTML file: " + file + "\n";}
968
969 // write the file
970
971 of << begin_data;
972
973 for (size_t i = 0 ; i < set_of_graphs.size() ; i++)
974 addData(of,i,set_of_graphs.get(i).data);
975
976 for (size_t i = 0 ; i < set_of_graphs.size() ; i++)
977 addOption(of,i,set_of_graphs.get(i).option);
978
979 for (size_t i = 0 ; i < set_of_graphs.size() ; i++)
980 addView(of,i,set_of_graphs.get(i).view);
981
982 for (size_t i = 0 ; i < set_of_graphs.size() ; i++)
983 addDrawDiv(of,i,set_of_graphs.get(i).view.size() == 0);
984
985 of << begin_div;
986
987 of << injectHTML.get(0);
988
989 for (size_t i = 0 ; i < set_of_graphs.size() ; i++)
990 {
991 addDiv(of,i,set_of_graphs.get(i).opt);
992 of << injectHTML.get(i+1);
993 }
994
995 of << div_end;
996
997 of.close();
998 }
999};
1000
1001#endif /* OPENFPM_DATA_SRC_PLOT_GOOGLECHART_HPP_ */
Small class to produce graph with Google chart in HTML.
bool get_v(typename get_value_type< Xs... >::type &x, typename get_value_type< Xs... >::type *point, size_t *counters, Xs &... xy)
Recursively sort variadic template of vectors.
void AddLinesGraph(openfpm::vector< X > &x, openfpm::vector< Y > &y, const openfpm::vector< std::string > &yn, const GCoptions &opt)
Add a simple plot graph.
bool isNext(size_t *counters, X &x, X &y, Xs &... xy)
Recursively sort variadic template of vectors.
T get_low(size_t *counters, X &x, X &y, Xs &... xy)
Recursively sort variadic template of vectors.
void get_point(T low, T *point, size_t *counters)
Recursively sort variadic template of vectors.
void addView(std::ofstream &of, size_t i, std::string view)
Add a view data variable.
void write(std::string file)
It write the graphs on file in html format using Google charts.
void addDrawDiv(std::ofstream &of, size_t i, bool draw_view)
Add a draw div section.
void AddLines(const openfpm::vector< std::string > &yn, const GCoptions &opt, X ... xy)
Add lines graph.
void get_point(typename X::value_type low, typename X::value_type *point, size_t *counters, X &x, X &y, Xs &... xy)
Recursively sort variadic template of vectors.
void addDiv(std::ofstream &of, size_t i, const GCoptions &gc)
Add a div section.
std::string get_points_plot_data(const openfpm::vector< X > &x, const openfpm::vector< Y > &y, const openfpm::vector< std::string > &yn, const GCoptions &opt, size_t i)
Given X and Y vector return the string representing the data section of the Google Chart.
T get_low(size_t *counters)
Recursively sort variadic template of vectors.
bool isNext(size_t *counters)
Recursively sort variadic template of vectors.
void AddLinesGraphT(openfpm::vector< X > &x, openfpm::vector< Y > &y, const GCoptions &opt)
Add lines graph.
void AddLinesGraph(openfpm::vector< X > &x, openfpm::vector< Y > &y, const GCoptions &opt)
Add a simple lines graph.
void AddHistGraph(openfpm::vector< X > &x, openfpm::vector< Y > &y, openfpm::vector< Yn > &yn)
Add an histogram graph.
void recursive_sort()
terminator for recursive sort
openfpm::vector< std::string > injectHTML
set inject HTML;
openfpm::vector< GGraph > set_of_graphs
set of graphs
bool holes
Data has holes.
void recursive_sort(X &x, X &y, Xs &... xy)
Recursively sort variadic template of vectors.
void AddHistGraph(openfpm::vector< X > &x, openfpm::vector< Y > &y, openfpm::vector< Yn > &yn, const GCoptions &opt)
Add an histogram graph.
void AddHistGraph(openfpm::vector< Y > &y)
Add an histogram graph.
void AddHistGraph(openfpm::vector< X > &x, openfpm::vector< Y > &y)
Add an histogram graph.
void addData(std::ofstream &of, size_t i, const std::string &data)
Add a graph data variable.
void addHTML(const std::string &html)
Add HTML text.
void addOption(std::ofstream &of, size_t i, const std::string &opt)
Add an option data variable.
std::string get_view_bar_option(const GCoptions &opt, size_t n_col)
Construct a view option.
Implementation of 1-D std::vector like structure.
size_t size()
Stub size.
Google chart options.
std::string stypeext
std::string intervalext
size_t width
width of the graph in pixels
size_t heigh
height of the graph in pixels
std::string xAxis
X axis name.
size_t lineWidth
Width of the line.
GCoptions & operator=(const GCoptions &opt)
copy operator
std::string more
more
std::string intervalsext
std::string curveType
curve type
std::string title
Title of the chart.
bool barWD
barWD
std::string stype
std::string yAxis
Y axis name.
Google Graph.
std::string option
option
std::string view
view in case we need a view
std::string data
data
GCoptions opt
Google chart option.
size_t type
TypeOfGraph.