Viewing contents of file '../idllib/contrib/fanning/xcontour.pro'
;+
; NAME:
;       XCONTOUR
;
; PURPOSE:
;       The purpose of this program is to demonstrate how to
;       create a contour plot with axes and a title in the
;       new IDL 5 object graphics.
;
; AUTHOR:
;       FANNING SOFTWARE CONSULTING
;       David Fanning, Ph.D.
;       2642 Bradbury Court
;       Fort Collins, CO 80521 USA
;       Phone: 970-221-0438
;       E-mail: davidf@dfanning.com
;       Coyote's Guide to IDL Programming: http://www.dfanning.com
;
; CATEGORY:
;       Widgets, IDL 5 Object Graphics.
;
; CALLING SEQUENCE:
;       XCONTOUR, data, x, y
;
; REQUIRED INPUTS:
;       None. Fake data will be used if no data is supplied in call.
;
; OPTIONAL INPUTS
;
;       data: A 2D array of surface data.
;
;       x: A vector of X data values.
;
;       y: A vector of Y data values.
;
; OPTIONAL KEYWORD PARAMETERS:
;
;       _EXTRA: This keyword collects otherwise undefined keywords that are
;       passed to the old IDL contour command. Most of the keywords will
;       have absolutely no effect.
;
;       GROUP_LEADER: The group leader for this program. When the group leader
;       is destroyed, this program will be destroyed.
;
;       NLEVELS: The number of equally spaced contour intervals to draw.
;       There are no provisions (yet) for specifying your own contour levels.
;
;       TITLE: A string used as the title of the plot.
;
;       XTITLE: A string used as the X title of the plot.
;
;       YTITLE: A string used as the Y title of the plot.
;
; COMMON BLOCKS:
;       None.
;
; SIDE EFFECTS:
;       None.
;
; RESTRICTIONS:
;       None.
;
; EXAMPLE:
;       To use this program with your 2D data, type:
;
;        IDL> XContour, data
;
; MODIFICATION HISTORY:
;       Written by David Fanning, 9 June 97.
;       Added a colorbar to the plot. 19 June 97, DWF.
;       Modified the way VCOLORBAR was called. 14 July 97. DWF.
;       Fixed cleanup procedure to clean up ALL objects. 12 Feb 98. DWF.
;       Changed IDLgrContainer to IDL_Container to fix 5.1 problems. 20 May 98. DWF.
;       Modified to use the IDLgrColorbar object. 20 Sept 98. DWF.
;       Added the ability to do a filled contour. 27 Sept 98. DWF.
;-


FUNCTION Normalize, range, Position=position

    ; This is a utility routine to calculate the scaling vector
    ; required to position a vector of specified range at a
    ; specific position given in normalized coordinates. The
    ; scaling vector is given as a two-element array like this:
    ;
    ;   scalingVector = [translationFactor, scalingFactor]
    ;
    ; The scaling vector should be used with the [XYZ]COORD_CONV
    ; keywords of a graphics object or model. For example, if you
    ; wanted to scale an X axis into the data range of -0.5 to 0.5,
    ; you might type something like this:
    ;
    ;   xAxis->GetProperty, Range=xRange
    ;   xScale = Normalize(xRange, Position=[-0.5, 0.5])
    ;   xAxis, XCoord_Conv=xScale

On_Error, 1
IF N_Params() EQ 0 THEN Message, 'Please pass range vector as argument.'

IF (N_Elements(position) EQ 0) THEN position = [0.0, 1.0] ELSE $
    position=Float(position)
range = Float(range)

scale = [((position[0]*range[1])-(position[1]*range[0])) / $
    (range[1]-range[0]), (position[1]-position[0])/(range[1]-range[0])]

RETURN, scale
END
;-------------------------------------------------------------------------



PRO XContour_Cleanup, tlb

    ; Come here when program dies. Free all created objects.

Widget_Control, tlb, Get_UValue=info
IF N_Elements(info) NE 0 THEN Obj_Destroy, info.thisContainer
END
;-------------------------------------------------------------------



PRO XContour_Draw_Events, event

    ; Draw widget expose events are handled here.

Widget_Control, event.top, Get_UValue=info, /No_Copy

    ; Redraw the view.

info.thisWindow->Draw, info.thisView

    ;Put the info structure back.

Widget_Control, event.top, Set_UValue=info, /No_Copy
END
;-------------------------------------------------------------------



PRO XContour_Properties, event

     ; Event handler to set graphic properties.

Widget_Control, event.top, Get_UValue=info, /No_Copy

    ; What property is wanted?

Widget_Control, event.id, Get_UValue=newProperty
CASE newProperty OF

       ; Appearance of the contour plot.

   'FILLED': info.thisContour->SetProperty, Fill=1
   'UNFILLED': info.thisContour->SetProperty, Fill=0

       ; Background color.

   'BBLACK': info.thisView->SetProperty, Color=[0,0,0]
   'BWHITE': info.thisView->SetProperty, Color=[255,255,255]
   'BCHARCOAL': info.thisView->SetProperty, Color=[80,80,80]

       ; Axes colors.

   'ABLACK': BEGIN
      info.xAxis1->SetProperty, Color=[0,0,0]
      info.yAxis1->SetProperty, Color=[0,0,0]
      info.xAxis2->SetProperty, Color=[0,0,0]
      info.yAxis2->SetProperty, Color=[0,0,0]
      info.thisColorbar->SetProperty, Color=[0,0,0]
      END
   'AWHITE': BEGIN
      info.xAxis1->SetProperty,Color=[255,255,255]
      info.yAxis1->SetProperty,Color=[255,255,255]
      info.xAxis2->SetProperty,Color=[255,255,255]
      info.yAxis2->SetProperty,Color=[255,255,255]
      info.thisColorbar->SetProperty, Color=[255,255,255]
      END
   'AGREEN': BEGIN
      info.xAxis1->SetProperty,Color=[0,255,0]
      info.yAxis1->SetProperty,Color=[0,255,0]
      info.xAxis2->SetProperty,Color=[0,255,0]
      info.yAxis2->SetProperty,Color=[0,255,0]
      info.thisColorbar->SetProperty, Color=[0,255,0]
      END
   'AYELLOW': BEGIN
      info.xAxis1->SetProperty,Color=[255,255,0]
      info.yAxis1->SetProperty,Color=[255,255,0]
      info.xAxis2->SetProperty,Color=[255,255,0]
      info.yAxis2->SetProperty,Color=[255,255,0]
      info.thisColorbar->SetProperty, Color=[255,255,0]
      END

       ; Title colors.

   'TBLACK': info.plotTitle->SetProperty, Color=[0,0,0]
   'TWHITE': info.plotTitle->SetProperty, Color=[255,255,255]
   'TGREEN': info.plotTitle->SetProperty, Color=[0,255,0]
   'TYELLOW': info.plotTitle->SetProperty, Color=[255,255,0]

      ; Color schemes.

   'B/W': BEGIN
      info.thisView->SetProperty, Color=[255,255,255]
      info.xAxis1->SetProperty, Color=[0,0,0]
      info.yAxis1->SetProperty, Color=[0,0,0]
      info.xAxis2->SetProperty, Color=[0,0,0]
      info.yAxis2->SetProperty, Color=[0,0,0]
      info.plotTitle->SetProperty, Color=[0,0,0]
      info.thisColorbar->SetProperty, Color=[0,0,0]
      END
   'W/B': BEGIN
      info.thisView->SetProperty, Color=[0,0,0]
      info.xAxis1->SetProperty,Color=[255,255,255]
      info.yAxis1->SetProperty,Color=[255,255,255]
      info.xAxis2->SetProperty,Color=[255,255,255]
      info.yAxis2->SetProperty,Color=[255,255,255]
      info.plotTitle->SetProperty, Color=[255,255,255]
      info.thisColorbar->SetProperty, Color=[255,255,255]
      END
   'ORIGINAL_COLORS': BEGIN
      info.thisView->SetProperty, Color=[80,80,80]
      info.xAxis1->SetProperty,Color=[255,255,0]
      info.yAxis1->SetProperty,Color=[255,255,0]
      info.xAxis2->SetProperty,Color=[255,255,0]
      info.yAxis2->SetProperty,Color=[255,255,0]
      info.plotTitle->SetProperty, Color=[0,255,0]
      info.thisColorbar->SetProperty, Color=[255,255,0]
      END

ENDCASE

    ; Redraw the graphic.

info.thisWindow->Draw, info.thisView

    ;Put the info structure back.

Widget_Control, event.top, Set_UValue=info, /No_Copy
END
;-------------------------------------------------------------------



PRO XContour_Output, event

   ; This event handler creates GIF and JPEG files.

Widget_Control, event.top, Get_UValue=info, /No_Copy

   ; Get a snapshop of window contents. (TVRD equivalent.)

info.thisWindow->GetProperty, Image_Data=snapshot

   ; JPEG or GIF file wanted?

Widget_Control, event.id, GET_UValue=whichFileType
CASE whichFileType OF

   'GIF': BEGIN

         ; Because we are using RGB color for this model, we have
         ; a 3-m-n array. Use Color_Quan to create a 2D image and
         ; appropriate color tables for the GIF file.

      image2D = Color_Quan(snapshot, 1, r, g, b)
      filename = Dialog_Pickfile(/Write, File='idl.gif')
      IF filename NE '' THEN Write_GIF, filename, image2d, r, g, b
      END

   'JPEG': BEGIN

      filename = Dialog_Pickfile(/Write, File='idl.jpg')
      IF filename NE '' THEN Write_JPEG, filename, snapshot, True=1
      END

ENDCASE

    ;Put the info structure back.

Widget_Control, event.top, Set_UValue=info, /No_Copy
END
;-------------------------------------------------------------------


PRO XContour_Exit, event

   ; Exit the program.

Widget_Control, event.top, /Destroy
END
;-------------------------------------------------------------------



PRO XContour_Printing, event

   ; PostScript printing and printer setup handled here.

Widget_Control, event.top, Get_UValue=info, /No_Copy

   ; Which button?

Widget_Control, event.id, Get_UValue=ButtonValue
CASE buttonValue OF
   'PRINT': BEGIN
      result = Dialog_PrintJob(info.thisPrinter)
      IF result EQ 1 THEN BEGIN
         info.thisPrinter->Draw, info.thisView
         info.thisPrinter->NewDocument
      ENDIF
      END
   'SETUP': BEGIN
      result = Dialog_PrinterSetup(info.thisPrinter)
      IF result EQ 1 THEN BEGIN
         info.thisPrinter->Draw, info.thisView
         info.thisPrinter->NewDocument
      ENDIF
      END
ENDCASE

   ; Put the info structure back.

Widget_Control, event.top, Set_UValue=info, /No_Copy
END
;-------------------------------------------------------------------



PRO XContour_Resize, event

     ; The only events generated by this simple program are resize
     ; events, which are handled here.

     ; Get the info structure.

Widget_Control, event.top, Get_UValue=info, /No_Copy

    ; Resize the draw widget.

info.thisWindow->SetProperty, Dimension=[event.x, event.y]

    ; Redisplay the graphic.

info.thisWindow->Draw, info.thisView

    ;Put the info structure back.

Widget_Control, event.top, Set_UValue=info, /No_Copy
END
;-------------------------------------------------------------------



PRO XContour, data, x, y, _Extra=extra, XTitle=xtitle, $
   YTitle=ytitle, NLevels=nlevels, Title=plotTitle, $
   Group_Leader=groupLeader

    ; Check for keywords. Define default values

IF N_Elements(xtitle) EQ 0 THEN xtitle = 'X Axis'
IF N_Elements(ytitle) EQ 0 THEN ytitle = 'Y Axis'
IF N_Elements(nlevels) EQ 0 THEN nlevels = 10 ELSE nlevels = nlevels < 10
IF N_Elements(plotTitle) EQ 0 THEN plotTitle = 'Pretty Good Contour Plot'

    ; Need some data.

Catch, error
IF error NE 0 THEN BEGIN  ; Can't find LoadData.
   data = Beselj(Shift(Dist(81), 20, 20)/2.0)
   x = Findgen(81)
   y = Findgen(81)
   IF !Error NE -154 THEN Print, !Err_String
ENDIF

IF N_Elements(data) EQ 0 THEN BEGIN
   data = LoadData(2)
ENDIF

s = Size(data)

IF s(0) NE 2 THEN Message,'Must pass 2D argument. Using fake data.'
IF N_Elements(x) EQ 0 THEN x = Findgen(s(1))
IF N_Elements(y) EQ 0 THEN y = Findgen(s(2))


CreateView:
Catch, /Cancel

    ; Create a view. Use RGB color. Charcoal background.
    ; The viewplane rectangle extends from 0 to 1 in XY directions.
    ; The chosen viewplane uses the old IDL "normalized" window. This
    ; is to make it easy to use the path information (xyData, which is
    ; returned in normalized coordinates) from the Contour command
    ; later. I won't have to worry about scaling.

thisView = OBJ_NEW('IDLgrView', Color=[80,80,80], Viewplane_Rect=[0,0,1,1])

    ; Create a model and add it to the view.

thisModel = OBJ_NEW('IDLgrModel')
thisView->Add, thisModel

    ; Colors are the only way to distinguish contour intervals.
    ; Here I load a color table and use colors from the table
    ; for the different contour lines.

thisDevice = !D.Name
Set_Plot, 'Z'
LoadCT, 4
TVLCT, red, green, blue, /Get
Set_Plot, thisDevice
dataColors = BytScl(data)
colorInterval = Fix(255/Float(nlevels))
cLevelColor = (BIndGen(nlevels) + 1) * colorInterval
contourColors = BIndGen(3, nlevels)
FOR j=0,nlevels-1 DO contourColors[*,j] = [red(cLevelColor[j]), $
   green(cLevelColor[j]), blue(cLevelColor[j])]

    ; Create a contour plot object.

xrange = [Min(x), Max(x)]
yrange = [Min(y), Max(y)]
zrange = [Min(data), Max(data)]
xs = Normalize(xrange, Position=[0.2,0.75])
ys = Normalize(yrange, Position=[0.2,0.85])
zs = Normalize(zrange)

thisContour = Obj_New('IDLgrContour', data, GeomZ=-0.01, N_Levels=nlevels, $
   Color=[255, 255, 0], XCoord_Conv=xs, YCoord_Conv=ys, /Planar, $
   ZCoord_Conv=zs, C_Color=contourColors)
thisModel->Add, thisContour

    ; Create a vertical colorbar for the plot. This example uses
    ; the IDL-supplied colorbar, but I don't recommend it, as I don't
    ; think it is very well written. You might better use HCOLORBAR or
    ; VCOLORBAR, which you can download from the Coyote Library.


; cbarPalette = Obj_New('IDLgrPalette', red, green, blue)
; thisColorbar = Obj_New('VColorbar', Range=[Min(data), Max(data)], $
;   Position=[0.93, 0.2, 0.98, 0.85], Color=[255,255,0], $
;   Palette=cbarPalette, Title='Meters')

cbarFont = Obj_New('IDLgrFont', Name='Helvetica', Size=9)
cbarTitle = Obj_New('IDLgrText', 'Meters', Color=[255,255,0],Font=cbarFont)

    ; Create the tick labels for the colorbar.

nDivisions = 6
step = (zRange[1] - zRange[0]) / (nDivisions - 1)
cbarTicksValues = StrArr(nDivisions)
FOR j=0,nDivisions-1 DO cbarTicksValues[j] = String(zrange[0] + j*step, Format='(I4)')
cbarTicks = Obj_New('IDLgrText', cbarTicksValues, Color=[255,255,0], Font=cbarFont)

thisColorbar = Obj_New('IDLgrColorbar', red, green, blue, $
   Dimensions=[40, 255], XCoord_Conv=Normalize([0,39], Position=[0.93,0.98]), $
   YCoord_Conv=Normalize([0,255], Position=[0.2, 0.85]),$
   Title=cbarTitle, Major=nDivisions, Color=[255,255,0], TickLen=5, $
   TickText=cbarTicks, /Show_Axis, /Show_Outline)

thisModel->Add, thisColorbar

    ; Create titles for the axes and plot. Color them yellow.

xTitle = Obj_New('IDLgrText', xtitle, Color=[255,255,0])
yTitle = Obj_New('IDLgrText', ytitle, Color=[255,255,0])

    ; Create a plot title. Add it to model.

plotTitle = Obj_New('IDLgrText', plotTitle, Color=[0,255,0], $
   Alignment=0.5, Location=[0.475, 0.9, 0.0])
thisModel->Add, plotTitle

    ; Create box axes for the contour plot. Color them yellow.
    ; Notice the large values in the Location keyword. These
    ; are values that are not used.

xAxis1 = Obj_New("IDLgrAxis", 0, Color=[255,255,0], Ticklen=0.05, $
   Minor=4, Title=xtitle, Range=xrange, XCoord_Conv=xs, $
   Location=[1000, 0.2, 0.0], /Exact)
 xAxis2 = Obj_New("IDLgrAxis", 0, Color=[255,255,0], Ticklen=0.05, $
   Minor=4, /NoText, Range=xrange, XCoord_Conv=xs, $
   Location=[1000, 0.85, 0.0], TickDir=1, /Exact)

yAxis1 = Obj_New("IDLgrAxis", 1, Color=[255,255,0], Ticklen=0.05, $
   Minor=4, Title=ytitle, Range=yrange, YCoord_Conv=ys, $
   Location=[0.2, 1000, 0.0], /Exact)
yAxis2 = Obj_New("IDLgrAxis", 1, Color=[255,255,0], Ticklen=0.05, $
   Minor=4, /NoText, Range=yrange, YCoord_Conv=ys, $
   Location=[0.75, 1000, 0.0], TickDir=1, /Exact)

    ; Add the axes to the model.

thisModel->Add, xAxis1
thisModel->Add, xAxis2
thisModel->Add, yAxis1
thisModel->Add, yAxis2

    ; Create the widgets to view the contour. Set expose events
    ; on the draw widget so that it refreshes itself whenever necessary.

tlb = Widget_Base(Title='Resizeable Window Contour Example', Column=1, $
   TLB_Size_Events=1, MBar=menubase)
drawID = Widget_Draw(tlb, XSize=400, YSize=400, Graphics_Level=2, $
   Expose_Events=1, Event_Pro='XContour_Draw_Events')

    ; Create FILE menu buttons for printing and exiting.

filer = Widget_Button(menubase, Value='File', /Menu)
pnt = Widget_Button(filer, Value='Print', $
   Event_Pro='XContour_Printing', UValue='PRINT')
pntset = Widget_Button(filer, Value='Print Setup', $
   Event_Pro='XContour_Printing', UValue='SETUP')
quitter = Widget_Button(filer, /Separator, Value='Exit', $
   Event_Pro='XContour_Exit')

   ; Create PROPERTIES menu buttons for surface properties.

properties = Widget_Button(menubase, Value='Properties', /Menu)

   ; Appearance

appear = Widget_Button(properties, Value='Appearance', /Menu)
dummy = Widget_Button(appear, Value='Filled Contours', $
   Event_Pro='XContour_Properties', UValue='FILLED')
dummy = Widget_Button(appear, Value='Contour Lines', $
   Event_Pro='XContour_Properties', UValue='UNFILLED')

   ; Background Color

bcolor = Widget_Button(properties, Value='Background Color', /Menu)
dummy = Widget_Button(bcolor, Value='Black', $
   Event_Pro='XContour_Properties', UValue='BBLACK')
dummy = Widget_Button(bcolor, Value='White', $
   Event_Pro='XContour_Properties', UValue='BWHITE')
dummy = Widget_Button(bcolor, Value='Charcoal', $
   Event_Pro='XContour_Properties', UValue='BCHARCOAL')

   ; Axes Color

acolor = Widget_Button(properties, Value='Axes Color', /Menu)
dummy = Widget_Button(acolor, Value='Black', $
   Event_Pro='XContour_Properties', UValue='ABLACK')
dummy = Widget_Button(acolor, Value='White', $
   Event_Pro='XContour_Properties', UValue='AWHITE')
dummy = Widget_Button(acolor, Value='Yellow', $
   Event_Pro='XContour_Properties', UValue='AYELLOW')
dummy = Widget_Button(acolor, Value='Green', $
   Event_Pro='XContour_Properties', UValue='AGREEN')

   ; Title Color

tcolor = Widget_Button(properties, Value='Title Color', /Menu)
dummy = Widget_Button(tcolor, Value='Black', $
   Event_Pro='XContour_Properties', UValue='TBLACK')
dummy = Widget_Button(tcolor, Value='White', $
   Event_Pro='XContour_Properties', UValue='TWHITE')
dummy = Widget_Button(tcolor, Value='Yellow', $
   Event_Pro='XContour_Properties', UValue='TYELLOW')
dummy = Widget_Button(tcolor, Value='Green', $
   Event_Pro='XContour_Properties', UValue='TGREEN')

   ; Color Schemes.

scolor = Widget_Button(properties, Value='Color Schemes', /Menu)
dummy = Widget_Button(scolor, Value='Black on White', $
   Event_Pro='XContour_Properties', UValue='B/W')
dummy = Widget_Button(scolor, Value='White on Black', $
   Event_Pro='XContour_Properties', UValue='W/B')
dummy = Widget_Button(scolor, Value='Original Colors', $
   Event_Pro='XContour_Properties', UValue='ORIGINAL_COLORS')

   ; Create OUTPUT menu buttons for formatted output files.

output = Widget_Button(menubase, Value='Output')
gif = Widget_Button(output, Value='GIF File', $
   UValue='GIF', Event_Pro='XContour_Output')
jpeg = Widget_Button(output, Value='JPEG File', $
   UValue='JPEG', Event_Pro='XContour_Output')

Widget_Control, tlb, /Realize

    ; Get the window destination object.

Widget_Control, drawID, Get_Value=thisWindow

    ; Draw the view in the window.

thisWindow->Draw, thisView

   ; Get a printer object for this graphic.

thisPrinter = Obj_New('IDLgrPrinter')

   ; Create a container object to hold all the other
   ; objects. This will make it easy to free all the
   ; objects when we are finished with the program.

thisContainer = Obj_New('IDL_Container')

   ; Add created objects to the container.

thisContainer->Add, thisView
thisContainer->Add, thisPrinter
thisContainer->Add, xAxis1
thisContainer->Add, xAxis2
thisContainer->Add, yAxis1
thisContainer->Add, yAxis2
thisContainer->Add, plotTitle
thisContainer->Add, thisContour
thisContainer->Add, xTitle
thisContainer->Add, yTitle
thisContainer->Add, thisColorbar

   ; If you use VCOLORBAR, comment out the next three lines
   ; and uncomment the fourth.

thisContainer->Add, cbarFont
thisContainer->Add, cbarTitle
thisContainer->Add, cbarTicks
; thisContainer->Add, cbarPalette

   ; Create an INFO structure to hold needed program information.

info = { thisContainer:thisContainer, $    ; The object container.
         thisWindow:thisWindow, $          ; The window object.
         thisPrinter:thisPrinter, $        ; The printer object.
         thisModel:thisModel, $            ; The model object.
         thisContour:thisContour, $        ; The contour object.
         thisColorbar:thisColorbar, $      ; The colorbar object.
         xAxis1:xAxis1, $                  ; The X Axis object.
         yAxis1:yAxis1, $                  ; The Y Axis object.
         xAxis2:xAxis2, $                  ; The X Axis object.
         yAxis2:yAxis2, $                  ; The Y Axis object.
         plotTitle:plotTitle, $            ; The plot title object.
         thisView:thisView }               ; The view object.

   ; Store the info structure in the UValue of the TLB.

Widget_Control, tlb, Set_UValue=info, /No_Copy

   ; Call XManager. Set a cleanup routine so the objects
   ; can be freed upon exit from this program.

XManager, 'XContour', tlb, Cleanup='XContour_Cleanup', /No_Block, $
   Event_Handler='XContour_Resize', Group_Leader=groupLeader
END
;-------------------------------------------------------------------