From octave-graphics-request at bevo dot che dot wisc dot edu Mon Apr 1 19:07:20 2002 Subject: A quick and dirty interface from Octave to Grace From: Chee-Kiang dot Goh at infineon dot com To: octave-graphics at bevo dot che dot wisc dot edu Date: Tue, 02 Apr 2002 09:05:40 +0800 This is a multi-part message in MIME format. --------------FA33921391D91BBBE24104AC Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Good day, all, I have written a quick and dirty interface for Octave to do some simple plotting using Grace (http://plasma-gate.weizmann.ac.il/Grace/). The tool is supposed to be a successor of the old Xmgr, and here is a snippet from the documentation of Grace: "Grace is a tool to make two-dimensional plots of numerical data. It runs under various (if not all) flavours of UNIX with X11 and M*tif. Its capabilities are roughly similar to GUI-based programs like Sigmaplot or Microcal Origin plus script-based tools like gnuplot or Genplot. Its strength lies in the fact that it combines the convenience of a graphical user interface with the power of a scripting language which enables it to do sophisticated calculations or perform automated tasks." The single grplot.cc file contains the following functions: grplot(X), grplot(X,Y) : plot a vector or a set of (X,Y) points is_gr_open() : check if the Grace subprocess is spawned grcmd("Native grace commands"): send native Grace commands grxlabel("TextString") : set the X-axis label of current graph grylabel("TextString") : set the Y-axis label of current graph graxis([xmin xmax ymin ymax]): set the axes grtitle("TextString") : set the title grsubtitle("TextString"): Set the subtitle grholdon : each grplot sends data into a new set in the current graph grholdoff : each grplot sends data into the same set, destroying the previous data grfigure(n): new graph n Note that subplots and more exotic placements/formatting etc can be done directly within Grace (and more recommended to do so) GUI interface. Printing to files in many formats are also supported within the Grace GUI. Requirement: You will need to have Grace installed, of course. Gcc (mine is 2.95.2 on a solaris 2.5.1 machine) Motif (for the Grace interface). Octave (mine is 2.1.34) with the mkoctfile Installation: 1. mkoctfile grplot.cc 2. create symbolic links such as grholdon.oct to grplot.cc etc. This will let octave knows where to look for the the command grholdon. To-do: This is definitely not complete but the functions do satisfy my current needs for octave with a better plotting facilities (tried pl-plot etc). Just to share with you. Suggestions are most welcome! Enjoy ! Best Regards -- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Goh Chee Kiang \e/ email: Chee-Kiang dot Goh at infineon dot com __o __o I Tel: +65-840-0334 `\<, `\<, `\\, Infineon Technologies Asia Pacific Pte Ltd _O/ O_________O/_O______O/_O_ 168, Kallang Way. Singapore 349253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --------------FA33921391D91BBBE24104AC Content-Type: text/plain; charset=us-ascii; name="grplot.cc" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="grplot.cc" #include #include #include #include #include #include #include #include #include #ifndef OPEN_MAX # define OPEN_MAX 256 #endif #define min(A,B) ((A)>(B)?(B):(A)) #define SIZEOF_CHAR sizeof(char) /* static global variables */ static char* buf = NULL; /* global write buffer */ static int bufsize; /* size of the global write buffer */ static int bufsizeforce; /* threshold for forcing a flush */ static int fd_pipe = -1; /* file descriptor of the pipe */ static int broken_pipe = 0; /* is the pipe broken ? */ static pid_t pid = (pid_t) -1; /* pid of grace */ static int ate_already=0; static short cur_graph=0,cur_set=0; static int holdon = 0; static bool grph_set_stat[512][512]; void grs_close(void) { signal(SIGPIPE,SIG_IGN);// To make sure that we do not trigger ourselve again after closing pipe signal(SIGCHLD,SIG_IGN);// To make sure that we do not trigger ourselve again after killing the child broken_pipe=1; if (fd_pipe !=-1) { close(fd_pipe); fd_pipe=-1; } if (pid != (pid_t) -1) { kill(pid, SIGTERM); /* Wait until grace exit */ waitpid (pid, NULL, 0); } free (buf); } void grs_close2(int sigvoid) { grs_close(); } /* * try to send data to grace (on pass only) */ static int grs_write(int left) { int written; written = write(fd_pipe, buf, left); if (written > 0) { left -= written; if (left > 0) { /* move the remaining characters (and the final '\0') */ bcopy(buf + written, buf, left + 1); } else { /* clear the buffer */ *buf = '\0'; } } else if (written < 0) { printf("grplot:problem writing to pipe !\n"); if (errno == EPIPE) /* Grace has closed the pipe : we cannot write anymore */ grs_close(); return (-1); } return (left); } int grs_open_pipe(char* exe, int bs, ...) { int i, fd[2]; int retval; char fd_number[4]; va_list ap; char **arglist; char *s; int numarg; if (fd_pipe != -1) { printf("grplot:Grace subprocess already running\n"); return (-1); } /* Set the buffer sizes according to arg */ if (bs < 64) { printf("grplot:The buffer size in GraceOpenVA should be >= 64\n"); return (-1); } bufsize = bs; bufsizeforce = bs / 2; if (ate_already==0) { atexit(grs_close); ate_already=1; } /* Make the pipe */ if (pipe(fd)) { printf("grplot:problem creating the pipe !\n"); return (-1); } else signal(SIGPIPE, grs_close2); //add watch on pipe only if pipe is successfully opened. /* Fork a subprocess for starting grace */ pid = vfork(); if (pid == (pid_t) (-1)) { printf("grplot: problem forking child process !\n"); return (-1); } /* If we are the child, replace ourselves with grace */ if (pid == (pid_t) 0) { for (i = 0; i < OPEN_MAX; i++) { /* we close everything except stdin, stdout, stderr and the read part of the pipe */ if (i != fd[0] && i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO) { close(i); } } /* build the argument list */ va_start(ap, bs); numarg = 3; arglist = (char **) malloc((numarg + 1)*sizeof(char *)); arglist[0] = exe; arglist[1] = "-dpipe"; sprintf(fd_number, "%d", fd[0]); arglist[2] = fd_number; while ((s = va_arg(ap, char *)) != NULL) { numarg++; arglist = (char **) realloc(arglist, (numarg + 1)*sizeof(char *)); arglist[numarg - 1] = (char *) malloc((strlen(s) + 1)*SIZEOF_CHAR); strcpy(arglist[numarg - 1], s); } arglist[numarg] = NULL; va_end(ap); retval = execvp(exe, arglist); if (retval == -1) { printf( "grplot: Cannot start %s\n", exe); exit(1); } else { exit(0); } } /* We are the parent -> keep the write part of the pipe and allocate the write buffer */ if (pid!=(pid_t)0 && pid!=(pid_t)(-1)) signal(SIGCHLD, grs_close2); buf = (char *)malloc(bufsize); if (buf == NULL) { printf("grplot: Not enough memory"); close(fd[0]); close(fd[1]); return (-1); } *buf = '\0'; close(fd[0]); fd_pipe = fd[1]; broken_pipe = 0; return (0); } int grs_is_open(void) { return (fd_pipe >= 0) ? 1 : 0; } int grs_flush(void) { int loop, left; if (fd_pipe == -1) { printf("grplot:No grace subprocess\n"); return (-1); } left = strlen(buf); for (loop = 0; loop < 30; loop++) { left = grs_write(left); if (left < 0) { return (-1); } else if (left == 0) { return (0); } } printf("grplot: flush ran into eternal loop"); return (-1); } int grs_cmd(const char * cmd) { int left; if (fd_pipe == -1) { printf("grplot:No grace subprocess\n"); return (-1); } /* Append the new string to the global write buffer */ if (strlen(buf) + strlen(cmd) + 2 > (unsigned) bufsize) { printf("grplot: Buffer full"); return (-1); } strcat(buf, cmd); strcat(buf, "\n"); left = strlen(buf); /* Try to send the global write buffer to grace */ left = grs_write(left); if (left >= bufsizeforce) { if (grs_flush() != 0) { return (-1); } } else if (left < 0) { return (-1); } return (0); } int grs_printf(const char* fmt, ...) { va_list ap; char* str; int nchar; if (fd_pipe == -1) { printf("grplot:No grace subprocess\n"); return (0); } /* Allocate a new string buffer for the function arguments */ str = (char *) malloc ((size_t) bufsize); if (str == (char *) NULL) { printf("grplot: Not enough memory"); return (0); } /* Print to the string buffer according to the function arguments */ va_start (ap, fmt); nchar = vsprintf (str, fmt, ap); va_end (ap); nchar++; /* This is for the appended "\n" */ if (grs_cmd(str) == -1) { nchar = 0; } free (str); return (nchar); } DEFUN_DLD (grplot, args, , "grplot(): A plotting tool for use with Grace\n\ grplot() : start the xmgrace child process.\n\ grplot(X): plot a real vector X versus indices\n\ grplot(X,Y): plot real vector X versus real vector Y\n") { ColumnVector out(1); int narg (args.length()); int i; sigset_t set,oset; sigemptyset(&set); sigaddset(&set, SIGINT); sigprocmask(SIG_BLOCK, &set, &oset); if (!grs_is_open()) { out.elem(0)=grs_open_pipe("xmgrace",8192,"-noask","-free", NULL); } if (holdon==0) { for (i=0;grph_set_stat[cur_graph][i]>0;i++) { grs_printf("kill g%i.s%i",cur_graph,i); grph_set_stat[cur_graph][i]=0; } cur_set=0; } else cur_set++; grs_printf("g%i type xy",cur_graph); grs_cmd("autoscale onread xyaxes"); grph_set_stat[cur_graph][cur_set]=1; if (narg!=0) { if (args(0).is_real_matrix()) { ColumnVector X (args(0).vector_value()); if (narg==1) for (i=0;i