*
* GraphMatrix graphs a rectangular array of series on separate graphs.
* The user can control the maximum number of graphs which can be placed
* either horizontally or vertically; if needed, the procedure will create
* as many pages as necessary in order to display the graphs. For instance,
* if you have an 8x8 matrix and set the row and column limits to 3, you'll
* get nine pages, since you need three blocks in each direction. Pages that
* aren't full will still be blocked out to match the other pages.
*
* There is also an option to produce a common scale across rows, down columns
* on across the entire matrix.
*
* Syntax:
*   @GraphMatrix( options )  data
*
* Parameters:
*    data is a RECT of SERIES (such as impulse responses)
*
* Options:
*    ROWLIMIT=maximum number of rows on a page [rows in data]
*    COLLIMIT=maximum number of columns on a page [cols in data]
*    COMMONSCALE=[NONE]/ROWS/COLS/ALL determines whether a common scale is
*      used. For instance, COMMONSCALE=ROWS means that all graphs in a row
*      will have the same scale, but different rows might not.
*    XLABELS=VECT[STRINGS] of labels for the columns [not used]
*    YLABELS=VECT[STRINGS] of labels for the rows [not used]
*
* Revision Schedule
*   07/05 Written by Tom Doan, Estima
*
* Example: data is a 5x5 RECT of SERIES. This will do three pages with
* two columns (of five rows) on the first two pages and one column on the
* third page.
*
*  @GraphMatrix(collimit=2,commonscale=none,$
*     xlabels=||'abc','def','ghi','jkl','mno'||,ylabels=||'123','456','789','012','345'||) data
*
procedure GraphMatrix mseries
type rect[series] mseries
*
option int rowlimit
option int collimit
option choice commonscale 1 none rows cols all
option vect[strings] xlabels
option vect[strings] ylabels
*
local vect rowmax colmax rowmin colmin
local rect elemax elemin
local real maxall minall
local int rows cols maxrows maxcols
local int i j iblock jblock ilimit jlimit
local vect[strings] xlx ylx
*
compute rows=%rows(mseries)
compute cols=%cols(mseries)

if .not.%defined(rowlimit)
   compute maxrows=rows
else
   compute maxrows=rowlimit

if .not.%defined(collimit)
   compute maxcols=cols
else
   compute maxcols=collimit

dim rowmax(rows) rowmin(rows) colmax(cols) colmin(cols)
dim elemax(rows,cols) elemin(rows,cols)
*
* Figure out the extreme values across the rows and columns
*
do i=1,rows
   do j=1,cols
      ext(noprint) mseries(i,j)
      if j==1
         compute rowmax(i)=%maximum,rowmin(i)=%minimum
      else
         compute rowmax(i)=%max(rowmax(i),%maximum),rowmin(i)=%min(rowmin(i),%minimum)
      if i==1
         compute colmax(j)=%maximum,colmin(j)=%minimum
      else
         compute colmax(j)=%max(colmax(j),%maximum),colmin(j)=%min(colmin(j),%minimum)
   end do j
end do i
*
* All overall
*
compute maxall=%maxvalue(rowmax),minall=%minvalue(rowmin)
*
* Depending upon the choice for commonscale, set the max and min
* to be used on each graph in the array.
*
if commonscale==1 {
   ewise elemax(i,j)=%na
   ewise elemin(i,j)=%na
}
else
if commonscale==2 {
   ewise elemax(i,j)=rowmax(i)
   ewise elemin(i,j)=rowmin(i)
}
else
if commonscale==3 {
   ewise elemax(i,j)=colmax(j)
   ewise elemin(i,j)=colmin(j)
}
else {
   ewise elemax(i,j)=maxall
   ewise elemin(i,j)=minall
}
*
*  Loop over the pages based upon rows
*
do iblock=1,rows,maxrows
*
*     Copy in the row labels
*
   compute ilimit=%imin(rows,iblock+maxrows-1)
   if %defined(ylabels) {
      dim ylx(ilimit-iblock+1)
      ewise ylx(i)=ylabels(iblock+i-1)
   }
   else
      dim ylx(0)
*
*     Now loop over page breaks based upon columns
*
   do jblock=1,cols,maxcols
*
*        And copy in the column labels
*
      compute jlimit=%imin(cols,jblock+maxcols-1)
      if %defined(xlabels) {
         dim xlx(jlimit-jblock+1)
         ewise xlx(j)=xlabels(jblock+j-1)
      }
      else
         dim xlx(0)
*
*        Set up the graph matrix for this page. Note that we always
*        use maxrows x maxcols fields, even on partially filled pages
*        so each graph will be the same size.
*
      spgraph(vfields=maxrows,hfields=maxcols,xlabels=xlx,ylabels=ylx)
      do i=iblock,ilimit
         do j=jblock,jlimit
            graph(max=elemax(i,j),min=elemin(i,j)) 1 (j-jblock+1) (i-iblock+1)
            # mseries(i,j)
         end do j
      end do i
      spgraph(done)
   end do jblock
end do iblock
end

