GTK+ IOStream  Beta
<< GTK+ >> add C++ IOStream operators to GTK+. Now with extra abilities ... like network serialisation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Plot.H
Go to the documentation of this file.
1 /* Copyright 2000-2013 Matt Flax <flatmax@flatmax.org>
2  This file is part of GTK+ IOStream class set
3 
4  GTK+ IOStream is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  GTK+ IOStream is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You have received a copy of the GNU General Public License
15  along with GTK+ IOStream
16  */
17 
18 #ifndef PLOT_H_
19 #define PLOT_H_
20 
21 #ifdef _MSC_VER
22 typedef unsigned int uint;
23 #pragma warning( disable : 4554)
24 #endif
25 
26 #include "ColourLineSpec.H"
27 #include "Table.H"
28 #include "Labels.H"
29 
30 #include <iostream>
31 #include <glib-object.h>
32 #include <gtk/gtk.h>
33 #include <gtkdatabox.h>
34 #include <gtkdatabox_points.h>
35 #include <gtkdatabox_lines.h>
36 #include <gtkdatabox_regions.h>
37 #include <gtkdatabox_ruler.h>
38 #include <gtkdatabox_grid.h>
39 #include <gtkdatabox_markers.h>
40 #include <gtkdatabox_offset_bars.h>
41 
42 //#include <vector>
43 //#include <stdlib.h>
44 //#include <string.h>
45 
46 using namespace std;
47 
87 class Plot : public Table {
88 protected:
89  GtkWidget *axis;
90  GtkDataboxGraph *gridGraph;
91  bool holdOn;
92  bool gridOn;
93 public:
94 
97  Plot(void) {
98  // We are going to manually place everything
99  setHomogeneous(false);
100  resize(5,4); // setup the default table to be x dimension : ylabel, yruler, plot, yruler, ylabel
101  // y dimension : title, plot, xruler, xlabel
102 
103  axis=gtk_databox_new ();
104  setOptions((GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK), (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK));
105  setRegion(2,3,1,2); // put the plot in the middle
106  *this<<axis; // put the plot in the middle
107 
108  GtkWidget *xRuler = gtk_databox_ruler_new (GTK_ORIENTATION_HORIZONTAL);
109  //gtk_databox_ruler_set_scale_type (GTK_DATABOX_RULER (xRuler), GTK_DATABOX(axis)->priv->scale_type_x);
110  gtk_databox_set_ruler_x (GTK_DATABOX(axis), GTK_DATABOX_RULER (xRuler));
111  GtkWidget *yRuler = gtk_databox_ruler_new (GTK_ORIENTATION_VERTICAL);
112  //gtk_databox_ruler_set_scale_type (GTK_DATABOX_RULER (yRuler), GTK_DATABOX(axis)->priv->scale_type_y);
113  gtk_databox_set_ruler_y (GTK_DATABOX(axis), GTK_DATABOX_RULER (yRuler));
114 
115  setOptions((GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK), (GtkAttachOptions)(GTK_FILL));
116  setRegion(2,3,2,3); // put the x axis on the bottom
117  *this<<xRuler;
118  setOptions((GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK));
119  setRegion(1, 2, 1, 2); // put the y axis on the left
120  *this<<yRuler;
121 
122  show();
123 
124  ColourLineSpec cls("w"); // default white colour
125  GdkColor gdkC=cls.getColour();
126  gtk_widget_modify_bg (axis, GTK_STATE_NORMAL, &gdkC); // set the background
127  gridGraph=NULL;
128  }
129 
133  GtkWidget *gca(void) {
134  return getCurrentAxis();
135  }
136 
140  GtkWidget *getCurrentAxis(void) {
141  return axis;
142  }
143 
146  void show(void) {
147  gtk_widget_show_all(axis);
148  gtk_widget_show_all(getWidget());
149  }
150  void hide(void) {
151  gtk_widget_hide(axis);
152  gtk_widget_hide(getWidget());
153  }
154 
160  void plot(gfloat *x, gfloat *y, int cnt) {
161  ColourLineSpec cls;
162  plot(x, y, cnt, cls);
163  }
164 
171  void plot(gfloat *x, gfloat *y, int cnt, const char *clsChar) {
172  ColourLineSpec cls(clsChar);
173  plot(x, y, cnt, cls);
174  }
175 
182  void plot(gfloat *x, gfloat *y, int cnt, ColourLineSpec &cls) {
183  if (!holdOn) {
184  clf();
185  if (gridOn)
186  grid(gridOn);
187  }
188 
189  //if (gtk_widget_get_realized (axis)){
190  GtkDataboxGraph *graph=NULL;
191  GdkColor gdkC=cls.getColour();
192  int size=cls.getSize();
193  if (cls.linePlot)
194  graph = gtk_databox_lines_new (cnt, x, y, &gdkC, size);
195  else
196  graph = gtk_databox_points_new (cnt, x, y, &gdkC, size);
197  gtk_databox_graph_add_front (GTK_DATABOX (axis), graph);
198  //}
199  }
200 
208  void plot(gfloat *x, gfloat *y1, gfloat *y2, int cnt) {
209  ColourLineSpec cls;
210  plot(x, y1, y2, cnt, cls);
211  }
212 
222  void plot(gfloat *x, gfloat *y1, gfloat *y2, int cnt, const char *clsChar) {
223  ColourLineSpec cls(clsChar);
224  plot(x, y1, y2, cnt, cls);
225  }
226 
236  void plot(gfloat *x, gfloat *y1, gfloat *y2, int cnt, ColourLineSpec &cls) {
237  if (!holdOn) {
238  clf();
239  if (gridOn)
240  grid(gridOn);
241  }
242 
243  //if (gtk_widget_get_realized (axis)) {
244  GtkDataboxGraph *graph=NULL;
245  GdkColor gdkC=cls.getColour();
246  int size=cls.getSize();
247  if (cls.linePlot)
248  graph = gtk_databox_regions_new (cnt, x, y1, y2, &gdkC);
249  else
250  graph = gtk_databox_offset_bars_new(cnt, x, y1, y2, &gdkC, size);
251  gtk_databox_graph_add_front (GTK_DATABOX (axis), graph);
252  //}
253  }
254 
261  void semilogx(gfloat *x, gfloat *y, int cnt) {
262  ColourLineSpec cls;
263  semilogx(x, y, cnt, cls);
264  }
265 
273  void semilogx(gfloat *x, gfloat *y, int cnt, const char *clsChar) {
274  ColourLineSpec cls(clsChar);
275  semilogx(x, y, cnt, cls);
276  }
277 
285  void semilogx(gfloat *x, gfloat *y, int cnt, ColourLineSpec &cls) {
286  plot(x, y, cnt, cls);
287  gtk_databox_set_scale_type_x (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LOG);
288  }
289 
298  void semilogx(gfloat *x, gfloat *y1, gfloat *y2, int cnt) {
299  ColourLineSpec cls;
300  semilogx(x, y1, y2, cnt, cls);
301  }
302 
313  void semilogx(gfloat *x, gfloat *y1, gfloat *y2, int cnt, const char *clsChar) {
314  ColourLineSpec cls(clsChar);
315  semilogx(x, y1, y2, cnt, cls);
316  }
317 
328  void semilogx(gfloat *x, gfloat *y1, gfloat *y2, int cnt, ColourLineSpec &cls) {
329  plot(x, y1, y2, cnt, cls);
330  //if (gtk_widget_get_realized (axis))
331  if (gtk_databox_get_scale_type_x(GTK_DATABOX (axis))!=GTK_DATABOX_SCALE_LOG)
332  gtk_databox_set_scale_type_x (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LOG);
333  }
334 
341  void semilogy(gfloat *x, gfloat *y, int cnt) {
342  ColourLineSpec cls;
343  semilogy(x, y, cnt, cls);
344  }
345 
353  void semilogy(gfloat *x, gfloat *y, int cnt, const char *clsChar) {
354  ColourLineSpec cls(clsChar);
355  semilogy(x, y, cnt, cls);
356  }
357 
365  void semilogy(gfloat *x, gfloat *y, int cnt, ColourLineSpec &cls) {
366  plot(x, y, cnt, cls);
367  //if (gtk_widget_get_realized (axis))
368 
369  if (gtk_databox_get_scale_type_y(GTK_DATABOX (axis))!=GTK_DATABOX_SCALE_LOG)
370  gtk_databox_set_scale_type_y (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LOG);
371  }
372 
379  void loglog(gfloat *x, gfloat *y, int cnt) {
380  ColourLineSpec cls;
381  loglog(x, y, cnt, cls);
382  }
383 
391  void loglog(gfloat *x, gfloat *y, int cnt, const char *clsChar) {
392  ColourLineSpec cls(clsChar);
393  loglog(x, y, cnt, cls);
394  }
402  void loglog(gfloat *x, gfloat *y, int cnt, ColourLineSpec &cls) {
403  plot(x, y, cnt, cls);
404  if (gtk_databox_get_scale_type_x(GTK_DATABOX (axis))!=GTK_DATABOX_SCALE_LOG)
405  gtk_databox_set_scale_type_x (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LOG);
406  if (gtk_databox_get_scale_type_y(GTK_DATABOX (axis))!=GTK_DATABOX_SCALE_LOG)
407  gtk_databox_set_scale_type_y (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LOG);
408  }
409 
416  GtkDataboxGraph * text(gfloat *x, gfloat *y, const char *textDisp, const char *clsChar) {
417  ColourLineSpec cls(clsChar);
418  return text(x, y, textDisp, cls);
419  }
420 
428  GtkDataboxGraph *text(gfloat *x, gfloat *y, const char *textDisp, ColourLineSpec &cls) {
429  GdkColor gdkC=cls.getColour();
430  GtkDataboxGraph *graph = gtk_databox_markers_new (1, x, y, &gdkC, 1, GTK_DATABOX_MARKERS_NONE);
431  bool boxed=false;
432  gtk_databox_markers_set_label (GTK_DATABOX_MARKERS (graph), 0, GTK_DATABOX_MARKERS_TEXT_CENTER, (gchar*)textDisp, boxed);
433  gtk_databox_graph_add_front (GTK_DATABOX (axis), graph);
434  return graph;
435  }
436 
439  void clear(void) {
440  clf();
441  }
442 
445  void clf(void) {
446  //if (gtk_widget_get_realized (axis))
447  gtk_databox_graph_remove_all(GTK_DATABOX (axis));
448  }
449 
452  void hold(bool on) {
453  holdOn=on;
454  }
455 
460  void grid(bool on) {
461  if (gridGraph) {
462  GtkDataboxGrid *gridG=GTK_DATABOX_GRID(gridGraph);
463  if (gtk_databox_grid_get_hline_vals(gridG)) { // reuse previously stored graph
464  grid(on, gtk_databox_grid_get_hlines(gridG), gtk_databox_grid_get_hline_vals(gridG), gtk_databox_grid_get_vlines(gridG), gtk_databox_grid_get_vline_vals(gridG));
465  return;
466  }
467  }
468  grid(on, 5, NULL, 5, NULL);
469  }
470 
478  void grid(bool on, int hCnt, gfloat *hLines, int vCnt, gfloat *vLines) {
479  //if (gtk_widget_get_realized (axis))
480  if (on) {
481  if (gridGraph!=NULL) {
482  gtk_databox_graph_remove(GTK_DATABOX (axis), gridGraph);
483  gridGraph=NULL;
484  }
485  ColourLineSpec cls("a1"); // gray line of size 1
486  GdkColor gdkC=cls.getColour();
487  int size=cls.getSize();
488  if ((hLines!=NULL) & (vLines!=NULL))
489  gridGraph=gtk_databox_grid_array_new(hCnt, vCnt, hLines, vLines, &gdkC, size);
490  else
491  gridGraph=gtk_databox_grid_new(hCnt, vCnt, &gdkC, size);
492  gtk_databox_graph_add_front (GTK_DATABOX (axis), gridGraph);
493  } else {
494  if (gridGraph!=NULL) {
495  gtk_databox_graph_remove(GTK_DATABOX (axis), gridGraph);
496  }
497  }
498  gridOn=on;
499  }
500 
508  void limits(float min_x, float max_x, float min_y, float max_y) {
509  gtk_databox_set_total_limits (GTK_DATABOX (axis), min_x, max_x, max_y, min_y);
510  }
511 
516  void limits(gfloat border=0.) {
517  gtk_databox_auto_rescale(GTK_DATABOX (axis), border);
518  }
519 
524  void replot(void) {
525  gtk_widget_queue_draw (GTK_WIDGET (axis));
526  }
527 
588  void set(GtkWidget *widget, ...) {
589  va_list args;
590  va_start(args, widget);
591  //cout<<"starting"<<endl;
592  while (1) { // terminates when a null is read
593  char *token=va_arg(args, char *);
594  if ((token==NULL) | (token=='\0'))
595  break;
596 
597  // first attempt to process non-axis (box) settings
598  if ((strcmp(&token[1],"oxShadow")==0) | (strcmp(&token[1],"oxshadow")==0))
599  gtk_databox_set_box_shadow(GTK_DATABOX(widget), (GtkShadowType)va_arg(args, int));
600  else if ((strcmp(&token[1],"Scale")==0) | (strcmp(&token[1],"scale")==0)) {
601  char *linearOrLog=va_arg(args, char*);
602  if (tolower(token[0])=='x'){
603  if (strcmp(&linearOrLog[1],"og")==0) // check for the right keyword
604  gtk_databox_set_scale_type_x (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LOG);
605  else
606  gtk_databox_set_scale_type_x (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LINEAR);
607  }
608  if (tolower(token[0])=='y'){
609  if (strcmp(&linearOrLog[1],"og")==0) // check for the right keyword
610  gtk_databox_set_scale_type_y (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LOG);
611  else
612  gtk_databox_set_scale_type_y (GTK_DATABOX (axis), GTK_DATABOX_SCALE_LINEAR);
613  }
614  } else {
615  // process axis (ruler) settings
616  GtkDataboxRuler *ruler;
617  bool xRuler=1;
618  if (tolower(token[0])=='x')
619  ruler=gtk_databox_get_ruler_x(GTK_DATABOX (widget));
620  else {
621  ruler=gtk_databox_get_ruler_y(GTK_DATABOX (widget));
622  xRuler=0;
623  }
624 
625  if ((strcmp(&token[1],"MinorTick")==0) | (strcmp(&token[1],"minortick")==0)) {
626 
627  int draw_ticks=va_arg(args, int);
628  gtk_databox_ruler_set_draw_subticks(ruler,draw_ticks);
629 
630  } else if ((strcmp(&token[1],"Tick")==0) | (strcmp(&token[1],"tick")==0)) {
631  uint manual_tick_cnt=va_arg(args, int);
632  if (manual_tick_cnt==0)
633  gtk_databox_ruler_set_draw_ticks(ruler,manual_tick_cnt);
634  else {
635  gtk_databox_ruler_set_manual_tick_cnt(ruler, manual_tick_cnt);
636  gtk_databox_ruler_set_manual_ticks(ruler, va_arg(args, gfloat*));
637  }
638  } else if ((strcmp(&token[1],"LabelFormat")==0) | (strcmp(&token[1],"labelformat")==0)) {
639  int scaleType;
640  if (xRuler)
641  scaleType=gtk_databox_get_scale_type_x(GTK_DATABOX (widget));
642  else
643  scaleType=gtk_databox_get_scale_type_y(GTK_DATABOX (widget));
644 
645  if (scaleType==GTK_DATABOX_SCALE_LINEAR) // set the label format
646  gtk_databox_ruler_set_linear_label_format(ruler, va_arg(args, char*));
647  else
648  gtk_databox_ruler_set_log_label_format(ruler, va_arg(args, char*));
649 
650  } else if ((strcmp(&token[1],"LabelLength")==0) | (strcmp(&token[1],"labellength")==0)) {
651  int scaleType;
652  if (xRuler)
653  scaleType=gtk_databox_get_scale_type_x(GTK_DATABOX (widget));
654  else
655  scaleType=gtk_databox_get_scale_type_y(GTK_DATABOX (widget));
656 
657  gtk_databox_ruler_set_max_length(ruler, va_arg(args, int));
658  } else if ((strcmp(&token[1],"LabelLength")==0) | (strcmp(&token[1],"labellength")==0)) {
659  gtk_databox_ruler_set_max_length(ruler, va_arg(args, int));
660  } else if ((strcmp(&token[1],"TickLabel")==0) | (strcmp(&token[1],"ticklabel")==0)) {
661  gtk_databox_ruler_set_manual_tick_labels(ruler, (gchar**)va_arg(args, gchar**));
662  } else if ((strcmp(&token[1],"TickXOffset")==0) | (strcmp(&token[1],"tickxoffset")==0)) {
663  gtk_databox_ruler_set_text_hoffset(ruler, va_arg(args, int));
664  } else if ((strcmp(&token[1],"Position")==0) | (strcmp(&token[1],"position")==0)) {
665  gtk_databox_ruler_set_draw_position(ruler, va_arg(args, int));
666  } else if ((strcmp(&token[1],"Shadow")==0) | (strcmp(&token[1],"shadow")==0)) {
667  gtk_databox_ruler_set_box_shadow(ruler, (GtkShadowType)va_arg(args, int));
668  } else if ((strcmp(&token[1],"LabelAlignment")==0) | (strcmp(&token[1],"labelalignment")==0)) {
669  char *which=va_arg(args, char*);
670  if (strcmp(&which[1],"ight")==0) // check for the right keyword
671  gtk_databox_ruler_set_text_alignment(ruler, PANGO_ALIGN_RIGHT);
672  else if (strcmp(&which[1],"enter")==0) // check for the center keyword
673  gtk_databox_ruler_set_text_alignment(ruler, PANGO_ALIGN_CENTER);
674  else // left aligned which is standard
675  gtk_databox_ruler_set_text_alignment(ruler, PANGO_ALIGN_LEFT);
676  } else if ((strcmp(&token[1],"LabelRotate")==0) | (strcmp(&token[1],"labelrotate")==0)) {
677  char *which=va_arg(args, char*);
678  if (strcmp(&which[1],"ertical")==0) // check for the vertical keyword
679  gtk_databox_ruler_set_text_orientation(ruler, GTK_ORIENTATION_VERTICAL);
680  else
681  gtk_databox_ruler_set_text_orientation(ruler, GTK_ORIENTATION_HORIZONTAL);
682  }
683 
684  if (tolower(token[0])=='x')
685  gtk_databox_set_ruler_x(GTK_DATABOX (widget), ruler);
686  else
687  gtk_databox_set_ruler_y(GTK_DATABOX (widget), ruler);
688  }
689  }
690  va_end(args);
691  }
692 
698  void connectAfter(const char *event, GCallback callback, gpointer data){
699  g_signal_connect_after(axis, event, callback, data);
700  }
701 
713  void xLabel(const char* label, int *indexes=NULL){
714  if (indexes==NULL){
715  setRegion(2, 3, 3, 4);
716  setOptions((GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK), (GtkAttachOptions)(GTK_FILL));
717  } else
718  *this<<indexes;
719  *this<<(Labels()<<label).setAlignment(0.5, 0.5);
720  }
721 
726  void xLabelBL(const char* label){
727  setOptions((GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(GTK_FILL | GTK_SHRINK));
728  int indexes[]={1,2,2,3};
729  xLabel(label,indexes);
730  }
731 
743  void yLabel(const char* label, int *indexes=NULL){
744  Labels ylabel; ylabel<<label;
745  if (indexes==NULL){
746  setRegion(0, 1, 1, 2);
747  setOptions((GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK));
748  ylabel.setAngle(90.0);
749  } else
750  *this<<indexes;
751  ylabel.setAlignment(0.5, 0.5);
752  *this<<ylabel.current();
753  }
754 
759  void yLabelTL(const char* label){
760  setOptions((GtkAttachOptions)(GTK_FILL | GTK_SHRINK), (GtkAttachOptions)(GTK_FILL));
761  int indexes[]={1,2,0,1};
762  yLabel(label,indexes);
763  }
764 
772  void title(const char* titleStr, int *indexes=NULL){
773  Labels labels; labels<<titleStr;
774  labels.setAlignment(0.5, 0.5);
775  title(labels.getWidget(), indexes);
776  }
777 
785  void title(GtkWidget *widget, int *indexes=NULL){
786  if (indexes==NULL){
787  setRegion(2, 3, 0, 1);
788  setOptions((GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK), (GtkAttachOptions)(GTK_FILL));
789  } else
790  *this<<indexes;
791  *this<<widget;
792  }
793 //static bool expose(GtkWidget *widget, GdkEventExpose *event, gpointer data){
794 // Plot*p=static_cast<Plot*>(data);
795 // p->replot();
796 // return false;
797 //}
798 // cout<<"Plot::expose"<<endl;
799 // if (gtk_widget_get_realized (axis))
800 // return false;
801 // else
802 // return true;
803 //}
804 };
805 #endif //PLOT_H_