Viewing contents of file '../idllib/contrib/markwardt/plotcube.pro'
;+
; NAME:
;   PLOTCUBE
;
; AUTHOR:
;   Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
;   craigm@lheamail.gsfc.nasa.gov
;
; PURPOSE:
;   Plots a three dimensional data that can be printed and made into a cube
;
; CALLING SEQUENCE:
;   PLOTCUBE, x, y, z
;
; DESCRIPTION: 
;
;   PLOTCUBE plots a three dimensional data set so that it can be
;   printed on paper, cut out, and folded together to make a real-life
;   three dimensional cube.  This may be useful in visualization
;   applications.  The six faces of the cube contain a projection of
;   the data onto that face.
;
;   The output consists of a flat matrix of six plots, which are
;   joined together at the proper edges of the cube.  Your task,
;   should you choose to accept it, is to cut out the cube and
;   assemble it.
;
;   Before folding the cube together, it will look like the diagram
;   below.  You need to match together edges labelled with the same
;   letter.
;
;                            A
;                          +----+
;                         B|    |G
;                      B   |    |   G
;                     +----+----+----+
;                     |    |    |    |
;                    C|    |    |    |E
;                     +----+----+----+
;                      D   |    |   F
;                         D|    |F
;                          +----+
;                          |    |
;                         C|    |E
;                          +----+
;                            A
;
;   HINT 1: When printing, be sure that the XSIZE and YSIZE are given
;           in the ratio of 3 to 4.  A size of 6 in by 8 in is
;           suitable.
;
;   HINT 2: As a practical matter for assembling the cube once it has
;           been printed, you should leave some extra paper tabs so
;           that adhesive can be applied.
;
; INPUTS:
;
;   X, Y, Z - Three arrays which specify position in three dimensional
;             space.  All three arrays should be of the same length.
;
; OPTIONAL INPUTS:
;   NONE
;
; INPUT KEYWORD PARAMETERS:
;
;   PANEL, SUBPANEL - An alternate way to more precisely specify the
;                     plot and annotation positions.  See SUBCELL.
;                     Default is full-screen.
;
;   XRANGE, YRANGE, ZRANGE - gives plot range for each dimension, as
;                            for other plot commands.  Default is
;                            range of data.
;
;   XTITLE, YTITLE, ZTITLE - gives title for each axis.  The title
;                            labels each face of the cube where
;                            possible.
;
;   NOERASE - If set, the display is not erased before graphics
;             operations.
;
;   Other options are passed along to the PLOT command directly.
;
; OUTPUTS:
;   NONE
;
; PROCEDURE:
;
; EXAMPLE:
;
;   This example takes some synthetic data and makes a cube out of it.
;   Visualizing the trace of the curve is more convenient when it can
;   be projected on the cube in each dimension.
;
;   t = findgen(200)/20. - 10.
;   x = cos(t)
;   y = sin(t) + 0.05*t
;   z = exp(t) + 0.05*randomn(seed, 200)
;   plotcube, x, y, z, xrange=[-1.5,1.5], yrange=[-1.5,1.5], zrange=[-1.5,1.5]
;
; SEE ALSO:
;
;   DEFSUBCELL, SUBCELLARRAY
;
; EXTERNAL SUBROUTINES:
;
;   SUBCELL, DEFSUBCELL, PLOTPAN
;
; MODIFICATION HISTORY:
;   Written, CM, 1997
;
;-

forward_function defsubcell, subcell

pro plotpan, x, y, $
             subpanel=subpanel, panel=panel, $
             _EXTRA=extra

  ;; Default is full-screen
  if n_elements(panel) EQ 0 AND n_elements(subpanel) EQ 0 then begin
      plot, x, y, /normal, _EXTRA=extra
  endif else begin
      if n_elements(panel) EQ 0 then panel=[0.0,0.0,1.0,1.0]
      plot, x, y, /normal, position=subcell(subpanel, panel, /marg), $
        _EXTRA=extra
  endelse

  return
end

function defsubcell, default

  if n_elements(default) EQ 0 then default = [-1.,-1,-1,-1]
  mysubcell = default
  defaultsubpos = [ 0.08, 0.08, 0.95, 0.95 ]

  iwh = where(mysubcell LT 0, ict)
  if ict GT 0 then $
    mysubcell(iwh) = defaultsubpos(iwh)

  return, mysubcell
end
function subcell, subpos, position, margin=margin

  ;; Default value for subposition
  if n_elements(subpos) EQ 0 then mysubpos = [-1.,-1,-1,-1] $
  else mysubpos = subpos

  ;; Default value for position - full screen
  if n_elements(position) EQ 0 then position = [0.,0.,1.,1.]

  ;; Get margins if necessary
  if keyword_set(margin) EQ 1 OR n_elements(subpos) EQ 0 then $
    mysubpos = defsubcell(mysubpos)

  ;; Compute new window position
  x0 = position(0)
  y0 = position(1)
  dx = position(2)-position(0)
  dy = position(3)-position(1)

  newsubpos = reform(mysubpos * 0, 4)
  newsubpos([0,2]) = x0 + dx * mysubpos([0,2])
  newsubpos([1,3]) = y0 + dy * mysubpos([1,3])

  return, newsubpos
end

  
pro subcellarray, xdivs, ydivs, newpanels, newsubpanels, $
                  panel=panel, subpanel=subpanel

  nx = n_elements(xdivs)
  ny = n_elements(ydivs)
  xd = double(xdivs)/total(xdivs)
  yd = double(ydivs)/total(ydivs)
  
  newpanels = dblarr(nx, ny, 4)
  newsubpanels = dblarr(nx, ny, 4) - 1.
  
  if n_elements(panel)    EQ 0 then panel    = [0.D,0.,1.,1.]
  if n_elements(subpanel) EQ 0 then subpanel = [-1.,-1.,-1.,-1.]
  
  subpanel1 = defsubcell(subpanel)
  
  xmarg = subpanel1(0)+(1.-subpanel1(2))
  ymarg = subpanel1(1)+(1.-subpanel1(3))
  
  xd = xd * (1. - xmarg)
  yd = yd * (1. - ymarg)

  xstart = 0.D
  for i = 0, nx-1 do begin
      xend = xstart + xd(i)
      spxstart = 0.
      spxend   = 1.
      if i EQ 0    then xend = xend + subpanel1(0)
      if i EQ nx-1 then xend = xend + (1.-subpanel1(2))
      if i EQ 0    then spxstart = subpanel1(0)/(xend - xstart)
      if i EQ nx-1 then spxend   = 1. - (1.-subpanel1(2))/(xend-xstart)
      ystart = 0.D
      for j = 0, ny-1 do begin
          yend = ystart + yd(j)
          spystart = 0.
          spyend   = 1.
          if j EQ 0    then yend = yend + subpanel1(1)
          if j EQ ny-1 then yend = yend + (1.-subpanel1(3))
          if j EQ 0    then spystart = subpanel1(1)/(yend-ystart)
          if j EQ ny-1 then spyend   = 1. - (1.-subpanel1(3))/(yend-ystart)

          
          newpanels(i,j,*) = subcell([xstart, ystart, xend, yend], panel)
          newsubpanels(i,j,*) = [spxstart, spystart, spxend, spyend]
          
          ystart = yend
      endfor
      
      xstart = xend
  endfor
  
  return
end

pro plotcube, x, y, z, $
              xrange=xrange, yrange=yrange, zrange=zrange, $
              xtitle=xtitle, ytitle=ytitle, ztitle=ztitle, $
              panel=panel, subpanel=subpanel, $
              noerase=noerase, $
              _EXTRA=extra

  ;; Default is full-panel
  if n_elements(panel) EQ 0 then panel=[0.0,0.0,1.0,1.0]
  if n_elements(subpanel) EQ 0 then subpanel=[-1.,-1,-1,-1]
  if n_elements(noerase) EQ 0 then noerase=0

  if n_elements(xrange) EQ 0 then xrange = [ min(x), max(x) ]
  if n_elements(yrange) EQ 0 then yrange = [ min(y), max(y) ]
  if n_elements(zrange) EQ 0 then zrange = [ min(z), max(z) ]

  if n_elements(xtitle) EQ 0 then xtitle = 'X'
  if n_elements(ytitle) EQ 0 then ytitle = 'Y'
  if n_elements(ztitle) EQ 0 then ztitle = 'Z'

  subcellarray, [1,1,1], [1,1,1,1], newpan, newsub, $
    panel=panel, subpanel=subpanel

  plotpan, x, z, /xstyle, /ystyle, noerase=noerase, $
    xtickformat='(A1)', ytitle=ztitle, $
    xrange=xrange, yrange=zrange, $
    panel=newpan(1,3,*), subpanel=newsub(1,3,*), _EXTRA=extra

  plotpan, z, y, /xstyle, /ystyle, /noerase, $
    xtitle=ztitle, ytitle=ytitle, $
    xrange=[zrange(1),zrange(0)], yrange=yrange, $
    panel=newpan(0,2,*), subpanel=newsub(0,2,*), _EXTRA=extra

  plotpan, x, y, /xstyle, /ystyle, /noerase, $
    xtickformat='(A1)', ytickformat='(A1)', $
    xrange=xrange, yrange=yrange, $
    panel=newpan(1,2,*), subpanel=newsub(1,2,*), _EXTRA=extra

  plotpan, z, y, /xstyle, /ystyle, /noerase, $
    ytickformat='(A1)', xtitle=ztitle, $
    xrange=zrange, yrange=yrange, $
    panel=newpan(2,2,*), subpanel=newsub(2,2,*), _EXTRA=extra

  plotpan, x, z, /xstyle, /ystyle, /noerase, $
    xtickformat='(A1)', ytitle=ztitle, $
    xrange=xrange, yrange=[zrange(1),zrange(0)], $
    panel=newpan(1,1,*), subpanel=newsub(1,1,*), _EXTRA=extra

  plotpan, x, y, /xstyle, /ystyle, /noerase, $
    xtitle=xtitle, ytitle=ytitle, $
    xrange=xrange, yrange=[yrange(1), yrange(0)], $
    panel=newpan(1,0,*), subpanel=newsub(1,0,*), _EXTRA=extra

  return
end