; $Id: davegr1d__display.pro,v 1.22 2006/10/10 16:10:11 azuah Exp $
;###############################################################################
;
; CLASS NAME:
;   DaveGr1D
;
; PURPOSE:
;   The DaveGr1D class extends the DaveGr class to better handle
;   plotting of 1D data ie line plots.
;
; CATEGORY:
;   Data Browser
;
; SUPERCLASSES:
;   DaveGr
;
; PUBLIC METHODS:
;   Display
;   Get
;   ResetLegend
;   ReserMiscGrAttribs
;   Set
;
; AUTHOR:
;   Richard Tumanjong Azuah
;   NIST Center for Neutron Research
;   100 Bureau Drive, Gaithersburg, MD 20899
;   United States
;   azuah@nist.gov; (301) 9755604
;   Nov, 2002
;
; LICENSE:
;  The software in this file is written by an employee of 
;  National Institute of Standards and Technology 
;  as part of the DAVE software project.
;
;  The DAVE software package is not subject to copyright protection
;  and is in the public domain. It should be considered as an
;  experimental neutron scattering data reduction, visualization, and
;  analysis system. As such, the authors assume no responsibility
;  whatsoever for its use, and make no guarantees, expressed or
;  implied, about its quality, reliability, or any other
;  characteristic. The use of certain trade names or commercial
;  products does not imply any endorsement of a particular product,
;  nor does it imply that the named product is necessarily the best
;  product for the stated purpose. We would appreciate acknowledgment
;  if the DAVE software is used or if the code in this file is
;  included in another product.
;
;###############################################################################



;===============================================================================
; DaveGr1D::dispHistogram
;
; PURPOSE:
;   Create a histogram plot of the object's dataset.
;
; PARAMETERS:
;   oScene [in] - the IDLgrScene object that is used as the root of
;                 the object graphics hierarchy that would be
;                 constructed.
;
; KEYWORDS:
;   dispError [in] - set this to indicate that data errors should be
;                    displayed.
;
;   dispTitle [in] - set this to make the main plot title visisble.
; 
;   _EXTRA [in] - Allows keywords to be passed to various IDLgr* class
;                 methods.
;
; RETURN VALUE:
;   0 => failure
;   1 => success.
;
function DaveGr1D::dispHistograms, oScene, dispError=dispError,dispTitle=dispTitle,_EXTRA=etc

retVal = 1

; if etc is empty, insert a dummy keyword into it
if (n_elements(etc) eq 0) then etc = {dummy:0}

nData = self->count()              ; number of DaveGr1D objects to display

; Get data references and all graphic attributes
if (not self->get(dataRef=dataRef,nameTag=nameTag,color=color,bgColor=bkgdColor,lineType=lineType, $
                  lineSize=lineSize, $
                  xColor=xaxisColor,xFontVal=xFont,xFontSize=xFontSize,xLabel=xLabel,xLineSize=xLineSize, $
                  zColor=yaxisColor,zFontVal=yFont,zFontSize=yFontSize,zLabel=yLabel,zLineSize=yLineSize, $
                  xMiscAttrib=xMiscAttribs,zMiscAttribs=yMiscAttribs,xmin=xmin,xmax=xmax,zmin=ymin,zmax=ymax, $
                  title=title,label=labelArray,nlabel=nlabel,legend=legend)) then return, 0

res = where(tag_names(etc) eq 'XRANGE', xrange_isSet)
res = where(tag_names(etc) eq 'YRANGE', yrange_isSet)


; set/calculate miscellaneous axes attributes
; x-axis
xscale = xMiscAttribs.scalefactor
case xrange_isSet of
    0: begin
        case xMiscAttribs.useCustomFlag of
            0: begin            ; using default data range
                dx = 0.05*(xmax-xmin)
                xmin = (xmin - dx)*xscale
                xmax = (xmax + dx)*xscale
                xMajorTicks = 5
            end
            1: begin            ; using custom range specified in axis property dialog
                xmin = xMiscAttribs.minimum * xscale
                xmax = xMiscAttribs.maximum * xscale
                xMajorInterval = xMiscAttribs.tickInterval * xscale
            end
        endcase
    end
    1: begin                    ; probably using a rubberband box setting
        xmin = etc.xrange[0]
        xmax = etc.xrange[1]
        ;; if log scale is on then need to revert data to original
        if (xMiscAttribs.logFlag) then begin
            xmin = 10.0^xmin
            xmax = 10.0^xmax
        endif
        ;xMajorInterval = 0.25*(xmax-xmin) ; ==>majorTicks = 5
        xMajorTicks = 5
    end
endcase

; If using log scale for x-axis, 
; - make sure range it is +ve
; - convert to log scale
xmin0 = xmin
xmax0 = xmax
if (xMiscAttribs.logFlag) then begin ; using log scale
    ;; xrange must be +ve
    if (xmin le 0.0) then begin
        xmin = 0.00001*xmax
        xmin0 = xmin
    endif
    xmin = alog10(xmin)
    xmax = alog10(xmax)
endif

xr = xmax-xmin
xpad = 0.25*xr
;vplaneX0 = xmin - xpad
;vplaneW = xr + 1.5*xpad
vplaneX0 = xmin - 1.65*xpad
vplaneW = xr + 2.0*xpad
xMinorTicks = xMiscAttribs.minorTicks
xLog = (xmin0 ge 0)? xMiscAttribs.logFlag : 0 ; range must be +ve for log
xFormat = getFormatCode(xmin0,xmax0,xMiscAttribs.decimalPlaces)
xTickDir = xMiscAttribs.tickDir
; y -axis
yscale = yMiscAttribs.scalefactor
case yrange_isSet of
    0: begin
        case yMiscAttribs.useCustomFlag of
            0: begin            ; using default data range
                dy = 0.05*(ymax-ymin)
                ymin = (ymin - dy)*yscale
                ymax = (ymax + dy)*yscale
                yMajorTicks = 5
            end
            1: begin            ; using custom range specified in axis property dialog
                ymin = yMiscAttribs.minimum * yscale
                ymax = yMiscAttribs.maximum * yscale
                yMajorInterval = yMiscAttribs.tickInterval * yscale
            end
        endcase
    end
    1: begin                    ; probably using a rubberband box setting
        ymin = etc.yrange[0]
        ymax = etc.yrange[1]
        ;; if log scale is on then need to revert data to original
        if (yMiscAttribs.logFlag) then begin
            ymin = 10.0^ymin
            ymax = 10.0^ymax
        endif
        yMajorTicks = 5
    end
endcase

ymin0 = ymin
ymax0 = ymax
if (yMiscAttribs.logFlag) then begin ; using log scale
    ;; xrange must be +ve
    if (ymin le 0.0) then begin
        ymin = 0.00001*ymax
        ymin0 = ymin
    endif
    ymin = alog10(ymin)
    ymax = alog10(ymax)
endif

yr = ymax-ymin
ypad = 0.25*yr
vplaneY0 = ymin - ypad
vplaneH = yr + 2*ypad
yMinorTicks = yMiscAttribs.minorTicks
yLog = (ymin0 gt 0.0)? yMiscAttribs.logFlag : 0 ; range must be +ve for log
if (yLog) then dispError = 0    ; can't display errorbars
yFormat = getFormatCode(ymin0,ymax0,yMiscAttribs.decimalPlaces)
yTickDir = yMiscAttribs.tickDir

xTickLen = 0.01 * xMiscAttribs.tickLen * yr
yTickLen = 0.01 * yMiscAttribs.tickLen * xr

bkgdColor = self.bgColor
xaxisColor = self.xColor
yaxisColor = self.zColor


; Create a container to hold misc object references that are not part
; of the IDL graphics object hierarchy
oMiscCont = obj_new('IDL_Container')
oScene->add, oMiscCont

; Create a new view and add it to scene
oView = obj_new('IDLgrView',units=0,viewplane_rect=[vplaneX0,vplaneY0,vplaneW,vplaneH],color=bkgdColor)
oScene->add, oView

; IDLgrModel to hold ALL graphic atoms.
oModel = obj_new('IDLgrModel',name='DG1DMODEL')

; Create (lower and upper) x-axis + an IDLgrModel to hold them
;--------------------------------
oXaModel = obj_new('IDLgrModel',name='AMODEL',/select_target) ; make it selectable
oModel->add, oXaModel

oXaxis1 = obj_new('IDLgrAxis',0,location=[xmin,ymin],range=[xmin0,xmax0],color=xaxisColor, $
                  ticklen=xTicklen,name='AXIS',major=xMajorTicks,minor=xMinorTicks,tickdir=xTickDir, $
                  /exact,uvalue={objRef:self,datInd:0},thick=xLineSize,tickformat=xFormat, $
                  tickinterval=xMajorInterval,log=xLog)
oXaxis2 = obj_new('IDLgrAxis',0,location=[xmin,ymax],range=[xmin0,xmax0],color=xaxisColor, $
                  ticklen=xTicklen,name='AXIS',major=xMajorTicks,minor=xMinorTicks,tickdir=1-xTickDir, $
                  /exact,/notext,uvalue={objRef:self,datInd:0},thick=xLineSize,$
                  tickinterval=xMajorInterval,log=xLog)
oXaModel->add, oXaxis1
oXaModel->add, oXaxis2



; Create (left and right) y-axis + an IDLgrModel to hold them
;----------------------------------
oYaModel = obj_new('IDLgrModel',name='AMODEL',/select_target) ; make it selectable
oModel->add, oYaModel
oYaxis1 = obj_new('IDLgrAxis',1,location=[xmin,ymin],range=[ymin0,ymax0],color=yaxisColor, $
                  ticklen=yTicklen,name='AXIS',major=yMajorTicks,minor=yMinorTicks,tickdir=yTickDir, $
                  /exact,uvalue={objRef:self,datInd:1},thick=yLineSize,tickformat=yFormat, $
                  tickinterval=yMajorInterval,log=yLog)
oYaxis2 = obj_new('IDLgrAxis',1,location=[xmax,ymin],range=[ymin0,ymax0],color=yaxisColor, $
                  ticklen=yTicklen,name='AXIS',major=yMajorTicks,minor=yMinorTicks,tickdir=1-yTickDir, $
                  /exact,/notext,uvalue={objRef:self,datInd:1},thick=yLineSize,$
                  tickinterval=yMajorInterval,log=yLog)
oYaModel->add, oYaxis1
oYaModel->add, oYaxis2

; create legend variables
item_color = bytarr(3,nData)
if (nData eq 1) then item_color = reform(item_color,3,1)
item_linestyle = bytarr(nData)+6b
item_object = objarr(nData)
item_type = bytarr(nData)

; Now cycle through the DaveDat objects and create appropriate IDL gr atoms to
; represent them
;----------------------------------------------------------------------------
for i=0,nData-1 do begin
    ;; Deal with dataset label


    ;; get the x,z-axis data
    if (not (dataRef[i])->get(xtype=xtype,xval=xval,zval=zval,zerr=zerr)) then goto, DestroyModel

    ;; Axes labels should be set, if necessary, using first dataset's values
    if (i eq 0) then begin
        oXfont = obj_new('IDLgrFont',name=xFont,size=xFontSize)
        oMiscCont->add,oXfont
        if (n_elements(xlabel) eq 0) then xlabel='X axis title'
        oXlabel = obj_new('IDLgrText',xlabel,name='XAXISLABEL',font=oXfont,/enable_formatting)
        oXaxis1->setProperty, title=oXlabel
        oMiscCont->add, oXlabel
        oXaxis1->getProperty, ticktext=ttRef ; get the axis tick text object
        ttRef->setProperty, font=oXfont ; and assign it the same font as for the label


        oYfont = obj_new('IDLgrFont',name=yFont,size=yFontSize)
        oMiscCont->add,oYfont
        if (n_elements(ylabel) eq 0) then ylabel='Y axis title'
        oYlabel = obj_new('IDLgrText',ylabel,name='YAXISLABEL',font=oYfont,/enable_formatting)
        oYaxis1->setProperty, title=oYlabel
        oMiscCont->add, oYlabel
        oYaxis1->getProperty, ticktext=ttRef ; get the axis tick text object
        ttRef->setProperty, font=oYfont ; and assign it the same font as for the label
    endif

    nz = n_elements(zval)
    nx = n_elements(xval)

    ;; create appropriate vectors to hold histogram data generated from
    ;; point/histogram data originally
    switch strmid(strupcase(xtype),0,4) of
        'POIN': begin
            nxh = 2*nx
            xh = fltarr(nxh)
            zh = xh
            xindex = lindgen(nx-1)
            zindex = 2*lindgen(nx)
            xvalMid = 0.5*(xval[xindex]+xval[xindex+1])
            xh[2*xindex+1] = xvalMid        
            xh[2*xindex+2] = xvalMid
            xh[0] = 0.5*(3.0*xval[0] - xval[1]) ; first term
            xh[2*nx-1] = 0.5*(3.0*xval[nx-1] - xval[nx-2]) ; last term
            zh[zindex] = zval
            zh[zindex+1] = zval
            xerr = xval
            break
        end
        
        'HIST':                 ; proceed to 'else' block!
        else: begin
            nxh = 2*(nx-2)+2    ; size of histogram vector
            xh = fltarr(nxh)    ; x hist values
            zh = xh             ; z hist values
            xindex = lindgen(nx-1)
            xh[2*xindex] = xval[0:nx-2]
            xh[2*xindex+1] = xval[1:nx-1]
            zh[2*xindex] = zval
            zh[2*xindex+1] = zval
            xvalMid = 0.5*(xval[xindex]+xval[xindex+1]) ; ==> mid values of the bin boundaries
            xerr = xvalMid
            break
        end
    endswitch

    ;; Apply scalefactor and offset to data
    ;; (**These are scalefactors set for individual DaveData* datasets ** -- now done in get() method)
    ;; xscale and yscale are set for the graphic object as a whole
    xh = xh*xscale
    xerr = xerr*xscale
    ;;zh = (zh * scalefactor + offset)*yscale
    ;;zval = (zval * scalefactor + offset)*yscale
    ;;if (n_elements(zerr) gt 0) then zerr = zerr * scalefactor *yscale 
    zh = zh*yscale
    zval = zval*yscale
    if (n_elements(zerr) gt 0) then zerr = zerr*yscale 

    ; using log x-axis?
    if (xLog) then begin
        index = where((xh ge xmin0) and (xh le xmax0), count)
        if (count gt 0) then begin
            xh = alog10(xh[index])
            zh = zh[index]
        endif else continue
    endif

    ; using log y-axis?
    if (yLog) then begin
        index = where((zh ge ymin0) and (zh le ymax0), count)
        if (count gt 0) then begin
            zh = alog10(zh[index])
            xh = xh[index]
        endif else continue
    endif

    ;; create:
    ;;  - 1 sub IDLgrModel to hold two graphic atoms :-
    ;;  - 1 histogram plot atom and
    ;;  - 1 (associated) error atom (as polylines) [if errobars requested]
    ;;------------------------------
    oPlotModel = obj_new('IDLgrModel',name='LMODEL',/select_target) ; make it selectable
    oModel->add, oPlotModel

    lineType[i] = (lineType[i] lt 0)? 0 :  lineType[i]
    lineType[i] = (lineType[i] gt 5)? 5 : lineType[i]
    lineSize[i] = (lineSize[i] lt 1.0)? 1.0 : lineSize[i]
    lineSize[i] = (lineSize[i] gt 10.0)? 10.0 : lineSize[i]
    
    item_color[*,i] = reform(color[i,*])
    item_linestyle[i] = lineType[i]

    ;; The line plot
    plotName = 'LPLOT'          ;+strtrim(string(i),2)
    oPlot = obj_new('IDLgrPlot',xh,zh,name=plotName,linestyle=lineType[i],thick=lineSize[i] $
                    ,color=reform(color[i,*]),xrange=[xmin,xmax],yrange=[ymin,ymax] $
                    ,uvalue={objRef:self,datInd:i})
    oPlotModel->add, oPlot
    

    ;; The errors
    if ((keyword_set(dispError)) and (n_elements(zerr) gt 0)) then begin
        oPlotErr = createObjectGrErrors(xerr,zval,zerr,xrange=[xmin,xmax],yrange=[ymin,ymax] $
                                        ,thick=lineSize[i],uvalue={objRef:self,datInd:i})
        if (obj_valid(oPlotErr) eq 1) then begin
            oPlotErr->setProperty, color=reform(color[i,*]), name='EPLOT'
            oPlotModel->add,oPlotErr
        endif
    endif

endfor

xs = scale_coord([0,1],[vplaneX0,vplaneX0+vplaneW])
ys = scale_coord([0,1],[vplaneY0,vplaneY0+vplaneH])

; Main plot title
if ((dispTitle eq 1) and (strtrim(title.text,2) ne '')) then begin
    oLabelModel = obj_new('IDLgrModel',name='LABMODEL',/select_target) ; make it selectable
    oModel->add, oLabelModel

    oTitleFont = obj_new('IDLgrFont',name=title.font,size=title.fontsize)
    oMiscCont->add,oTitleFont   ; so it can be properly cleaned up
    oTitle = obj_new('IDLgrText',title.text,name='LABEL',font=oTitleFont,/enable_formatting $
                     ,location=title.position,alignment=title.alignment,color=title.color $
                     ,xcoord_conv=xs,ycoord_conv=ys,uvalue={objRef:self,datInd:-1})
    oLabelModel->add,oTitle
endif

; Miscellaneous text labels
while (nlabel gt 0) do begin
    nlabel = nlabel - 1
    newLabel = labelArray[nlabel]
    oLabelModel = obj_new('IDLgrModel',name='LABMODEL',/select_target) ; make it selectable
    oModel->add, oLabelModel
    oLabelFont = obj_new('IDLgrFont',name=newLabel.font,size=newLabel.fontsize)
    oMiscCont->add,oLabelFont   ; so it can be properly cleaned up
    oLabel = obj_new('IDLgrText',newLabel.text,name='LABEL',font=oLabelFont,/enable_formatting $
                     ,location=newLabel.position,alignment=newLabel.alignment,color=newLabel.color $
                     ,xcoord_conv=xs,ycoord_conv=ys,uvalue={objRef:self,datInd:nlabel})
    oLabelModel->add,oLabel
endwhile     


; The Legend
item_name = legend.itemName[0:nData-1]
item_thick = legend.itemThick[0:nData-1] 

xs = scale_coord([0,1],[vplaneX0,vplaneX0+vplaneW])
ys = scale_coord([0,1],[vplaneY0,vplaneY0+vplaneH])

olegTitFont = obj_new('IDLgrFont',name=legend.tFont,size=legend.tFontsize)
olegFont = obj_new('IDLgrFont',name=legend.font,size=legend.fontsize)
olegTitle = obj_new('IDLgrText',legend.title,font=olegTitFont,color=legend.tcolor,/enable_formatting) 
oMiscCont->add,[olegTitFont,olegFont,olegTitle] ; so they can be cleaned

oLegend = obj_new('IDLgrLegend',name='LEGEND',fill_color=legend.bkgdColor $
                  ,font=olegFont,gap=legend.gap,glyph_width=legend.gwidth,hide=legend.hideFlag $
                  ,title=olegTitle,show_outline=legend.outlFlag,show_fill=legend.fillFlag $
                  ,outline_color=legend.outlColor,outline_thick=legend.outlThick $
                  ,text_color=legend.textColor,item_name=item_name $
                  ,item_linestyle=item_linestyle,item_color=item_color,item_thick=item_thick $
                  ,item_object=item_object,item_type=item_type $
                  ,xcoord_conv=xs,ycoord_conv=ys,/select_target $
                  ,uvalue={objRef:self,datInd:0,vpdim:[vplaneW,vplaneH]})

oLegend->Translate,legend.location[0]*vplaneW,legend.location[1]*vplaneH,0.0
print,vplaneW
print,vplaneH
oView->add, oLegend

; Finally add the model to the view
oView->add, oModel
return, 1

; Destroy  oModel if an error condition was encountered
DestroyModel:
if (obj_valid(oModel)) then obj_destroy, oModel
return, 0
 
end
;-------------------------------------------------------------------------------



;===============================================================================
; DaveGr1D::dispPoints
;
; PURPOSE:
;   Create a line plot of the object's dataset(s).
;
; PARAMETERS:
;   oScene [in] - the IDLgrScene object that is used as the root of
;                 the object graphics hierarchy that would be
;                 constructed.
;
;   dim [in] - the dimensions of the IDLgr* destination object
;
; KEYWORDS:
;   dispError [in] - set this to indicate that data errors should be
;                    displayed.
;
;   dispTitle [in] - set this to make the main plot title visisble.
; 
;   _EXTRA [in] - Allows keywords to be passed to various IDLgr* class
;                 methods.
;
; RETURN VALUE:
;   0 => failure
;   1 => success.
;
function DaveGr1D::dispPoints, oScene, dim,dispError=dispError,dispTitle=dispTitle,_EXTRA=etc

retVal = 1

; if etc is empty, insert a dummy keyword into it
if (n_elements(etc) eq 0) then etc = {dummy:0}

nData = self->count()              ; number of DaveGr1D objects to display

; Get data references and all graphic attributes
if (not self->get(dataRef=dataRef,nameTag=nameTag,color=color,bgColor=bkgdColor,lineType=lineType, $
                  lineSize=lineSize,symType=symType,symSize=symSize,lineSymFlag=lineSymFlag, $
                  xColor=xaxisColor,xFontVal=xFont,xFontSize=xFontSize,xLabel=xLabel,xLineSize=xLineSize, $
                  zColor=yaxisColor,zFontVal=yFont,zFontSize=yFontSize,zLabel=yLabel,zLineSize=yLineSize, $
                  xMiscAttrib=xMiscAttribs,zMiscAttribs=yMiscAttribs,xmin=xmin,xmax=xmax,zmin=ymin,zmax=ymax, $
                  title=title,label=labelArray,nlabel=nlabel,legend=legend)) then return, 0


res = where(tag_names(etc) eq 'XRANGE', xrange_isSet)
res = where(tag_names(etc) eq 'YRANGE', yrange_isSet)


; set/calculate miscellaneous axes attributes
; x-axis
;xetc = {exact:1}
xscale = xMiscAttribs.scalefactor
case xrange_isSet of
    0: begin
        case xMiscAttribs.useCustomFlag of
            0: begin            ; using default data range
                dx = 0.05*(xmax-xmin)
                xmin = (xmin - dx)*xscale
                xmax = (xmax + dx)*xscale
                xMajorTicks = 5
                ;xetc = {extend:1}
            end
            1: begin            ; using custom range specified in axis property dialog
                xmin = xMiscAttribs.minimum * xscale
                xmax = xMiscAttribs.maximum * xscale
                xMajorInterval = xMiscAttribs.tickInterval * xscale
            end
        endcase
    end
    1: begin                    ; probably using a rubberband box setting
        xmin = etc.xrange[0]
        xmax = etc.xrange[1]
        ;; if log scale is on then need to revert data to original
        if (xMiscAttribs.logFlag) then begin
            xmin = 10.0^xmin
            xmax = 10.0^xmax
        endif
        ;xMajorInterval = 0.25*(xmax-xmin) ; ==>majorTicks = 5
        xMajorTicks = 5
    end
endcase

; If using log scale for x-axis, 
; - make sure range it is +ve
; - convert to log scale
xmin0 = xmin
xmax0 = xmax
if (xMiscAttribs.logFlag) then begin ; using log scale
    ;; xrange must be +ve
    if (xmin le 0.0) then begin
        xmin = 0.00001*xmax
        xmin0 = xmin
    endif
    xmin = alog10(xmin)
    xmax = alog10(xmax)
endif

xr = xmax-xmin
xpad =  0.25*xr
vplaneX0 = xmin - 1.65*xpad
vplaneW = xr + 2.0*xpad
xMinorTicks = xMiscAttribs.minorTicks
xLog = (xmin0 gt 0.0)? xMiscAttribs.logFlag : 0 ; range must be +ve for log
xFormat = getFormatCode(xmin0,xmax0,xMiscAttribs.decimalPlaces)
xTickDir = xMiscAttribs.tickDir

; y -axis
;yetc = {exact:1}
yscale = yMiscAttribs.scalefactor
case yrange_isSet of
    0: begin
        case yMiscAttribs.useCustomFlag of
            0: begin            ; using default data range
                dy = 0.05*(ymax-ymin)
                ymin = (ymin - dy)*yscale
                ymax = (ymax + dy)*yscale
                yMajorTicks = 5
                ;yetc = {extend:1}
            end
            1: begin            ; using custom range specified in axis property dialog
                ymin = yMiscAttribs.minimum * yscale
                ymax = yMiscAttribs.maximum * yscale
                yMajorInterval = yMiscAttribs.tickInterval * yscale
            end
        endcase
    end
    1: begin                    ; probably using a rubberband box setting
        ymin = etc.yrange[0]
        ymax = etc.yrange[1]
        ;; if log scale is on then need to revert data to original
        if (yMiscAttribs.logFlag) then begin
            ymin = 10.0^ymin
            ymax = 10.0^ymax
        endif
        yMajorTicks = 5
    end
endcase

ymin0 = ymin
ymax0 = ymax
if (yMiscAttribs.logFlag) then begin ; using log scale
    ;; xrange must be +ve
    if (ymin le 0.0) then begin
        ymin = 0.00001*ymax
        ymin0 = ymin
    endif
    ymin = alog10(ymin)
    ymax = alog10(ymax)
endif

yr = ymax-ymin
ypad = 0.25*yr
vplaneY0 = ymin - ypad
vplaneH = yr + 2*ypad
yMinorTicks = yMiscAttribs.minorTicks
yLog = (ymin0 gt 0.0)? yMiscAttribs.logFlag : 0 ; range must be +ve for log
if (yLog) then dispError = 0    ; can't display errorbars
yFormat = getFormatCode(ymin0,ymax0,yMiscAttribs.decimalPlaces)
yTickDir = yMiscAttribs.tickDir

xTickLen = 0.01 * xMiscAttribs.tickLen * yr
yTickLen = 0.01 * yMiscAttribs.tickLen * xr

symScale = 0.005*[vplaneW,dim[0]/dim[1]*vplaneH]

bkgdColor = self.bgColor
xaxisColor = self.xColor
yaxisColor = self.zColor

; Create a container to hold misc object references that are not part
; of the IDL graphics object hierarchy
oMiscCont = obj_new('IDL_Container')
oScene->add, oMiscCont

; Create a new view and add it to scene
vpscale = 0.75

shift = 0.5*(1-vpscale)*dim
dim = dim*vpscale 
oView = obj_new('IDLgrView',units=0,viewplane_rect=[vplaneX0,vplaneY0,vplaneW,vplaneH],color=bkgdColor)
;oView = obj_new('IDLgrView',units=0,viewplane_rect=[vplaneX0,vplaneY0,vplaneW,vplaneH],color=bkgdColor $
;                ,dimensions=dim,location=shift)
oScene->add, oView

; IDLgrModel to hold ALL graphic atoms.
oModel = obj_new('IDLgrModel',name='DG1DMODEL')

; Create (lower and upper) x-axis + an IDLgrModel to hold them
;--------------------------------
oXaModel = obj_new('IDLgrModel',name='AMODEL',/select_target) ; make it selectable
oModel->add, oXaModel
oXaxis1 = obj_new('IDLgrAxis',0,location=[xmin,ymin],range=[xmin0,xmax0],color=xaxisColor, $
                  ticklen=xTicklen,name='AXIS',major=xMajorTicks,minor=xMinorTicks,tickdir=xTickDir, $
                  uvalue={objRef:self,datInd:0},thick=xLineSize,tickformat=xFormat, $
                  tickinterval=xMajorInterval,log=xLog,/exact)
oXaxis2 = obj_new('IDLgrAxis',0,location=[xmin,ymax],range=[xmin0,xmax0],color=xaxisColor, $
                  ticklen=xTicklen,name='AXIS',major=xMajorTicks,minor=xMinorTicks,tickdir=1-xTickDir, $
                  /notext,uvalue={objRef:self,datInd:0},thick=xLineSize,$
                  tickinterval=xMajorInterval,log=xLog,/exact)
oXaModel->add, oXaxis1
oXaModel->add, oXaxis2

; Create (left and right) y-axis + an IDLgrModel to hold them
;----------------------------------
oYaModel = obj_new('IDLgrModel',name='AMODEL',/select_target) ; make it selectable
oModel->add, oYaModel
oYaxis1 = obj_new('IDLgrAxis',1,location=[xmin,ymin],range=[ymin0,ymax0],color=yaxisColor, $
                  ticklen=yTicklen,name='AXIS',major=yMajorTicks,minor=yMinorTicks,tickdir=yTickDir, $
                  uvalue={objRef:self,datInd:1},thick=yLineSize,tickformat=yFormat, $
                  tickinterval=yMajorInterval,log=yLog,/exact)
oYaxis2 = obj_new('IDLgrAxis',1,location=[xmax,ymin],range=[ymin0,ymax0],color=yaxisColor, $
                  ticklen=yTicklen,name='AXIS',major=yMajorTicks,minor=yMinorTicks,tickdir=1-yTickDir, $
                  /notext,uvalue={objRef:self,datInd:1},thick=yLineSize,$
                  tickinterval=yMajorInterval,log=yLog,/exact)
oYaModel->add, oYaxis1
oYaModel->add, oYaxis2 

; create legend variables
item_color = bytarr(3,nData)
if (nData eq 1) then item_color = reform(item_color,3,1)
item_linestyle = bytarr(nData)+6b
item_object = objarr(nData)
item_type = bytarr(nData)

; Now cycle through the DaveDat objects and create appropriate IDL gr atoms to
; represent them
;----------------------------------------------------------------------------
for i=0,nData-1 do begin
    ;; Deal with dataset label


    ;; get the x,z-axis data
    if (not (dataRef[i])->get(xtype=xtype,xval=xval,zval=zval,zerr=zerr)) then goto, DestroyModel

    ;; Axes labels should be set, if necessary, using first dataset's values
    if (i eq 0) then begin
        oXfont = obj_new('IDLgrFont',name=xFont,size=xFontSize)
        oMiscCont->add,oXfont
        if (n_elements(xlabel) eq 0) then xlabel='X axis title'
        oXlabel = obj_new('IDLgrText',xlabel,name='XAXISLABEL',font=oXfont,/enable_formatting)
        oXaxis1->setProperty, title=oXlabel
        oMiscCont->add, oXlabel
        oXaxis1->getProperty, ticktext=ttRef ; get the axis tick text object
        ttRef->setProperty, font=oXfont ; and assign it the same font as for the label

        oYfont = obj_new('IDLgrFont',name=yFont,size=yFontSize)
        oMiscCont->add,oYfont
        if (n_elements(ylabel) eq 0) then ylabel='Y axis title'
        oYlabel = obj_new('IDLgrText',ylabel,name='YAXISLABEL',font=oYfont,/enable_formatting)
        oYaxis1->setProperty, title=oYlabel
        oMiscCont->add, oYlabel
        oYaxis1->getProperty, ticktext=ttRef ; get the axis tick text object
        ttRef->setProperty, font=oYfont ; and assign it the same font as for the label
    endif

    nz = n_elements(zval)
    nx = n_elements(xval)
    
    ;; create appropriate vectors to hold point data generated from
    ;; point/histogram data originally
    switch strmid(strupcase(xtype),0,4) of
        'POIN': break
        
        'HIST': begin
            xindex = lindgen(nx-1)
            xvalMid = 0.5*(xval[xindex]+xval[xindex+1]) ; ==> mid values of the bin boundaries
            xval = xvalMid
            break
        end
    endswitch

    ;; Apply scalefactor and offset to data
    ;; (**These are scalefactors set for individual DaveDat* datasets** - now done in the get() method)
    ;; xscale and yscale are set for the graphic object as a whole
    xval = xval*xscale
    ;zval = (zval*scalefactor + offset)*yscale
    ;if (n_elements(zerr) gt 0) then zerr = zerr*scalefactor*yscale
    zval = zval*yscale
    if (n_elements(zerr) gt 0) then zerr = zerr*yscale

    ; using log x-axis?
    if (xLog) then begin
        index = where((xval ge xmin0) and (xval le xmax0), count)
        if (count gt 0) then begin
            xval = alog10(xval[index])
            zval = zval[index]
        endif else continue
    endif

    ; using log y-axis?
    if (yLog) then begin
        index = where((zval ge ymin0) and (zval le ymax0), count)
        if (count gt 0) then begin
            zval = alog10(zval[index])
            xval = xval[index]
        endif else continue
    endif
    

    ; if performing a log plot, then take log of data
    ;if (ylog) then zval = alog10(zval)

    ;; create:
    ;;  - 1 sub IDLgrModel to hold the graphic atoms :-
    ;;  - 1 line plot atom, if lineSymFlag=0 or 2
    ;;  - 1 symbol plot atom, if lineSymFlag=1 or 2
    ;;  - 1 (associated) error atom (as polylines) [if errobars requested]
    ;;------------------------------

    ;; The model
    case lineSymFlag[i] of
        0: modelName = 'LMODEL' ; lines only
        1: modelName = 'SMODEL' ; symbols only
        2: modelName = 'LSMODEL' ; lines+symbols
    endcase
    oPlotModel = obj_new('IDLgrModel',name=modelName,/select_target) ; make it selectable
    oModel->add, oPlotModel

    lineType[i] = (lineType[i] lt 0)? 0 :  lineType[i]
    lineType[i] = (lineType[i] gt 5)? 5 : lineType[i]
    lineSize[i] = (lineSize[i] lt 1.0)? 1.0 : lineSize[i]
    lineSize[i] = (lineSize[i] gt 10.0)? 10.0 : lineSize[i]
    symType[i] = (symType[i] lt 1)? 1 : symType[i]
    symSize[i] = (symSize[i] lt 1.0)? 1.0 : symSize[i]
    symSize[i] = (symSize[i] gt 10.0)? 10.0 : symSize[i]

    item_color[*,i] = reform(color[i,*])

    ;; The errors: create first so that it is behind the symbols.
    if ((keyword_set(dispError)) and (n_elements(zerr) gt 0)) then begin
        oPlotErr = createObjectGrErrors(xval,zval,zerr,xrange=[xmin,xmax],yrange=[ymin,ymax],log=ylog $
                                        ,thick=lineSize[i],uvalue={objRef:self,datInd:i})
        if (obj_valid(oPlotErr) eq 1) then begin
            oPlotErr->setProperty, color=reform(color[i,*]), name='EPLOT'
            oPlotModel->add,oPlotErr
        endif
    endif

    ;; The line plot
    if (lineSymFlag[i] ne 1) then begin
        plotName = 'LPLOT'      ;+strtrim(string(i),2)
        oPlot = obj_new('IDLgrPlot',xval,zval,name=plotName,linestyle=lineType[i],thick=lineSize[i] $
                        ,color=reform(color[i,*]),xrange=[xmin,xmax],yrange=[ymin,ymax] $
                        ,uvalue={objRef:self,datInd:i})
        oPlotModel->add, oPlot

        item_linestyle[i] = lineType[i]
    endif
    ;; The symbol plot
    if (lineSymFlag[i] ne 0) then begin
        ;print,'symScale = ',symScale
        plotName = 'SPLOT'      ;+strtrim(string(i),2)
        oSym = obj_new('IDLgrSymbol',data=symType[i],color=reform(color[i,*]),thick=lineSize[i] $
                       ,size=symSize[i]*symScale,uvalue=symScale)
        oMiscCont->add, oSym
        oPlot = obj_new('IDLgrPlot',xval,zval,name=plotName,symbol=oSym,color=reform(color[i,*]) $
                        ,xrange=[xmin,xmax],yrange=[ymin,ymax],thick=lineSize[i] $
                        ,linestyle=6,uvalue={objRef:self,datInd:i})
        oPlotModel->add, oPlot

        item_object[i] = oSym
    endif

endfor

; Main plot title
oLabelModel = obj_new('IDLgrModel',name='LABMODEL',/select_target) ; make it selectable
oModel->add, oLabelModel
xs = scale_coord([0,1],[vplaneX0,vplaneX0+vplaneW])
ys = scale_coord([0,1],[vplaneY0,vplaneY0+vplaneH])
if ((dispTitle eq 1) and (strtrim(title.text,2) ne '')) then begin
    oTitleFont = obj_new('IDLgrFont',name=title.font,size=title.fontsize)
    oMiscCont->add,oTitleFont   ; so it can be properly cleaned up
    oTitle = obj_new('IDLgrText',title.text,name='LABEL',font=oTitleFont,/enable_formatting $
                     ,location=title.position,alignment=title.alignment,color=title.color $
                     ,xcoord_conv=xs,ycoord_conv=ys,uvalue={objRef:self,datInd:-1})
    oLabelModel->add,oTitle
endif

; Miscellaneous text labels
while (nlabel gt 0) do begin
    nlabel = nlabel - 1
    newLabel = labelArray[nlabel]
    oLabelModel = obj_new('IDLgrModel',name='LABMODEL',/select_target) ; make it selectable
    oModel->add, oLabelModel
    oLabelFont = obj_new('IDLgrFont',name=newLabel.font,size=newLabel.fontsize)
    oMiscCont->add,oLabelFont   ; so it can be properly cleaned up
    oLabel = obj_new('IDLgrText',newLabel.text,name='LABEL',font=oLabelFont,/enable_formatting $
                     ,location=newLabel.position,alignment=newLabel.alignment,color=newLabel.color $
                     ,xcoord_conv=xs,ycoord_conv=ys,uvalue={objRef:self,datInd:nlabel})
    oLabelModel->add,oLabel
endwhile

; The Legend
item_name = legend.itemName[0:nData-1]
item_thick = legend.itemThick[0:nData-1] 

xs = scale_coord([0,1],[vplaneX0,vplaneX0+vplaneW])
ys = scale_coord([0,1],[vplaneY0,vplaneY0+vplaneH])

olegTitFont = obj_new('IDLgrFont',name=legend.tFont,size=legend.tFontsize)
olegFont = obj_new('IDLgrFont',name=legend.font,size=legend.fontsize)
olegTitle = obj_new('IDLgrText',legend.title,font=olegTitFont,color=legend.tcolor,/enable_formatting)
oMiscCont->add,[olegTitFont,olegFont,olegTitle] ; so they can be cleaned

oLegend = obj_new('IDLgrLegend',name='LEGEND',fill_color=legend.bkgdColor $
                  ,font=olegFont,gap=legend.gap,glyph_width=legend.gwidth,hide=legend.hideFlag $
                  ,title=olegTitle,show_outline=legend.outlFlag,show_fill=legend.fillFlag $
                  ,outline_color=legend.outlColor,outline_thick=legend.outlThick $
                  ,text_color=legend.textColor,item_name=item_name $
                  ,item_linestyle=item_linestyle,item_color=item_color,item_thick=item_thick $
                  ,item_object=item_object,item_type=item_type $
                  ,xcoord_conv=xs,ycoord_conv=ys,/select_target $
                  ,uvalue={objRef:self,datInd:0,vpdim:[vplaneW,vplaneH]})

oLegend->Translate,legend.location[0]*vplaneW,legend.location[1]*vplaneH,0.0
oView->add, oLegend

; Finally add the model to the view
oView->add, oModel
return, 1

; Destroy  oModel if an error condition was encountered
DestroyModel:
if (obj_valid(oModel)) then obj_destroy, oModel
return, 0
 
end
;-------------------------------------------------------------------------------



;===============================================================================
; DaveGr1D::Display
;
; PURPOSE:
;   Create a line plot of the object's dataset(s).
;
; PARAMETERS:
;   oDest [in] - a valid IDL graphics destination object
;
;   oScene [in] - the IDLgrScene object that is used as the root of
;                 the object graphics hierarchy that would be
;                 constructed.
;
; KEYWORDS:
;   dispType [in] - specify display type (either 'histogram' or
;                   'points'). If dispType is not set, then the
;                   (x-axis) data type determines the display mode.
;
;   _EXTRA [in] - Allows keywords to be passed on
;
pro DaveGr1D::display, oDest, oScene, dispType=dispType, _EXTRA=etc

; reset !error_state structure, ie clear all errors
message,/reset

; ensure (required) number of parameters are present
if (n_params() ne 2) then begin
    !error_state.code = -1
    !error_state.msg = "DaveGr1D::display: Two parameters required for this procedure call"
    return
endif

; Don't proceed any further if there is no data
if (self->count() lt 1) then begin
    !error_state.code = -1
    !error_state.msg = "DaveGr1D::display: No data to display!"
    return
endif

; oDest should be a valid destination object
valid = ['IDLGRWINDOW','IDLGRBUFFER','IDLGRCLIPBOARD','IDLGRPRINTER','IDLGRVRML']
res = where(vartype(oDest) eq valid, okay)
if (not okay) then begin
    !error_state.code = -1
    !error_state.msg = "DaveGr1D::display: parameter 1 (oDest) must be a valid IDL Object Graphics destination object"
    return
endif

; oScene should be a valid IDL Graphics container object
valid = ['IDLGRMODEL','IDLGRSCENE','IDLGRVIEW','IDLGRVIEWGROUP']
res = where(vartype(oScene) eq valid, okay)
if (not okay) then begin
    !error_state.code = -1
    !error_state.msg = "DaveGr1D::display: parameter 2 (oScene) must be a valid IDL Object Graphics container object"
    return
endif

; Get contents of the current scene and destroy them
objects = oScene->get(/all, count=nObjects)
if (nObjects gt 0) then begin
    print,'**** Destroying Scene...'
    obj_destroy, objects
endif

; display data based on dispType keyword settings (or x-axis data type
; setting of the first object in the container).
if (n_elements(dispType) gt 0) then begin
    dispType = strmid(strupcase(dispType),0,4)
endif else begin
    ;; get the x-axis data type of the first DaveDat object
    if (not self->get(dataRef=dataRef, position=0)) then return
    if (not dataRef->get(xtype=xtype)) then return
    dispType = strmid(strupcase(xtype),0,4)
endelse

; if etc is empty, insert a dummy keyword into it
if (n_elements(etc) eq 0) then etc = {dummy:0}

case dispType of
    'POIN': begin
        oDest->getProperty, dimensions=dim
        retVal = self->dispPoints(oScene,dim,_EXTRA=etc)
    end
    'HIST': retVal = self->dispHistograms(oScene,_EXTRA=etc)
endcase

if (retVal ne 1) then begin
    print,'DaveGr1D::display: ERROR - DATA DISPLAY WAS UNSUCCESSFUL'
endif else $
    oDest->draw, oScene

return

end
