;+ ;spd_ui_draw_object method: updatePanels ; ;draws the panels for this window. ;This routine is the workhorse of the draw object, ; ;Inputs: ; Layout Dims(2-elements long): The number of rows and columns in the layout(from the spd_ui_window) ; Margins(6-elements double): The size of the margins for the panel in points. Elements are as follows ; [left,right,top,bottom,horizontal_internal,vertical_internal] ; PanelObjs(array of objects): Array of references to the spd_ui_panel objects being drawn ; LoadedData(object): Reference to the spd_ui_loaded_data object in which the data to be plotted is stored ; Backgroundcolor(3-element Byte array): The color of the background, needed to emulate some transparency effects. ; Locked(long index): The locked value from the window object. -1 is unlocked, otherwise it is the index ; of the panel to which others are locked. Index in terms of the list of panelObjs ; Window(object): The active window from which the drawn panels originate. Needed to query layout information. ; ; ;Outputs: ; returns 1 on success, 0 on failure ; errmsg: a struct describing an error that has occurred, to be passed up to calling routine. ; The existance of errmsg does not guarantee updatePanels returns 0 and vice versa. ; Currently updatepanels itself does not set errmsg, it is simply passed on through here to other routines ; (presently only getRange and makeView). ; See spd_ui_draw_object_update for more details. ; ;Mutates: ; self.panelViews,self.staticViews,self.dynamicViews,self.panelInfo ; ;NOTE: The order in which various elements of the panel are added to the display is IMPORTANT ;If you change the ordering be sure to check that this change hasn't oscured some ;important feature. ; ;$LastChangedBy: nikos $ ;$LastChangedDate: 2017-11-20 10:43:28 -0800 (Mon, 20 Nov 2017) $ ;$LastChangedRevision: 24317 $ ;$URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/tags/spedas_5_0/spedas_gui/display/draw_object/spd_ui_draw_object__updatepanels.pro $ ;- function spd_ui_draw_object::updatePanels,layoutDims,margins,panelObjs,loadedData,backgroundcolor,locked,window, errmsg=errmsg compile_opt idl2,hidden systm = systime(/seconds) ;This factor determines the distance the panel title is placed from the panel proper panelTitleVposFactor = .1 dataXptr = ptr_new() dataYptr = ptr_new() dataZptr = ptr_new() ;Normalize the margin values to draw area marginsNorm = [self->pt2norm(margins[0],0),$ ;left self->pt2norm(margins[1],0),$ ;right self->pt2norm(margins[2],1),$ ;top self->pt2norm(margins[3],1),$ ;bottom self->pt2norm(margins[4],0),$ ;internal margin x self->pt2norm(margins[5],1)] ;internal margin y ;these structures serve as a quick reference for performing fast graphical operations legendInfoStruct = { $ notationSet:0, $ timeFormat:6, $ numFormat:5, $ xIsTime:0, $ yIsTime:0, $ zIsTime:0 $ } panelInfoStruct = {xplotpos:[0D,1D],$ ;position of the plot yplotpos:[0D,1D],$ margins:dblarr(5),$ ; size of edge components. Used for identifying location of click in panel [left,right,top,bottom,vars] locked:0,$ lockedRange:[0D,1D],$ ; alternative range to use for plot scaling, in the event of locked panels lockedScale:0,$; alternative scaling to use xrange:[0D,1D],$ ;data range of the plot yrange:[0D,1D],$ zrange:[0D,1D],$ xmajorSize:0D,$ ;size of a major tick in converted data space(log applied if logarithimic) ymajorSize:0D,$ xscale:0,$ ;indicates log or normal scaling yscale:0,$ xcenter:0d, $ ycenter:0d, $ lockedcenter:0d, $ xmajorNum:0,$ ; the number of major ticks on the x-axis ymajorNum:0,$ ; the number of major ticks on the y-axis zmajorNum:0,$ ; the number of major ticks on the z-axis xminorNum:0,$ ; the number of minor ticks on the x-axis yminorNum:0,$ ; the number of minor ticks on the y-axis zminorNum:0,$ ; the number of minor ticks on the z-axis xisTime:0,$ ;indicates whether the axis is time yisTime:0,$ hasSpec:0,$ ;boolean, indicates whether a spectrogram is present hasLine:0,$ ;boolean, indicates whether a line is present zscale:0,$ ;indicates log/lin scaling for z axis zisTime:0,$ ;indicates whether the z axis is a time(I'm not sure a z time axis is possible) zplacement:4,$ ;0:top,1:bottom,2:left,3:right,4:no zaxis markerIdx:-1,$ ; indicates the index the highlighted marker(if any) on this panel traceInfo:ptr_new(),$ ;ptr to array of info for each trace varInfo:ptr_new(),$ ; ptr to array of variable info markerInfo:ptr_new(),$ ; ptr to array of marker info vBar:obj_new(),$ ;ptr to vertical bar model hBar:obj_new(),$ ;ptr to horizontal bar model marker:obj_new(),$ ;ptr to currently drawing marker model annotation:obj_new(),$ ;ptr to annotation view view:obj_new(),$ ;ptr to main view xobj:obj_new(),$ ;ptr to independent variable 1 legend text object yobj:obj_new(),$ ;ptr to independent variable 2 legend text object legendModel:obj_new(), $ ;the model in which the legend is stored legendAnnoModel:obj_new(), $ ; the model in which the legend annotations are stored dxptr:[ptr_new(0),ptr_new(0)],$ ; storing the valid data x-range legendInfo:ptr_new(legendInfoStruct) $ ; pointer to the legend structure defined above } traceInfoStruct = { $ isSpec:0,$ ; dataX:ptr_new(),$ ; dataY:ptr_new(),$ ; dataZ:ptr_new(),$ refData:ptr_new(),$ abcissa:ptr_new(),$ plotData:ptr_new(), $ ;pointer to a struct in which some information is passed internally. dataName:'',$ color:[0,0,0],$ textObj:obj_new() $ ;text object that displays dependent variable text output } varInfoStruct = { $ dataX:ptr_new(),$ ;ptr to the x data quantity(note that this is normalized data, not real data) dataY:ptr_new(),$ ; ptr to the y data quantity textObj:obj_new(),$ ; ptr to the text object to be updated during tracking isTime:0B, $ ; indicates whether the data y is a time annotateStyle:0, $ ; the annotation style for the output scaling:0, $ ;0=linear,1=log10,2=log range:[0D,1D] $ } markerInfoStruct = { $ pos:[0D,1D], $ ;the x-start & x-stop of the marker in normalized panel coordinates color:[0B,0B,0B], $ ; the original color of the frame frames:[obj_new(),obj_new()], $ ;the IDLgrPolyline objects for the left and right sides of the marker frame selected:0, $ ;indicates whether marker is selected displayed:0 $ ;indicates whether the marker is displayed at this level of zoom } lockedIsTime = -1 panelInfoArray = replicate(panelInfoStruct,n_elements(panelObjs)) ;Gets the variable size of all the variables in the layout ;Note this has a problem, because it doesn't account for panels in separate columns ;It should get the height of all the variables in a column. self->getRowTextSizes, panelObjs, top_sizes=top_sizes, bottom_sizes=bottom_sizes bottom_sizes = self->pt2norm(bottom_sizes,1) top_sizes = self->pt2norm(top_sizes,1) ;Do not alter panel layout to account for panel titles unless panels are locked. ; -This is partly for consistency as no other annotations are accounted for ; (sans variables), but also to prioritize data space over annotation space. if locked eq -1 then top_sizes[*] = 0. ;calculate the range of the locked panel ;so that we can use it on other panels if locked ne -1 then begin if locked ge n_elements(panelObjs) then begin self.historyWin->update,'Warning: Locked value requests locking to nonexistent panel' self.statusBar->update,'Warning: Locked value requests locking to nonexistent panel' endif else begin currentPanel = panelObjs[locked] currentPanel->getProperty,traceSettings=traceSettings,xAxis=xAxis,yAxis=yAxis,zAxis=zAxis ;reverse the order of trace processing so that spectrograms layer correctly traces = reverse(traceSettings->get(/all)) ;extract and process data if obj_valid(traces[0]) then begin yaxis->getProperty,scaling=yscale ;Removes copies of data from draw object, ;Performs some basic formatting. ;Generate mirror data if needed self->collatedata,traces,loadedData,yscale=yscale,outXptrs=dataXptr,outYptrs=dataYptr,outZptrs=dataZptr,mirror=mirrorptr,fail=fail,dataNames=dataNames,dataidx=dataidx if fail then begin self.historyWin->update,'Failed to read data for locking master panel' return,0 endif if dataidx[0] ne -1 then begin ;some data quantities may turn out invalid, so we remove those traces = traces[dataidx] dataXptr = dataXptr[dataidx] dataYptr = dataYptr[dataidx] dataZptr = dataZptr[dataidx] mirrorptr = mirrorptr[dataidx] datanames = datanames[dataidx] ;get plot range self->getRange,dataXptr,xAxis,range=lockedRange,scaling=lockedScale,istime=lockedIsTime,fail=fail,center=lockedcenter, errmsg=errmsg,isspec=obj_valid(zAxis) if fail then begin self.historyWin->update,'No range on locking master panel.' return,0 endif else begin ptr_free,dataXptr,dataYptr,dataZptr,mirrorPtr endelse endif else begin self.historyWin->update,'No valid data on locking master panel.' lockedRange = [0D,1D] lockedScale = 0 lockedcenter = 0.5 endelse endif else begin self.historyWin->update,'No valid traces on locking master panel' lockedRange = [0D,1D] lockedScale = 0 lockedcenter = 0.5 endelse endelse endif ;This is the big loop in this function, ;It loops over all the panelObjects for i = 0,n_elements(panelObjs) - 1 do begin ;print,"panel:",i,systime(/seconds)-systm currentPanel = panelObjs[i] ;Modify settings to reflect locked expectations. ;This will override some user settings if locked ne -1 then begin ;The window tells us where the panel is within the layout ;I suspect this can be fooled by irregular layouts panelLayoutPos = window->getPanelPos(currentPanel) if panelLayoutPos eq -1 then begin self.historyWin->update,'Problem evaluating locked panel layout' self.statusBar->update,'Problem evaluating locked panel layout' return,0 endif else if panelLayoutPos eq 1 then begin self->lockBottom,currentPanel endif else if panelLayoutPos eq 2 then begin self->lockMiddle,currentPanel endif else if panelLayoutPos eq 3 then begin self->lockTop,currentPanel endif ;doesn't modify a panel that is only in column end currentPanel->getProperty,settings=settings,markers=markerContainer, $ variables=variableContainer,showvariables=showvariables,legendSettings=legendSettings panelInfoArray[i].legendInfo = ptr_new(legendSettings) settings->getProperty,row=row,col=col,rSpan=rSpan,cSpan=cSpan, $ backgroundcolor=color,titleobj=titleobj,framecolor=framecolor, $ framethick=framethick,titleMargin=titleMargin layoutPos = [row,col,rSpan,cSpan] ;Coordinates of the panel in points. pcoord = currentPanel->getPanelCoordinates() ;normalize coordinates pcoord = [(pcoord[0] ne -1)?self->pt2norm(pcoord[0],0):-1,$ (pcoord[1] ne -1)?self->pt2norm(pcoord[1],1):-1,$ (pcoord[2] ne -1)?self->pt2norm(pcoord[2],0):-1,$ (pcoord[3] ne -1)?self->pt2norm(pcoord[3],1):-1] ;Pull any markers out of IDL_Container markerNum = 0 if obj_valid(markerContainer) && obj_isa(markerContainer,'IDL_Container') then begin markerList = markerContainer->get(/all) if obj_valid(markerList[0]) then begin markerNum = n_elements(markerList) markerInfo = replicate(markerInfoStruct,markerNum) endif endif varNum = 0 ;showvariables = 1 ;Pull any variables out of IDL_Container if obj_valid(variableContainer) && $ obj_isa(variableContainer,'IDL_Container') && $ showvariables then begin varList = variableContainer->get(/all) if obj_valid(varList[0]) then begin varNum = n_elements(varList) varInfo = replicate(varInfoStruct,varNum) panelInfoArray[i].varInfo = ptr_new(varInfo) endif endif ;The next call returns all the different views used for different parts of the panels ;I'd very much like to create the returned views by calling this routine each time I need a view,(rather than returning multiple identical items from 1 call) ;but for some reason the transparency doesn't work if I do that. It seems very odd, although maybe I'm missing something obvious. ;(like mutating an input so that the second call produces differing results) self->makeView,$ layoutDims,$ marginsNorm,$ layoutPos,$ pcoord,$ markernum,$ bottom_sizes,$ top_sizes,$ view=view,$ annotation=annotation,$ markers=markerviews,$ xplotPos=xplotPos,$ yplotpos=yplotpos,$ outmargins=outmargins,$ fail=fail,$ errmsg=errmsg if fail then return,0 panelInfoArray[i].annotation=annotation panelInfoArray[i].view=view panelInfoArray[i].margins=outmargins ;This should be fixed, mutation will not have any outward effect. ;It should newsize = self->getpanelsize(xplotpos,yplotpos) currentPanel->setPanelCoordinates,newsize ;add views to graphics tree self.panelViews->add,view self.panelViews->add,annotation ;add static components to the list of static views self.staticViews->add,view ;add animated components to the list of dynamic views self.dynamicViews->add,annotation ;title if obj_valid(titleobj) then begin grTitleObj = self->getTextObject(titleobj,[.5,self->pt2norm(titleMargin,1)/(yplotpos[1]-yplotPos[0])+1.,.5],1,0) grTitle = obj_new('IDLgrModel') grTitle->add,grTitleObj view->add,grTitle endif ;get data quantities currentPanel->getProperty,traceSettings=traceSettings,traceFillSettings=traceFillSettings,xAxis=xAxis,yAxis=yAxis,zAxis=zAxis ;reverse the order of trace processing so that spectrograms layer correctly traces = reverse(traceSettings->get(/all)) ;extract and process data if obj_valid(traces[0]) then begin yaxis->getProperty,scaling=yscale self->collateData,traces,loadedData,yscale=yscale,outXptrs=dataXptr,outYptrs=dataYptr,outZptrs=dataZptr,mirror=mirrorptr,fail=fail,dataNames=dataNames,dataidx=dataidx if fail then return,0 if dataidx[0] ne -1 then begin ;some data quantities may turn out invalid, so we remove those ; traces = traces[dataidx] ; dataXptr = dataXptr[dataidx] ; dataYptr = dataYptr[dataidx] ; dataZptr = dataZptr[dataidx] ; mirrorptr = mirrorptr[dataidx] ; datanames = datanames[dataidx] ;get plot x range self->getRange,dataXptr,xAxis,scaling=xscaling,range=xrange,fail=fail,center=lockedCenter,errmsg=errmsg,isSpec=obj_valid(zAxis) dataRange = *dataXptr[0] ;translate the range into the scaling used by this trace if size(lockedRange,/type) then begin panelInfoArray[i].locked = 1 panelInfoArray[i].lockedRange = lockedRange panelInfoArray[i].lockedScale = lockedScale if ~undefined(lockedCenter) then panelInfoArray[i].xcenter= lockedCenter currentRange = lockedRange currentScale = lockedScale endif else begin currentRange = xrange currentScale = xscaling endelse ;The large block of nested if-statements below ;performs all the data processing tasks to prepare ;the data for plotting and in the event of a failure, ;to properly set the remaining values in such a way ;that it fails gracefully if fail then begin traceInfoArray = 0 xrange = [0D,1D] if size(lockedRange,/type) then begin currentRange=lockedRange currentScale = lockedScale endif else begin currentRange = [0D,1D] currentScale = 0 endelse yrange = [0D,1D] yscale = 0 zrange = [0D,1D] traces = 0 zscaling = 0 endif else begin panelInfoArray[i].xrange=xrange panelInfoArray[i].xscale=xscaling if ~undefined(lockedCenter) then panelinfoarray[i].xcenter=lockedCenter ;clip the data with respect to x-axis self->xclip,dataXptr,dataYptr,dataZptr,currentRange,currentScale,fail=fail,mirrorptr=mirrorptr ; spd_ui_xyclip,dataXptr,dataYptr,dataZptr,xrange,xscaling,fail=fail,transposez=0,mirrorptr=mirrorptr if fail then begin traceInfoArray = 0 yrange = [0D,1D] yscale = 0 zrange = [0D,1D] traces = 0 zscaling = 0 endif else begin ;get plot y range self->getRange,dataYptr,yAxis,scaling=yscaling,mirror=mirrorptr,range=yrange,fail=fail,center=ycenter, errmsg=errmsg,isspec=obj_valid(zAxis) if fail then begin traceInfoArray = 0 traces = 0 yrange = [0D,1D] zrange = [0D,1D] zscaling = 0 endif else begin panelInfoArray[i].yrange=yrange panelInfoArray[i].yscale=yscaling if ~undefined(yCenter) then panelinfoarray[i].ycenter=ycenter ;clip with respect to y axis self->yclip,dataXptr,dataYptr,dataZptr,yrange,yscaling,fail=fail,mirrorptr=mirrorptr ; spd_ui_xyclip,dataYptr,dataXptr,dataZptr,yrange,yscaling,fail=fail,transposez=1,yaxis=1,mirrorptr=mirrorptr ;spd_ui_xyclip,mirrorptr,dataXptr,dataZptr,yrange,yscaling,fail=fail,transposez=1,keepnans=1 if fail then begin traceInfoArray = 0 traces = 0 zrange = [0D,1D] zscaling = 0 endif else begin ;print,"gotxy range",systime(/seconds)-systm if obj_valid(zAxis) then begin ; panelInfoArray[i].hasSpec = 1 ;get plot z range self->getZRange,dataZptr,zAxis,range=zrange,scaling=zscaling,fixed=zFixed,fail=fail if fail then begin traceInfoArray = 0 traces = 0 zrange = [0D,1D] zscaling = 0 endif else begin panelInfoArray[i].zscale=zscaling panelInfoArray[i].zrange=zrange ; self->zclip ;clip with respect to z-axis spd_ui_xyzclip,dataZptr,zrange,zscaling,fail=fail if fail then begin traceInfoArray = 0 traces = 0 endif endelse traceInfoArray = replicate(traceInfoStruct,n_elements(traces)) ; traceInfoArray[*].isSpec = 1 ; traceInfoArray[*].dataX = dataXptr ; traceInfoArray[*].dataY = dataYptr ; traceInfoArray[*].dataZ = dataZptr if obj_valid(traces[0]) then begin ;set the list of names on each trace traceInfoArray[*].dataName = dataNames endif endif else begin zrange = [0D,1D] zscaling = 0 traceInfoArray = replicate(traceInfoStruct,n_elements(traces)) ; traceInfoArray[*].isSpec = 0 ; traceInfoArray[*].dataX = dataXptr ; traceInfoArray[*].dataY = dataYptr ; traceInfoArray[*].dataZ = dataZptr if obj_valid(traces[0]) then begin traceInfoArray[*].dataName = dataNames endif endelse endelse endelse endelse endelse endif else begin traceInfoArray = 0 if size(lockedRange,/type) then begin currentRange=lockedRange currentScale = lockedScale endif else begin currentRange = [0D,1D] currentScale = 0 endelse yrange = [0D,1D] yscale = 0 zrange = [0D,1D] traces = 0 zscaling = 0 endelse ;print,"got zrange",systime(/seconds)-systm endif else begin traceInfoArray = 0 if size(lockedRange,/type) then begin currentRange=lockedRange currentScale = lockedScale endif else begin currentRange = [0D,1D] currentScale = 0 endelse yrange = [0D,1D] yscale = 0 zrange = [0D,1D] endelse ;draw permanent markers if markerNum gt 0 then begin zstack = .21 + .0001 for j = 0,n_elements(markerList)-1 do begin self->addMarker,markerviews[j],markerList[j],currentrange,zstack,fail=fail,markerpos=markerpos,markerframes=markerframes,markercolor=markercolor,markerSelected=markerSelected if ~fail then begin ;set all the information needed for operations that occur between updates zstack += .0001 self.panelViews->add,markerviews[j] markerInfo[j].pos = markerpos markerInfo[j].frames = markerFrames markerInfo[j].color = markercolor markerInfo[j].displayed = 1 markerInfo[j].selected = markerSelected ;adding marker view to dynamic view list self.dynamicViews->add,markerViews[j] endif else begin markerInfo[j].displayed = 0 obj_destroy,markerviews[j] endelse endfor panelInfoArray[i].markerInfo = ptr_new(markerInfo) endif ;make axes ;DEFSYSV,'!VIEW',view ;This creates all models associated with the x axis self->makeXYaxisModel, $ 0,$ currentrange,$ yrange,$ currentScale,$ xAxis,$ yplotpos,$ xplotpos,$ framecolor,$ framethick,$ backgroundcolor,$ useIsTime=lockedIsTime,$ model=xAxisModel,$ gridmodel=gridmodelx,$ majors=xAxisMajors,$ minorNum=xMinorNum,$ isTimeAxis=xistime,$ labelpos=labelpos,$ fail=fail if fail then return,0 ;This creates all models associated with the y axis self->makeXYaxisModel, $ 1,$ currentrange,$ yrange,$ yscale,$ yAxis,$ xplotpos,$ yplotpos,$ framecolor,$ framethick,$ backgroundcolor,$ model=yAxisModel,$ gridmodel=gridmodely,$ majors=yAxisMajors,$ minorNum=yMinorNum,$ isTimeAxis=yistime,$ fail=fail if fail then return,0 ;Some processing on these major variables. ;They will be stored for return to the ;calling routine via getPanelInfo if n_elements(xAxisMajors) lt 2 then begin ;if x axis majors are not set, use the x-range xMajorSize = currentrange[1]-currentrange[0] xMajorNum = 0 endif else begin ;this rescales the x-majors into data space. xMajorSize = (currentRange[1]-currentRange[0])*median(xAxisMajors[1:n_elements(xAxisMajors)-1]-xAxisMajors[0:n_elements(xAxisMajors)-2]) xMajorNum = n_elements(xAxisMajors)-2 endelse if n_elements(yAxisMajors) lt 2 then begin ;if y axis majors are not set, use the y-range yMajorSize = yrange[1]-yrange[0] yMajorNum = 0 endif else begin ;this rescales the y-majors into data space. yMajorSize = (yrange[1]-yrange[0])*median(yAxisMajors[1:n_elements(yAxisMajors)-1]-yAxisMajors[0:n_elements(yAxisMajors)-2]) yMajorNum = n_elements(yAxisMajors)-2 endelse ;Storing information about major ticks for output panelInfoArray[i].xmajorsize=xmajorsize panelInfoArray[i].ymajorsize=ymajorsize panelInfoArray[i].xmajornum=xmajornum panelInfoArray[i].ymajornum=ymajornum panelInfoArray[i].xminornum=xminornum panelInfoArray[i].yminornum=yminornum panelInfoArray[i].xistime=xistime panelInfoArray[i].yistime=yistime ;If we have a z-axis object if obj_valid(zAxis) then begin ;Get the z-axis color palette number( number corresponds to rainbow, hot-cold, spedas, etc...not in that order) zaxis->getProperty,colorTable=paletteNum ;The actual z-range of autoscaled data may actually decrease during the clipping that occurs during rendering ;This variable is used as part of a fix that rescales at the last minute to increase dynamic range. In other words, ;if the plot is zoomed, data that is not on screen could make the z-range wider than it would be if not for this fix. if ~keyword_set(zfixed) then begin zRangeRecalc = [!VALUES.D_NAN,!VALUES.D_NAN] endif endif ;If we have any valid traces ;this block will generate models representing the ;data itself if obj_valid(traces[0]) then begin ;Calculate the size of the panel for the purpose of generating spec plots ;This will be a 2-element array, with the values being some multiple/fraction of the ;number of pixels on each axis respectively. panel_sz_pt = self->getPlotSize(xplotpos,yplotpos,self.specres) ;If we're generating a postscript, ;All the spectral plots in a panel will be turned ;into a single composite image. Prior to this ;They will be stored in this container if self.postscript then begin spec_list = obj_new('IDL_Container') endif ;Create shaded fill areas between lines as needed if traceFillSettings.count() gt 0 then begin fills = traceFillSettings.get(/all) for j=0,n_elements(fills)-1 do begin if obj_isa(fills[j],'spd_ui_linefill_settings') then begin fillinfo = fills[j].getall() tridx = where((traceInfoArray.dataname eq fillinfo.datay1) or (traceInfoArray.dataname eq fillinfo.datay2)) if n_elements(tridx) eq 2 then begin polymodel = self->getLineFill(traces[tridx],currentRange,yrange,dataXptr[tridx],dataYptr[tridx],color=fillinfo.fillcolor,alpha=fillinfo.opacity) view->add,polymodel endif endif endfor endif ;Loop over traces in the panel for j = 0,n_elements(traces)-1 do begin ;Create line model if obj_isa(traces[j],'spd_ui_line_settings') && $ ptr_valid(dataXptr[j]) && $ ptr_valid(dataYptr[j]) then begin panelInfoArray[i].hasLine = 1 ;Generate a line plot model, and the reference data associated with it. linePlot = self->getLinePlot(traces[j],currentRange,yrange,xplotpos,yplotpos,currentScale,yscaling,xAxisMajors,dataXptr[j],datayPtr[j],panelInfoArray[i].xistime,linecolor=linecolor,mirrorptr=mirrorptr[j],refvar=refvar,abcissa=abcissa) if ~obj_valid(linePlot) then begin self.statusbar->update,'Error: Could not generate the plot due to internal error' self.historyWin->update,'Error: Could not generate the plot due to internal error' ;ok = error_message('Invalid line plot, indicates plot generation error',/traceback) return,0 endif ;Store the parameters that are generated during line plot creation traceInfoArray[j].color = linecolor ;The dependent variable lookup table for the legend if size(refVar,/type) then begin traceInfoArray[j].refData = ptr_new(refVar) endif traceInfoArray[j].isSpec = 0 ;The independent variable lookup table for the legend ;This is not needed in the current schema because lookup ; can be done by the pixel index if size(abcissa,/type) then begin ;if keyword_set(abcissa) && ~xistime then begin traceInfoArray[j].abcissa = ptr_new(abcissa) endif ;Add the line model to the view view->add,linePlot ;Create Spectral Reference Data endif else if obj_isa(traces[j],'spd_ui_spectra_settings') && $ ptr_valid(dataXptr[j]) && $ ptr_valid(dataYptr[j]) && $ ptr_valid(dataZptr[j]) && $ obj_valid(zAxis) then begin panelInfoArray[i].hasSpec = 1 ;This routine grids spectral data and performs any additional clipping that can be done after gridding. ;This also finds a new range after gridding and clipping, which is necessary to prevent loss of dynamic range on z. ;Because of dependency issues with the rescaling, the complete model cannot be generated at this step. self->getSpecRef,currentRange,yrange,panel_sz_pt[0],panel_sz_pt[1],currentScale,yscaling,zscaling,dataXptr[j],datayptr[j],datazptr[j],refvar=refvar,plotdata=plotdata ;These store the results of getSpecRef in the info struct if size(refvar,/type) ne 0 then begin traceInfoArray[j].refData = ptr_new(refVar) traceInfoArray[j].isSpec = 1 endif if size(plotData,/type) ne 0 then begin traceInfoArray[j].plotData = ptr_new(plotData) if ~keyword_set(zfixed) then begin zRangeRecalc[0] = min([zrangeRecalc[0],min(plotdata.data,/nan)],/nan) zRangeRecalc[1] = max([zrangeRecalc[1],max(plotdata.data,/nan)],/nan) endif endif endif endfor ;Now that we've definitively clipped and gridded the z-data ;We loop over the data again and create the true model. The z-data ;Will be appropriately scaled to ensure we bound the data tightly. if panelInfoArray[i].hasSpec then begin if ~keyword_set(zFixed) && finite(zRangeRecalc[0]) && finite(zRangeRecalc[1]) then begin zRange = zRangeRecalc endif for j = 0,n_elements(traces)-1 do begin if traceInfoArray[j].isSpec && ptr_valid(traceInfoArray[j].plotData) then begin ;This routine actually generates the model self->getSpecModel,traceInfoArray[j].plotData,zrange,paletteNum,model=specModel ;Either add to the view, or add to the list ;for creation of composite image if obj_valid(specModel) then begin if ~self.postscript then begin view->add,specModel endif else begin spec_list->add,specModel endelse endif endif endfor endif if self.postscript && spec_list->count() then begin ;This takes all the individual images and generates a single composite image, ;Which it puts in a model. model = self->aggregateSpecplots(spec_list,panel_sz_pt,color) ;and the model goes on the main view view->add,model endif endif ;Now that the z-range has been definitely locked down, we create the z-axis if obj_valid(zAxis) then begin self->makeZAxisModel,zrange,zAxis,xplotpos,yplotpos,framecolor,framethick,model=zAxisModel,majorNum=zMajorNum,minorNum=zMinorNum zaxis->getProperty,placement=placement ;This stores any information from axis creation process panelInfoArray[i].zplacement=placement panelInfoArray[i].zmajornum=zmajornum panelInfoArray[i].zminornum=zminornum endif ; print,"made plot",systime(/seconds)-systm ;Now we generate models for dynamic content vBarModel = obj_new('IDLgrModel') hBarModel = obj_new('IDLgrModel') markerModel = obj_new('IDLgrModel') ;This is the model for markers in the process of being drawn, not completed markers ;And store any other parameters identified panelInfoArray[i].xplotpos=xplotpos panelInfoArray[i].yplotpos=yplotpos panelInfoArray[i].vBar=vBarModel panelInfoArray[i].hBar=hBarModel panelInfoArray[i].marker = markerModel currentPanel->getProperty,labelMargin=labelMargin ;This adds the variables to the current panel if varNum gt 0 then begin self->addVariables,view,annotation,varList,panelInfoArray[i],loadedData,xAxisMajors,xAxis,labelpos,labelMargin,varptr=varptr ptr_free,panelInfoArray[i].varInfo panelInfoArray[i].varInfo=varptr endif ; print,"added info",systime(/seconds)-systm ;annotation->add,vBarModel annotation->add,vBarModel annotation->add,hBarModel annotation->add,markerModel ;This adds the panel background self->addBackGround,view,color ;This adds the 2-line date string that normally rests in the bottom left or top left self->addDateString,view,xAxis,currentRange,currentScale,xplotpos[1]-xplotpos[0],yplotpos[1]-yplotpos[0],labelMargin if keyword_set(traceInfoArray) then begin ; store the valid data range for loaded data in this panel ; note: this is the full range, not the range shown in the panel ; this is used to check bounds for 'out of range' versus 'NaN' panelInfoArray[i].dxptr = [ptr_new(dataRange[0]), ptr_new(max(dataRange))] paTmp = panelInfoArray[i] ;error occurs if you edit the array in place ;This generates the initial rendering of the legend. The final appearance will be controlled ;Largely by turning the hide flags for the model on and off dynamically self->addLegend,view,annotation,paTmp,traceInfoArray panelInfoArray[i] = paTmp ;print,"added other fun stuff",systime(/seconds)-systm panelInfoArray[i].traceInfo = ptr_new(traceInfoArray) endif else begin panelInfoArray[i].traceInfo = ptr_new() endelse ;add models to the view ;The order in which they were added matters because this changes layering, ;even though it shouldn't ;Currently prior to axes, so that they will be below them in the layering view->add,gridmodelx view->add,gridmodely view->add,xAxisModel view->add,yAxisModel if obj_valid(zAxis) then begin view->add,zAxisModel endif ; ptr_free,dataXptr,dataYptr,dataZptr dataXptr = ptr_new() dataYptr = ptr_new() dataZptr = ptr_new() ;Garbage collect any memory sitting around from this last iteration. ;Most languages would do this automatically, but IDL seems pretty ;bad about it. if double(!version.release) lt 8.0d then heap_gc ;print,"did everything",systime(/seconds)-systm endfor self.panelInfo = ptr_new(panelInfoArray) return,1 end