This chapter shows how to use PLplot to embed plots in graphical user interfaces.
PLplot plots can be embedded into Gnome/GTK applications by installing a GnomeCanvas widget into the GCW "Gnome Canvas Widget" driver. Once the canvas is installed and set up, the standard PLplot commands may be used. A special Canvas called the PlplotCanvas is also provided, and provides an object-oriented interface which simplifies plotting to multiple Canvasses (i.e., multiple streams).
A specialized API is provided both GCW and the PlplotCanvas, and bindings are included for C and Python. Bindings for the other languages supported by PLplot are possible, and can be requested via PLplot mailing lists at plplot.sourceforge.net.
Example programs are provided for both C and Python, and demonstrate the use of the PlplotCanvas object-oriented API. They are:
plplotcanvas_demo: Demonstrates the basic usage of the PlplotCanvas to embed a plot in a Gnome application.
plplotcanvas_animation: Demonstrates advanced multi-threaded dual-stream usage of the PlplotCanvas.
Use of GCW in conjunction with a user-supplied GnomeCanvas requires the use of a specialized widget-driver API. It is typically easier to use the PlplotCanvas API instead, but the GCW API is described here for reference. An understanding of both GTK and GnomeCanvas usage is assumed.
On the Canvas, plot commands draw into three different groups, each with different behaviours. The default group is shown when the page is advanced, and is cleared for every new PLplot page. The foreground and background groups are persistent (i.e., never cleared), and so are useful for when static material on the Canvas is required. Manipulation of the Canvas groups can help render fast animations on a common set of axes, but is not usually employed otherwise.
For multiple streams, you must keep track of the stream number for each Canvas and switch to the required stream as appropriate before calling PLplot commands. A key benefit to the PlplotCanvas is that stream coordination is handled automatically.
To access the C API for GCW, include "gcw.h". The GnomeCanvas should be installed into the GCW driver after the device is set and initialized. The sequence of commands is as follows:
plsdev("gcw"); /* Set the device */ plinit(); /* Initialize the device */ plP_esc(PLESC_DEVINIT,(void*)canvas); /* Install canvas into the driver */ |
Once the canvas is installed into the driver, the GCW API and PLplot commands ma be used.
gcw_set_canvas_size
: Sets the canvas width and height in pixels.
Sets the canvas width and height in pixels.
|
gcw_set_canvas_zoom
: Zooms in on the Canvas according to the magnification factor.
Zooms in on the Canvas according to the magnification factor. Note that all magnifications are multiplicative.
|
gcw_get_canvas_viewport
: Transforms a PLplot viewport into one appropriate for the GCW driver.
Transforms a PLplot viewport into coordinates appropriate for use with the GCW driver. The returned limits should be set with plvpor
. This transformation is required because of the way the GCW driver sizes the canvas. The viewport should only be retrieved after the canvas size is set.
|
gcw_use_text
: Sets up text handling capabilities.
Determines whether or not truetype text (use_text = TRUE) or Hershey fonts (use_text = FALSE) are used. For non-antialiased Canvasses, only Hershey fonts are available, and truetype fonts will not display. Truetype fonts are the default.
|
gcw_use_fast_rendering
: Uses fast (but buggy) rendering on the Canvas.
Set use_fast_rendering to TRUE for fast rendering on the Canvas (default FALSE). This might occasionally result in an 'attempt to put segment in horiz list twice' error message from libgnomecanvas, which may be accompanied by plotting errors. The problem occurs particularly for shade and vector plots. However, the error does not often occur for line plots, and the use of fast rendering can dramatically improve the performance of real-time displays.
|
gcw_use_pixmap
: Use a pixmap for shade rendering.
Set use_pixmap to TRUE to render shades using a pixmap (default FALSE). This is useful for contour plots, which display much faster and have a smaller memory footprint when a pixmap is used.
The drawback of the pixmap approach is that lines and text cannot be drawn with antialiasing to the pixmap. Instead, the pixmap is moved to the back of the current group, and all lines on the canvas are drawn over top. For this reason, use of the pixmap is usually appropriate for contour plots, but not for 3D plots.
|
gcw_use_default_group
: Sets GCW to direct all subsequent plotting commands into the default group.
Sets GCW to direct all subsequent plotting commands into the default group.
|
gcw_use_foreground_group
: Sets GCW to direct all subsequent plotting commands into the foreground group.
Sets GCW to direct all subsequent plotting commands into the foreground group.
|
gcw_use_background_group
: Sets GCW to direct all subsequent plotting commands into the background group.
Sets GCW to direct all subsequent plotting commands into the background group.
|
To access the GCW driver from python, import gcw. PyGTK provides the required Gnome components. The API is much the same as the C API. For example, the canvas size is set using gcw.set_canvas_size
. Output variables are returned in a tuple instead of being passed as parameters to a function.
PlplotCanvas is a GnomeCanvas subclass that provides an object-oriented interface which abstracts away some of the complexity of using the GCW driver with PLplot. When a new Canvas is initialized, plsdev
and plinit
are automatically invoked, and the Canvas is automatically installed into the driver. Object-oriented wrappers to all PLplot functions are provided (see the discussion in plplot_canvas_get_stream_number
, below), which coordinates the access to multiple streams automatically (i.e., calls to plsstrm
are not required).
The methods described below assume an understanding of the GCW API.
To use the PlplotCanvas in C, include plplotcanvas.h. The object model is the same as Gnome's GLib Object system used by GnomeCanvas.
Each of the GCW driver functions have object-oriented PlplotCanvas method analogues, and these are not repeated below. For example, gcw_set_canvas_size(...)
maps to plplot_canvas_set_size(canvas,...)
. Notice that we don't repeat the word "canvas" twice. When in doubt, check plplotcanvas.h for the method names and arguments.
The additional methods are as follows.
plplot_canvas_new
: Creates a new canvas.
Returns a pointer to the new PlplotCanvas. Either an antialiased or non-antialiased Canvas ma be used. Antialiased Canvasses provide nicer looking results, but the performance is somewhat poorer for animated displays. Truetype fonts can only be used with the antialiased Canvas.
|
plplot_canvas_dispose
: Disposes the Canvas.
Disposes the Canvas.
|
plplot_canvas_get_stream_number
: Returns the stream number of the given Canvas.
Returns the stream number for the given Canvas. When using multiple streams (i.e., multiple Canvasses), this number should be used with plsstrm
to select the stream before any PLplot functions are called; e.g., plline(...)
.
Alternatively, object-oriented methods are provided that wrap each of the PLplot functions; e.g., plplot_canvas_plline(canvas,...)
. The first argument to an object-oriented methods is the object itself, followed by the same arguments as used in the PLplot functions. The object-oriented methods automatically set the stream.
When in doubt, check plplotcanvas.h for the method names and arguments. Go to the Examples section below to see each of these alternatives in action.
|
To use the PlplotCanvas in python, import plplotcanvas. A call to plplotcanvas.Canvas() returns a new Canvas, and accepts an optional argument "aa" (True/False) which sets the canvas as antialiased or not. The PlplotCanvas can be used with PyGTK like any other GnomeCanvas.
The PlplotCanvas methods in Python are analogous to their C counterparts. For example, if the object is "canvas", use canvas.plline(...)
to draw lines, where the usual arguments for plline
are employed.
As an example, the code from plplotcanvas_demo.c is given below. An identical program is implemented in Python as plplotcanvas_demo.py, and is provided with the PLplot distribution.
#include <plplotcanvas.h> #include <gtk/gtk.h> /* The width and height of the plplot canvas widget */ #define WIDTH 1000 #define HEIGHT 600 /* Delete event callback */ gint delete_event( GtkWidget *widget,GdkEvent *event,gpointer data ) { return FALSE; } /* Destroy event calback */ void destroy(GtkWidget *widget,gpointer data) { gtk_main_quit (); } int main(int argc,char *argv[] ) { PlplotCanvas* canvas; GtkWidget *window; gdouble xmin,xmax,ymin,ymax; /* The data to plot */ double x[11] = {0,1,2,3,4,5,6,7,8,9,10}; double y[11] = {0,0.1,0.4,0.9,1.6,2.6,3.6,4.9,6.4,8.1,10}; /* Initialize gtk and the glib type system */ gtk_init(&argc, &argv); g_type_init(); /* Create the canvas and set its size; during the creation process, * the gcw driver is loaded into plplot, and plinit() is invoked. */ canvas=plplot_canvas_new(TRUE); plplot_canvas_set_size(canvas,WIDTH,HEIGHT); /* Determine the viewport so that everything is drawn on the canvas */ plplot_canvas_get_viewport(canvas,0.12,0.95,0.15,0.88, &xmin,&xmax,&ymin,&ymax); /* Create a new window and stuff the canvas into it */ window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width(GTK_CONTAINER(window),10); gtk_container_add(GTK_CONTAINER(window),GTK_WIDGET(canvas)); /* Connect the signal handlers to the window decorations */ g_signal_connect(G_OBJECT(window),"delete_event", G_CALLBACK(delete_event),NULL); g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(destroy),NULL); /* Display everything */ gtk_widget_show_all(window); /* Draw on the canvas with Plplot */ plplot_canvas_pladv(canvas,0); /* Advance to first page */ plplot_canvas_plcol0(canvas,15); /* Set color to black */ plplot_canvas_plwid(canvas,2); /* Set the pen width */ plplot_canvas_plvpor(canvas,xmin,xmax,ymin,ymax); /* Set the viewport */ plplot_canvas_plwind(canvas,0.,10.,0.,10.); /* Set the window */ plplot_canvas_plbox(canvas,"bcnst",0.,0,"bcnstv",0.,0); /* Set the box */ plplot_canvas_pllab(canvas,"x-axis","y-axis","A Simple Plot"); /* Draw some labels */ /* Draw the line */ plplot_canvas_plcol0(canvas,1); /* Set the pen color */ plplot_canvas_plline(canvas,11,x,y); /* Advancing the page finalizes this plot */ plplot_canvas_pladv(canvas,0); /* Start the gtk main loop */ gtk_main(); } |
gtk_init
and g_type_init
. A PlplotCanvas is created using plplot_canvas_new
, and it's size is set using plplot_canvas_set_size
. We want the viewport to have normalized coordinates (0.12,0.95,0.15,0.88), but this must be transformed for use with the GCW driver by using plplot_canvas_get_viewport
. Next, a window is created (gtk_window_new
), the border is set (gtk_set_border_width
), and the canvas is stuffed into it (gtk_container_add
). Callback functions are installed using g_signal_connect
so that the window decorations respond, and the window is set to display everything (gtk_widget_show_all
).
Now come the PLplot commands, invoked using PlplotCanvas's object-oriented interface. First we must advance the page using plplot_canvas_pladv
. Next, the pen color and width are set with plplot_canvas_plcol0
and plplot_canvas_plwid
. The PLplot viewport, window, box and labels are created using plplot_canvas_plvpor
, plplot_canvas_plwind
, plplot_canvas_plbox
and plplot_canvas_pllab
, respectively. Note that the viewport is set using the transformed coordinates. A line is drawn on the canvas using plplot_canvas_plline
, and advancing the page with plplot_canvas_pladv
displays the plot. The GTK main loop is entered using gtk_main
, where it resides until the program is exited.
Alternatively, the PLplot API can be used instead of the object-oriented methods given above. In place of the given plot commands, use:
pladv(0); /* Advance to first page */ plcol0(15); /* Set color to black */ plwid(2); /* Set the pen width */ plvpor(xmin,xmax,ymin,ymax); /* Set the viewport */ plwind(0.,10.,0.,10.); /* Set the window */ plbox("bcnst",0.,0,"bcnstv",0.,0); /* Set the box */ pllab("x-axis","y-axis","A Simple Plot"); /* Draw some labels */ /* Draw the line */ plcol0(1); /* Set the pen color */ plline(canvas,11,x,y); /* Advancing the page finalizes this plot */ pladv(canvas,0); |
plplot_canvas_get_stream_number
and set using plsstrm
, prior to PLplot API calls; e.g.,
PLINT N; . . . N = plplot_canvas_get_stream_number(canvas); plsstrm(N); pladv(0); /* Advance to first page */ plcol0(15); /* Set color to black */ . . . |