Viewing contents of file '../idllib/contrib/fanning/xplot.pro'
;+
; NAME:
;       XPLOT
;
; PURPOSE:
;       The purpose of this program is to demonstrate how to
;       create a line 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:
;       XPlot, x, y
;
; REQUIRED INPUTS:
;       x: A vector of input values used as the dependent data.
;
; OPTIONAL INPUTS
;       y: A vector of input values used as the dependent data.
;          If both x and y parameters are present, x is the independent data.
;
; OPTIONAL KEYWORD PARAMETERS:
;
;       _EXTRA: This keyword collects otherwise undefined keywords that are
;       passed to new Plot command. To some extent these are similar to the
;       old IDL Plot command. For example: Linestyle=2, Thick=3,
;       XRange=[-100,100], etc.
;
;       GROUP_LEADER: The group leader for this program. When the group leader
;       is destroyed, this program will be destroyed.
;
;       PSYM: The index of a plotting symbol to use on the plot. Integers 0-7
;       are valid values.
;
;       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:
;       Axes are always drawn with the Exact keyword set.
;
; EXAMPLE:
;       To use this program, pass a 1D vector or vectors, like this:
;
;        IDL> XPlot, RandomU(seed, 11) * 9, YRange=[0, 10]
;
; MODIFICATION HISTORY:
;       Written by David Fanning, 13 June 97.
;       Modified axis font handling. 17 Sept 97. DWF.
;       Was not destroying all objects on exit. 12 Feb 98. DWF.
;       Changed IDLgrContainer to IDL_Container to fix 5.1 problems. 20 May 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

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 XPlot_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 a window set up for RGB color,
         ; snapshot contains a 3xMxN 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 XPlot_Exit, event

   ; Exit the program.

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



PRO XPlot_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.plotView
         info.thisPrinter->NewDocument
      ENDIF
      END

   'SETUP': BEGIN
      result = Dialog_PrinterSetup(info.thisPrinter)
      IF result EQ 1 THEN BEGIN
         info.thisPrinter->Draw, info.plotView
         info.thisPrinter->NewDocument
      ENDIF
      END

ENDCASE

   ; Put the info structure back.

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



PRO Xplot_Cleanup, id

    ; Come here when the widget dies. Free all the program
    ; objects, pointers, pixmaps, etc. and release memory.

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



PRO XPlot_Draw_Widget_Events, event

    ; This event handler handles draw widget expose events.

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

    ; Draw the graphic.

info.thisWindow->Draw, info.plotView

    ;Put the info structure back.

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



PRO XPlot_Resize_Events, event

    ; This event handler handles TLB resize events.

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.plotView

    ;Put the info structure back.

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



PRO XPlot, x, y, _Extra=extra, PSym=psym, Title=title, $
   Group_Leader=group, XTitle=xtitle, YTitle=ytitle

    ; Check to be sure at least one parameter is present.

np =  N_Params()
CASE np OF
    0: BEGIN
       Print, 'Using fake data in XPLOT...'
       y = FIndGen(101)
       y = Sin(y/5) / Exp(y/50)
       x = IndGen(N_Elements(y))
       END
    1: BEGIN
       y = x
       x = IndGen(N_Elements(y))
       END
    ELSE:
ENDCASE

    ; Check keyword parameters. Make symbols red.

IF N_Elements(psym) EQ 0 THEN psym = Obj_New() ELSE $
   psym = Obj_New('IDLgrSymbol', psym, Color=[255,0,0], Size=0.5)
IF N_Elements(title) EQ 0 THEN title = 'Example Object Graphics Line Plot'
IF N_Elements(xtitle) EQ 0 THEN xtitle = 'X Axis'
IF N_Elements(ytitle) EQ 0 THEN ytitle = 'Y Axis'

    ; Create a plot object. The plot will be in the coordinate
    ; space 0->1. The view will be in the range -0.35->1.25 so
    ; that the plot axis annotation will be visable. Make the plot
    ; a green color.

thisPlot = Obj_New('IDLgrPLOT', x, y, _Extra=extra, $
   Color=[0,255,0], Symbol=psym, Thick=2)

    ; Get the data ranges from the Plot Object.

thisPlot->GetProperty, XRange=xrange, YRange=yrange

    ; Set up the scaling so that the axes for the plot and the
    ; plot data extends from 0->1 in the X and Y directions.

xs = Normalize(xrange)
ys = Normalize(yrange)

    ; Scale the plot data into 0->1.

thisPlot->SetProperty, XCoord_Conv=xs, YCoord_Conv=ys

  ; Create a plot title. Center it at a location above the plot.

helvetica14pt = Obj_New('IDLgrFont', 'Helvetica', Size=14)
plotTitle = Obj_New('IDLgrText', title, Color=[255,255,0], $
   Location=[0.5, 1.05, 0.0], Alignment=0.5, Font=helvetica14pt)

   ; Create titles objects for the axes. Color them yellow.

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

    ; Create plot box style axes. Make the axes yellow.
    ; The large values in the LOCATION keyword indicates which
    ; values are NOT used. The axes text is set to Helvetica
    ; 10 point font.

xAxis1 = Obj_New("IDLgrAxis", 0, Color=[255,255,0], Ticklen=0.025, $
    Minor=4, Range=xrange, Title=xtitle, XCoord_Conv=xs,  $
    Location=[1000, 0 ,0], /Exact)
xAxis1->GetProperty, Ticktext=xAxisText
helvetica10pt = Obj_New('IDLgrFont', 'Helvetica', Size=10)
xAxisText->SetProperty, Font=helvetica10pt

xAxis2 = Obj_New("IDLgrAxis", 0, Color=[255,255,0], Ticklen=0.025, $
    Minor=4, /NoText, Range=xrange, TickDir=1, XCoord_Conv=xs, $
    Location=[1000, 1, 0], /Exact)

yAxis1 = Obj_New("IDLgrAxis", 1, Color=[255,255,0], Ticklen=0.025, $
    Minor=4, Title=ytitle, Range=yrange, YCoord_conv=ys, $
    Location=[0, 1000, 0], /Exact)
yAxis1->GetProperty, Ticktext=yAxisText
yAxisText->SetProperty, Font=helvetica10pt

yAxis2 = Obj_New("IDLgrAxis", 1, Color=[255,255,0], Ticklen=0.025, $
    Minor=4, /NoText, Range=yrange, TickDir=1, YCoord_conv=ys, $
    Location=[1, 1000, 0], /Exact)

    ; Create a plot model and add axes, plot, and plot title to it.

plotModel = Obj_New('IDLgrModel')
plotModel->Add, thisPlot
plotModel->Add, xAxis1
plotModel->Add, xAxis2
plotModel->Add, yAxis1
plotModel->Add, yAxis2
plotModel->Add, plotTitle

    ; Create a view and add the plot model to it. Notice that the view
    ; is larger than the 0->1 plot area to accomodate axis annotation.
    ; The view will have a gray background.

plotView = Obj_New('IDLgrView', Viewplane_Rect=[-.35, -.35, 1.6, 1.6], $
   Location=[0,0], Color=[80,80,80])
plotView->Add, plotModel

    ; Create the widgets for this program.

tlb = Widget_Base(Column=1, Title='Resizeable Line Plot Example', $
   TLB_Size_Events=1, MBar=menubase)

    ; Create FILE menu buttons for printing and exiting.

filer = Widget_Button(menubase, Value='File', /Menu)
b = Widget_Button(filer, Value='Print', $
   Event_Pro='XPlot_Printing', UValue='PRINT')
b = Widget_Button(filer, Value='Print Setup', $
   Event_Pro='XPlot_Printing', UValue='SETUP')
b = Widget_Button(filer, /Separator, Value='Exit', $
   Event_Pro='XPlot_Exit')

    ; Create OUTPUT menu buttons for formatted output files.

output = Widget_Button(menubase, Value='Output')
b = Widget_Button(output, Value='GIF File', $
   UValue='GIF', Event_Pro='XPlot_Output')
b = Widget_Button(output, Value='JPEG File', $
   UValue='JPEG', Event_Pro='XPlot_Output')

    ; Create the draw widget. Use RGB color model. Be sure to set
    ; the Expose_Events keyword so that graphics are redisplayed
    ; properly. (This implies that RETAIN=0. The Graphics_Level
    ; keyword makes it a window object.

drawID = Widget_Draw(tlb, XSize=400, YSize=400, Color_Model=0, $
   Graphics_Level=2, Expose_Events=1, Retain=0, $
   Event_Pro='XPlot_Draw_Widget_Events')

    ; Realize the widgets and get the window object.

Widget_Control, tlb, /Realize
Widget_Control, drawID, Get_Value=thisWindow

    ; Display the plot in the window.

thisWindow->Draw, plotView

   ; 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')
thisContainer->Add, thisWindow
thisContainer->Add, plotView
thisContainer->Add, thisPrinter
thisContainer->Add, helvetica10pt
thisContainer->Add, helvetica14pt
thisContainer->Add, xaxis1
thisContainer->Add, xaxis2
thisContainer->Add, yaxis1
thisContainer->Add, yaxis2
thisContainer->Add, plotTitle
thisContainer->Add, xTitle
thisContainer->Add, yTitle


   ; Create an info structure to hold program information.

info = { thisContainer:thisContainer, $  ; The container object.
         thisWindow:thisWindow, $        ; The window object.
         plotView:plotView, $            ; The view that will be rendered.
         thisPrinter:thisPrinter }       ; The printer object.

    ; Put the info stucture in the TLB.

Widget_Control, tlb, Set_UValue=info, /No_Copy

    ; Start the event loop.

XManager, 'xplot', tlb, Cleanup='XPlot_Cleanup', Group_Leader=group, $
   Event_Handler='XPlot_Resize_Events', /No_Block

END
;------------------------------------------------------------------------