A LIBINCLUDE Interface to MATLAB for PLOTTING from GAMS


Michael C. Ferris

A batinclude file "matplot" is provided that allows you to use MATLAB for plotting plots directly from GAMS. This package assumes that GAMS is the client and MATLAB is the server, ie you just run GAMS and this sets up and runs MATLAB for you.

The simplest usage is via the syntax: $libinclude matplot A

In this case, A is a one or two dimensional parameter. The first index runs over the points to be plotted on a given line. The second index runs over the different lines to be superimposed on the plot.

The libinclude creates a file "matplot.m" containing all the commands needed to create the plot, and executes these commands using a "matlab engine". The "matplot.m" file is left in the current directory allowing modification and direct running from MATLAB at a later time if required.

The examples and mechanism for carrying this out are adapted from the GNUPLOT plotting interface to GAMS written by Tom Rutherford. He deserves much credit for this interface.


Contents:

  • Hardware and software requirements

  • Installation

  • Frequently asked questions about using GNUPLOT with GAMS

  • Environment variables

  • Some examples



    Hardware and software requirements:

    1. A machine running both GAMS and MATLAB
    2. GAMS version 2.25.089 or later (released in October, 1996).


    Installation:

    1. Ensure that the GAMS system directory is on your system path. 2. Copy matplot.zip into your GAMS system directory and run unzip matplot
    If you are on a SOLARIS box or a PC box, you are done.
    3. If you are not running on a SOLARIS box or a PC box, then you need to (mex)-compile the file matplot.c that is now in your GAMS system directory. The details are platform specific and can be found on pages 6-14 - 6-18 of the MATLAB API Guide.


    Environment variables:

    In GAMS, an environment variable is set with a statement such as:

    $setglobal variable  value
    

    This passes a variable with a specified value to MATLAB. The following variables are understood:

    domainSpecifies the domain on the x-axis of data which are to be displayed. (Note: this parameter may be specified as the second argument on the $libinclude call.)
    seriesSpecifies the data series (individual output plots) which are to be displayed. (Note: this parameter may be specified as the third argument on the $libinclude call.)
    labelsSubset of X axis labels to be displayed on graph.
    xvalueSpecifies a parameter or column containing the x-axis values -- included to permit generating graphs with unequal intervals. (The package first looks to see if there is a parameter named %xvalue%. If there is no parameter with that name, it then looks for a datacolumn with that name.)
    batchSpecifying $setglobal batch yes indicates that MATPLOT should be called in batch mode. When this switch is omitted, MATPLOT awaits the user's click before closing the graph window.

    The following extra environment variables can be used as well.

    gp_figure: Specifies the number of a new figure to be created.
    
    gp_key: This specifies the location of the legend on the plot
            0 = Automatic "best" placement (least conflict with data, default)
            1 = Upper right-hand corner
            2 = Upper left-hand corner
            3 = Lower left-hand corner
            4 = Lower right-hand corner
           -1 = To the right of the plot
    [Note: can change location with mouse after the plot is drawn].
    
    gp_xscale: This gives the scaling of the x axis within the figure
    (typical value less than or equal to 1, default 1.
    
    gp_yscale: This gives the scaling of the y axis within the figure,
    default = xscale.
    
    [Note: can use mouse to change the size of figure after plot is
    drawn].
    
    gp_opt0: string to pass additional MATLAB commands to the plotting
    routine. This is put into matplot.m before the plot is issued.
    
    gp_opt1,gp_opt2,....,gp_opt19: strings to pass additonal MATLAB
    commands to the plotting routine.  These are added to the end of
    matplot.m in the order specified by their numbering.
    
    

    Some examples:

    (matplotex.zip)

    ex0.gms

    $title  Example 0: Plot a one dimensional vector to the screen
    
    set t /1990*2030/;
    
    parameter a(t)  Example 0: Generic output to the screen (default invocation);
    a("1990") = 1;
    loop(t,  a(t+1) = a(t) * (1 + 0.04 * uniform(0.2,1.8)); );
    
    *        I know that a() is defined over set t.  The plotting package
    *       knows that the argument has one dimension, but it does not know
    *       what set defines those entry.  Three ways to pass the domain:
    
    *       (i) Let GAMS figure out which elements of A are nonzero (not a problem
    *       here because the parameter is dense:
    
    $libinclude matplot A 
    
    *       (ii) Pass GAMS the domain on the call:
    
    $libinclude matplot A t
    
    *       (iii) Pass GAMS the domain in an environment vaiable:
    
    $setglobal domain t
    
    $libinclude matplot A
    

    ex1.gms

    $title  Example 1: Generic Invocation of MATPLOT
    
    set t /1990*2030/, j /a,b,c,d/;
    
    parameter a(t,j)  Example 1: Generic output to the screen (default invocation);
    a("1990",j) = 1;
    loop(t,  a(t+1,j) = a(t,j) * (1 + 0.04 * uniform(0.2,1.8)); );
    
    $setglobal gp_key 2
    $libinclude matplot A
    

    ex2.gms

    $title  Example 2: Directing MATPLOT Output to File
    
    set t /1990*2030/, j /a,b,c,d/;
    
    parameter a(t,j)  Random time series with a trend; 
    a("1990",j) = 1;
    loop(t,  a(t+1,j) = a(t,j) * (1 + 0.04 * uniform(0.2,1.8)); );
    
    
    $setglobal gp_figure 1
    $setglobal gp_key 4
    $setglobal gp_opt1
    $libinclude matplot A
    
    $setglobal batch yes
    
    $setglobal gp_opt1 "print -dpsc ex2.ps"
    $libinclude matplot A
    
    $setglobal gp_opt1 "print -depsc -epsi ex2.eps"
    $libinclude matplot A
    
    $setglobal gp_xscale 0.8
    $setglobal gp_opt1 "print -djpeg ex2.jpg"
    $libinclude matplot A
    
    

    The JPEG file generated by ex2.gms:

    ex3.gms

    $title  Example 3: Graphs with Labels and Titles
    
    set t /0*40/, j /a,b,c,d/;
    
    *       Note: where we specify descriptive text for subset elements,
    *       it is then displayed in place of the subset index on the 
    *       graph -- i.e. 1990,2000 etc. are displayed, not 0,10,...
    
    set decade(t) / 0 1990, 10 2000, 20 2010, 30 2020, 40 2030/;
    
    parameter a(t,j)  Example 3: Labels and Titles; 
    a("0",j) = 1;
    loop(t,  a(t+1,j) = a(t,j) * (1 + 0.04 * uniform(0.2,1.8)); );
    
    *       ---------------------------
    *       Generic plotting commands:
    
    $setglobal labels decade
    
    *       ---------------------------
    *       PLOT commands:
    
    $setglobal gp_figure 2
    $setglobal gp_opt1 "title('Graph of Random Time Series');"
    $setglobal gp_opt2 "xlabel('Year -- time step annual');"
    $setglobal gp_opt3 "ylabel('Value');"
    $libinclude matplot A
    
    $setglobal gp_xscale 0.6
    $setglobal gp_opt4 "print -djpeg ex3.jpg"
    $libinclude matplot A
    
    

    The JPEG file generated by ex3.gms:

    ex4.gms

    $title  Example 4: Changes the graph size, y range and location of key:
    
    set t /1990*2030/, j /a,b,c,d/;
    
    set decade(t) / 1990 'michael', 2000, 2010, 2020, 2030/;
    
    parameter a(t,j)  Example 4: Changing graph size and scaling ;
    a("1990",j) = 1;
    loop(t,  a(t+1,j) = a(t,j) * (1 + 0.04 * uniform(0.2,1.8)); );
    
    $setglobal labels decade
    
    $setglobal gp_key 1
    $setglobal gp_xscale 0.8
    
    $setglobal gp_opt1 "xlabel('Year -- time step annual');"
    $setglobal gp_opt2 "ylabel('Value');"
    $setglobal gp_opt3 "grid"
    $setglobal gp_opt4 "v = axis; v(3:4) = [0 3]; axis(v);"
    $libinclude matplot A
    
    $setglobal batch yes
    $setglobal gp_opt5 "print -djpeg ex4.jpg"
    $libinclude matplot A
    
    

    The JPEG file generated by ex4.gms:

    ex5.gms

    $title  Example 5: Unequally spaced data
    
    set t /0*40/, j /a,b,c,d/; 
    parameter a(t,j)  Example 5: Missing data represented by NA;
    a("0",j) = 1;
    loop(t,  a(t+1,j) = a(t,j) * (1 + 0.04 * uniform(0.2,1.8)); );
    
    set decade(t) / 0 1990, 10 2000, 20 2010, 30 2020, 40 2030/;
    parameter year(t); year(t) = 1989 + ord(t);
    
    * Omit some data points randomly, indicating these as missing
    * by assigning values equal to na:
    
    a(t,j)$(uniform(0,1) le 0.25) = na;
    
    $setglobal labels decade
    $setglobal xvalue year
    
    $setglobal gp_key 0
    $setglobal gp_figure 1
    $setglobal gp_opt1 "set(gp.plot,'Marker','x');"
    $setglobal gp_opt2 "xlabel('Year -- time step annual');"
    $setglobal gp_opt3 "ylabel('Value');"
    $libinclude matplot A
    
    $setglobal gp_xscale 0.9
    $setglobal gp_yscale 0.7
    $setglobal gp_opt4 "print -djpeg ex5.jpg"
    $libinclude matplot A
    
    

    The JPEG file generated by ex5.gms:

    ex6.gms

    $title  Example 6: Dealing with Zero Rows and Zero Columns
    
    set     i       evaluation points       /1990*2000/
            j       various time seris      /a, b, c, d/;
    
    $setglobal labels i
    
    table  time_path(i,j)  Time series with holes
    
            a       b       c       d
    1990    0       2       0       0
    1991    1       2       1       0
    1992    2       3       4       0
    1993    3       4       0       0
    1994    4       0       2       0
    1995    0       0       0       0
    1996    1       2       3       0
    1997    2       3       4       0
    1998    3       4       5       0
    1999    4       5       6       0
    2000    5       1       7       0;
    
    *       Note that time series d is all zeros, and 
    *       all of the time series equals zero in 1995.
    
    *       Problem:        Get matplot.gms to pass zero files
    *                       through to the plotting package.
    
    
    $setglobal gp_key 2
    $setglobal gp_xscale 0.9
    $setglobal gp_yscale 0.6
    
    $setglobal gp_opt1 "title('Problem: 1995 and series D are both zero.');"
    $libinclude matplot time_path
    
    $setglobal batch yes
    $setglobal gp_opt2 "print -djpeg ex6a.jpg"
    $libinclude matplot time_path
    $setglobal gp_opt2
    $setglobal batch no
    
    *       Define an explicit domain and series:
    
    $setglobal domain i
    $setglobal series j
    
    $setglobal gp_opt1 "title('One solution: define domain and series');"
    $libinclude matplot time_path
    
    $setglobal batch yes
    $setglobal gp_opt2 "print -djpeg ex6b.jpg"
    $libinclude matplot time_path
    $setglobal gp_opt2
    $setglobal batch no
    
    *       Drop the domain and series definition:
    
    $setglobal domain
    $setglobal series 
    
    *       Method 2: replace zero by eps
    
    time_path(i,j)$(not time_path(i,j)) = eps;
    
    $setglobal gp_opt1 "title('Another solution: replace zero by eps.');"
    $libinclude matplot time_path
    
    $setglobal batch yes
    $setglobal gp_opt2 "print -djpeg ex6c.jpg"
    $libinclude matplot time_path
    $setglobal gp_opt2
    $setglobal batch no
    
    JPEG files generated by ex6.gms:

    ex7.gms

    $title Example 7: Plotting Multiple Independent Series 
    
    set             i       observation counts /1*4/,
                    g       graphs /a, b, c/;
    
    table data(i,*,g)
    
            x.a     y.a     x.b     y.b     x.c     y.c
    1       1       1       0       2       1       6
    2       2       2       3       2       2       4
    3       4       3       5       5       3       3
    4       10      4       7       6       4       1;
    
    *       First define a set which can hold 4 observations x 
    *       3 plot series:
    
    set     p       plot points /1*12/
    
    set pp(p);
    
    pp("1") = yes;
    
    parameter       x       X coordinate for a given point,
                    y       Series values for points;
    
    
    *       The next statement is crucial -- initialize
    *       all plot points to NA (missing).  The package
    *       will then only plot those items which are 
    *       specified.
    
    y(p,g) = na;
    loop(g,
            loop(i,
              x(pp)   = data(i,"x",g);
              y(pp,g) = data(i,"y",g);
              pp(p+1)$pp(p) = yes;
              pp(p)$pp(p+1) = no;
            );
    );
    display x, y;
    
    $setglobal domain p
    $setglobal xvalue x
    
    $setglobal gp_opt1 "grid;"
    $setglobal gp_opt2 "set(gca,'TickDir','out');"
    
    $libinclude matplot y
    
    *       The X coordinates may also be passed as a column in the matrix.
    
    y(p,"xv") = x(p);
    
    $setglobal xvalue xv
    $libinclude matplot y
    
    $setglobal gp_xscale 0.7
    $setglobal gp_yscale 0.6
    $setglobal gp_opt3 "print -djpeg ex7.jpg"
    $libinclude matplot y
    
    JPEG file generated by ex7.gms:

    ex8.gms

    $title Example 8: Plotting Two-Dimensional Series 
    
    set     i       Commodities     /i1*i3/,
            r       Regions         /r1*r3/,
            t       Time periods    /2000*2100/
            s(i,r)  Plot series;
    
    s(i,r) = yes;
    
    parameter       prices(t,i,r)   Commodity prices;
    
    
    prices(t,i,r) = 1;
    loop(t,  prices(t+1,i,r) = prices(t,i,r) * (1 + 0.04 * uniform(0.2,1.8)); );
    
    $setglobal domain t
    
    $setglobal gp_key 2
    $setglobal series s
    * before matplot option: give 9 different colors to lines
    $setglobal gp_opt0 "set(0,'DefaultAxesColorOrder',rand(9,3));"
    * remove border around legend box
    $setglobal gp_opt1 "h = findobj('type', 'axes'); set(h(1), 'visible', 'off');"
    $libinclude matplot prices 
    
    $setglobal gp_xscale 0.9
    $setglobal gp_yscale 0.8
    * before matplot option: cycle through line styles
    $setglobal gp_opt0 "set(0,'DefaultAxesColorOrder',[0 0 0]); set(0,'DefaultAxesLineStyleOrder','-|:|-.|--|x|o|+|d|v')"
    $setglobal gp_opt2 "print -djpeg ex8.jpg"
    $libinclude matplot prices 
    
    
    
    JPEG file generated by ex8.gms:

    ex9.gms

    $title Example 9: Contour Plotting Example
    
    set     i /1*20/;
    alias (i,j);
    
    parameter       a(i,j)  Evaluation of xy
                    x(i)    Ages of individuals
                    y(j)    Number of individuals;
    
    x(i) = ord(i) - 10;
    y(j) = ord(j) - 10;
    
    
    loop((i,j), a(i,j) = x(i) * y(j); );
    
    $setglobal gp_opt1 "xlabel('value of X');"
    $setglobal gp_opt2 "ylabel('value of Y');"
    $setglobal gp_opt3 "title('Evaluation of xy');"
    
    $libinclude contour a i j
    
    $setglobal batch yes
    $setglobal gp_opt4 "print -dpsc -epsi ex9.ps"
    
    $libinclude contour a i j
    
    $setglobal gp_opt4 "print -djpeg ex9.jpg"
    
    $libinclude contour a i j
    
    JPEG file generated by ex9.gms:

    Frequently asked questions about using MATPLOT with GAMS:

    How can I move MATPLOT output into a paper or presentation?

    Figures may be copied to the Windows clipboard (use Edit -> Copy Figure, or the MATLAB commands "print -dmeta" or "print -dbitmap"). This provides a Windows-compatible image which can be pasted into any number of applications.

    Alternative, you can produce publication-quality figures by loading MATPLOT output into LaTeX. The graphicx package can be used in association with EPSI files generated using "print -depsc -epsi figname.ps". Several examples are given above. Also see the MATLAB command "help print".

    How do I represent missing values?

    MATPLOT.GMS uses use the special GAMS numeric value "NA" to represent missing data.

    Can I regenerate a plot using MATPLOT independent of GAMS?

    Yes. If you look at files matplot.m and GNUPLOT.DAT after GAMS has exited, you will find that these contain all the MATLAB commands and data required to generate the last plot from your GAMS code. To reproduce the graph, execute matplot.m within MATLAB. Can I make MATLAB the cleint?

    A more complete interface between GAMS and MATLAB (that makes MATLAB the client and GAMS the server) can be obtained from MATLAB for visualization.


    The software comes with no guarantees and can be freeely used on an "as is" basis. The author remains responsible for any bugs which exist in this software. This software is not officially supported by GAMS Corporation.