14.16. Photon: Setting Up Plots - make_graph, make_CwGraph_points

These two functions plot the query results using Cogent's CwGraph widget. The make_graph function creates a new CwGraph widget and sets up its resources. Each time new values are plotted, this function is called, but it doesn't create a new CwGraph widget each time. Using the grf variable assigned to the widget, we can change the value ranges and traces that get displayed, without recreating the widget.

   /*--------------------------------------------------------------------
    * Function:    make_graph
    * Returns:     a CwGraph widget
    * Description: Sets up a CwGraph widget to plot the query results.
    *------------------------------------------------------------------*/
   function make_graph (xmin, xmax, ymin, ymax, xlist, ylist, dband)
   {
     local grf;
   
     /* Set a size for the points created by make_CwGraph_points. */
     local xdist = (xmax - xmin) * .007;
     local ydist = (ymax - ymin) * .007;
     
     if (undefined_p(GraphWidget) || !GraphWidget)
       {
         /* Make a new graph, if one doesn't already exist. */
         PtSetParentWidget (hw.GraphPane);
         GraphWidget = new(CwGraph);
         
         GraphWidget.SetArea(0, 0, hw.GraphPane.dim.w, hw.GraphPane.dim.h);
         GraphWidget.fill_color = 0xffffe5;
         GraphWidget.bot_border_color = 0x000000;
         GraphWidget.graph_y_label_left = "Y history";
         GraphWidget.graph_x_font = anyos_assign("graph_font");
         GraphWidget.graph_y_font_left = anyos_assign("graph_font");
         GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_AXIS_RIGHT);
         GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_AXIS_LABEL_RIGHT);
         GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_AXIS_TITLE_RIGHT);
         GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_MAJOR_TICK_RIGHT);
         GraphWidget.ClearBit(#graph_flags, Cw_GRAPH_Y_MINOR_TICK_RIGHT);
         
         PtAttachCallback (hw.GraphPane, Pt_CB_RESIZE,
                           `GraphWidget.SetArea(0, 0, hw.GraphPane.dim.w,
                                                hw.GraphPane.dim.h));
       }
   
     /* Change the tick size and scale of the existing graph for a new data plot. */
     grf = GraphWidget;
     
     grf.graph_x_major_tick = (xmax - xmin) / 5;
     grf.graph_x_minor_tick = (xmax - xmin) / 25;
     grf.graph_y_major_tick_left = (ymax - ymin) / 5;
     grf.graph_y_minor_tick_left = (ymax - ymin) / 25;
     grf.graph_xmin = xmin;
     grf.graph_xmax = xmax;
     grf.graph_ymin_left = ymin;
     grf.graph_ymax_left = ymax;
     grf.graph_traces = 3;
     
     if (xmax > 1000)
       grf.graph_x_label = "Time (number of seconds after midnight)";
     else
       grf.graph_x_label = "X history";
   
     /* Assign trace limits and colors for the new data plot. */
     CwGraphSetYLimits(grf, 0, ymin, ymax);
     CwGraphSetYLimits(grf, 1, ymin, ymax);
     CwGraphSetYLimits(grf, 2, ymin, ymax);
     
     CwGraphSetTraceColor(grf, 0, 0xdd00aa);
     CwGraphSetTraceColor(grf, 1, 0x0000aa);
     CwGraphSetTraceColor(grf, 2, 0x00aa00);
   
     /* Create the traces for the new data plot. */
     if(dband == "NONE")
       CwGraphAddXYPoints(grf, 0, make_CwGraph_points(xlist, xdist, t),
                          make_CwGraph_points(ylist, ydist, nil));
     else if(dband == "DB")
       CwGraphAddXYPoints(grf, 1, make_CwGraph_points(xlist, xdist, t),
                          make_CwGraph_points(ylist, ydist, nil));
     else if(dband == "DBP")
       CwGraphAddXYPoints(grf, 2, make_CwGraph_points(xlist, xdist, t),
                          make_CwGraph_points(ylist, ydist, nil));
     
     PtRealizeWidget(grf);
   }
   

The make_CwGraph_points function is used to create a small, diamond-shaped box at each point in the CwGraph trace. This is especially useful for demonstrating the effect of applying deadbands, because you can see at a glance how many points actually get plotted.

When applied to both the X and Y point lists, this function adds 5 new points in a diamond shape around each point in the plot. Of course, this increases the size of the plot by 500%, but the number of points that the CwGraph widget can plot is limited only by available memory, so the effect is negligible, as far as the demo is concerned. Plotting over 200,000 points, which is roughly the equivalent of an hour's worth of recorded data (including the diamond-shaped boxes), you might notice some decline in speed, but at that point the trace would fill so much of the space as to be unreadable anyway.

This function uses the Gamma list_to_array function to change the list of points into an array to facilitate adding elements, and then the array_to_list function to change it back. The Gamma insert function is used to insert the new elements.

   /*--------------------------------------------------------------------
    * Function:    make_CwGraph_points
    * Returns:     a list
    * Description: Applied to the x and y arguments of the CwGraphAddXYPoints()
    *              function, which are lists. This function destructively
    *              modifies those lists, adding extra values that, when plotted
    *              by CwGraph, render as small, diamond-shaped points. The xval
    *              parameter must be set to t for the x-coordinate, and to nil
    *              for the y coordinate.
    *------------------------------------------------------------------*/
   function make_CwGraph_points (ptlist, ptsize, xval)
   {
     parray = list_to_array(ptlist);
     i = 0;
     if(xval)
       {
         /* Add x-values to the trace. */ 
         while (i < length(parray))
           {        
             insert(parray, i+1, parray[i] + (ptsize));
             insert(parray, i+2, parray[i]);
             insert(parray, i+3, parray[i] - (ptsize));
             insert(parray, i+4, parray[i]);
             insert(parray, i+5, parray[i] + (ptsize));
             insert(parray, i+6, parray[i]);
             i = i + 7;
           }
       }
     else
       {
         /* Add y-values to the trace. */ 
         while (i < length(parray))
           {        
             insert(parray, i+1, parray[i]);
             insert(parray, i+2, parray[i] - (ptsize));
             insert(parray, i+3, parray[i]);
             insert(parray, i+4, parray[i] + (ptsize));
             insert(parray, i+5, parray[i]);
             insert(parray, i+6, parray[i]);
             i = i + 7;
           }
       }
     ret = array_to_list(parray);
   }