;+ ; NAME: ; qLine ; PURPOSE: ; Plotting of curves ; CATEGORY: ; Widget qLine ; CALLING SEQUENCE: ; qLine, group=group, x, y, time=time, xsize=xsize, ysize=ysize, charsize=charsize, $ ; title = title, $ ; xmargin = xmargin, $ ; skip = skip, $ ; newyaxis = newyaxis, $ ; exact = exact, $ ; ynozero = ynozero, $ ; ylog = ylog, $ ; linestyle = linestyle, $ ; ytitle = ytitle, $ ; use_sigma = use_sigma, $ ; sigma_index = sigma_index, $ ; plotstr = plotstr ; OPTIONAL INPUT PARAMETERS: ; x array[n] or array[m,n]; type: any ; if y is specified then x should be a 1-dim array with n x-coordinates ; if y is not specified then x[0,*] is used as x-coordinates, while ; x[1:m-1] are used as m-1 curves with n y-values ; y array[m-1,n] ; m-1 curves with n y-values ; The x argument is used as x-coordinate ; ; time = time array[n]; type: time structure ; times corresponding to the n x-coordinates ; xsize = xsize scalar; type: integer; default: 640 ; ysize = ysize scalar; type: integer; default: 480 ; x and y size of plot window (device units) ; charsize = charsize scalar; type: float; default: 1 ; character size ; plotstr = plotstr array[*]; type: string ; string array containing plot commands to be executed ; added to the display (executed using the IDL 'execute' command). ; group = group scalar; type: long integer ; widget ID of group leader if widget is called from other widget ; ; The remaining keywords determine the initial display. All of these can be modified ; once the widget is displayed: ; ; title = title scalar; type: string ; main plot title ; xmargin = xmargin array[2]; type: integer ; same as IDL xmargin keyword ; skip = skip array[m]; type: byte ; 0B: don't plot the curve ; 1B: plot the curve ; newyaxis = newyaxis array[m]; type: byte ; 0B: if existing y-axis is to be used ; 1B: if new y-axis is to be drawn ; exact = exact array[m]; type: byte ; 0B: if no exact y-axis needs to be drawn ; 1B: if exact y-axis is needed ; ynozero = ynozero array[m]; type: byte ; same convention as IDL ynozero keyword ; ylog = ylog array[m]; type: byte ; 0B: for linear y-axis ; 1B: for logarithmic y-axis ; linestyle = linestyle array[m]; type: integer ; same convention as IDL linestyle keyword ; ytitle = ytitle array[m]; type: string ; titles for y-axis ; sigma_index = sigma_index array[m]; type: integer ; index of timeseries to be used as standard deviation ; (first index is 1) ; use_sigma = use_sigma array[m]; type: integer ; 0: do not plot standard deviations ; 1: plot standard deviations ; OUTPUTS: ; (screen or printer) ; CALLS: ; qLine_Kill, qLine_XBase, qLine_YBase, qLine_Print, qLine_Read, qLine_Write ; qLine_Curve, qLine_Structure, qLine_YAction, qLine_Fit, qLine_FitDraw, qLine_Sequence ; qLine_IsX, qLine_Skip, qLine_NewYAxis, IsTime, BadValue, IsType ; RESTRICTIONS: ; Currently up to 10 curves can be manipulated (this is set in qLine_Structure) ; PROCEDURE: ; The widget is set up as a no-blocking widget. After being registered wit XMANAGER ; an event is generated to bring up the first display. ; ; The state structure is defined as follows: ; ; state = {STATE_QPLOT, $ ; wid_top : 0L, $ base widget along top of widget ; QPLOT_STRUCTURE events send to this widget create the ; X-Base section of the widget (main draw widget+X-axis parameters) ; The event is then passed to the wid_xbase widget to create the ; Y-Base section ; user value: none ; Top section of widget: ; wid_done : 0L, $ 'Done' button widget ; user value: none ; wid_print : 0L, $ 'Print' button widget ; user value: none ; wid_read : 0L, $ button widget for reading binary file ; user value: none ; wid_write : 0L, $ button widget for writing binary file ; user value: none ; wid_xysize : [0L,0L], $ cw_fields for setting horizontal/vertical plot window size ; user value: none ; wid_margin : [0L,0L], $ cw_fields for setting left and right x-margin ; user value: none ; wid_chars : 0L, $ cw_field for setting character size ; user value: none ; wid_title : 0L, $ cw_field for setting main plot label ; ; ; X-Base section of widget: ; ; wid_xbase : 0L, $ base widget containing remaining widgets ; A QPLOT_STRUCTURE event to this widget creates the Y-Base section. ; user value: none ; wid_draw : 0L, $ main draw widget for displaying the curves ; user value: none ; wid_ymd : 0L, $ non-exclusive button for plotting of time-axis ; user value: current on/off status ; wid_ydoy : 0L, $ non-exclusive button for plotting of time axis ; user value: current on/off status ; wid_degree : 0L, cw_field widget setting degree of polynomial fit ; user value: two-element array specifying the x-range over which to fit ; wid_scalefit: 0L, $ cw_field widget setting scale factor for residuals from fit ; user value: none ; ; Y-Base section of widget: ; ; wid_ybase : 0L, $ base widget container for rest of Y-Base section ; ; wid_isx : lonarr(nmax), $ exclusive button group selecting variable for x-axis ; user value: current setting (only one button in the group ; is 'on'; all others are 'off') ; wid_sequence : lonarr(nmax), $ cw_field group, setting order in which to process curves ; user value: none ; wid_ymin : lonarr(nmax), $ cw_field group, setting minimum for plot range ; user value: none ; wid_ymax : lonarr(nmax), $ cw_field group, setting maximum for plot range ; user value: none ; wid_skip : lonarr(nmax), $ non-exclusive button group; selects curves to be plotted ; user value: current on/off status ; wid_newyaxis : lonarr(nmax), $ non-exclusive button group; selects curves to be plotted with ; separate y-axis ; user value: current on/off status ; wid_exact : lonarr(nmax), $ non-exclusive button group; decide wheter to use exact axis or not ; user value: current on/off status ; wid_ynozero : lonarr(nmax), $ non-exclusive button group; decide whether to use /ynozero keyword ; user value: current on/off status ; wid_ylog : lonarr(nmax), $ non-exclusive button group; decide whether to use logarithmic axis ; user value: current on/off status ; wid_use_sigma : lonarr(nmax), $ non-exclusive button group; decide on whether to plot vertical error bars ; user value: current on/off status ; wid_sigma_index : lonarr(nmax), $ cw_field group; curve index of the array with standard deviations ; user value: none ; wid_fit : lonarr(nmax), $ non-exclusive button group for activating polynomial fitting ; user value: current on/off status ; wid_linestyle : lonarr(nmax), $ cw_field group; decide on linestyle ; user value: none ; wid_ytitle : lonarr(nmax), $ cw_field group: titles for y-axis ; user value: none ; ; ; ; The remaining stores the curves in heap variables: ; ; nmax : nmax, $ maximum number of curves ; n : 0, $ number of curves ; y : ptr_new(/allocate_heap), $ y-axis values ; t : ptr_new(/allocate_heap), $ time axis ; plotstr : ptr_new(/allocate_heap) $ plot strings ; } ; MODIFICATION HISTORY: ; FEB-2000, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ;- PRO qLine_Event, event @compile_opt.pro ; On error, return to caller widget_control, event.top, get_uvalue=state, /no_copy CASE event.id OF ; ID of widget that generated the message event.top : qLine_Kill, state, event ; WIDGET_KILL_REQUEST from top level widget state.wid_done : qLine_Kill , state, event ; Message from 'Done' widget ; If the draw widget needs to be redrawn (e.g, when the window size is changed, ; this is done by sending an event to state.wid_top. qLine_XBase redraws the draw ; widget; then passes the event to the state_wid_xbase widget (see below). state.wid_top : BEGIN qLine_XBase, state widget_control, state.wid_xbase, send_event=event END ; If the draw widget is OK, but the curve (Y-base) widgets need to be updated ; (for instance when a new data file is read; see qLine_Read), this is done by ; sending an event to state.wid_xbase. After redrawing the widgets, the curves ; are redrawn. state.wid_xbase : BEGIN qLine_YBase, state, event qLine_Curve, state END state.wid_print : qLine_Print, state, event state.wid_read : qLine_Read , state state.wid_write : qLine_Write, state ; After a change of window size the whole widget needs to be redrawn state.wid_xysize[0] : widget_control, state.wid_top , send_event=qLine_Structure(state) state.wid_xysize[1] : widget_control, state.wid_top , send_event=qLine_Structure(state) state.wid_margin[0] : qLine_Curve, state ; Change x-margin[0] state.wid_margin[1] : qLine_Curve, state ; Change x-margin[1] state.wid_chars : qLine_Curve, state ; Change character size state.wid_title : qLine_Curve, state ; Change main plot title state.wid_draw : IF qLine_FitDraw(state, event) THEN qLine_Curve, state ; Change time state.wid_ymd : BEGIN widget_control, state.wid_ymd , set_uvalue=event.select widget_control, state.wid_ydoy , set_uvalue=0, set_button=0 widget_control, state.wid_degree, set_uvalue=replicate(BadValue(0.0),2) qLine_Curve, state END state.wid_ydoy : BEGIN widget_control, state.wid_ydoy , set_uvalue=event.select widget_control, state.wid_ymd , set_uvalue=0, set_button=0 widget_control, state.wid_degree, set_uvalue=replicate(BadValue(0.0),2) qLine_Curve, state END qLine_YAction(state.wid_sequence, event, iy): IF qLine_Sequence(state, iy) THEN qLine_Curve, state qLine_YAction(state.wid_isx , event, iy): IF qLine_IsX (state, event, iy) THEN qLine_Curve, state qLine_YAction(state.wid_skip, event, iy): IF qLine_Skip(state, event, iy) THEN qLine_Curve, state qLine_YAction(state.wid_fit , event, iy): IF qLine_Fit(state, event, iy) THEN qLine_Curve, state qLine_YAction(state.wid_newyaxis, event, iy): IF qLine_NewYAxis(state, event, iy) THEN qLine_Curve, state qLine_YAction(state.wid_ymin , event, iy): qLine_Curve, state qLine_YAction(state.wid_ymax , event, iy): qLine_Curve, state qLine_YAction(state.wid_exact , event, iy, /onoff): qLine_Curve, state qLine_YAction(state.wid_ynozero, event, iy, /onoff): qLine_Curve, state qLine_YAction(state.wid_ylog , event, iy, /onoff): qLine_Curve, state qLine_YAction(state.wid_use_sigma, event, iy, /onoff): qLine_Curve, state qLine_YAction(state.wid_sigma_index, event, iy): BEGIN widget_control, state.wid_sigma_index[iy], get_value=sigma_index widget_control, state.wid_use_sigma [iy], sensitive=sigma_index NE 0 qLine_Curve, state END qLine_YAction(state.wid_linestyle, event, iy): qLine_Curve, state qLine_YAction(state.wid_ytitle , event, iy): qLine_Curve, state ELSE: BEGIN print, 'qLine: unexpected event' print, tag_names(event, /structure_name) print, event END ENDCASE IF widget_info(event.top, /valid_id) THEN $ widget_control, event.top, set_uvalue=state, /no_copy RETURN & END PRO qLine, group=group, x, y, use_index=use_index, isx=isx, time=time, xysize=xysize, $ charsize = charsize , $ title = title , $ xmargin = xmargin , $ nmax = nmax , $ sequence = sequence , $ skip = skip , $ newyaxis = newyaxis , $ exact = exact , $ ynozero = ynozero , $ ylog = ylog , $ linestyle = linestyle , $ ytitle = ytitle , $ use_sigma = use_sigma , $ sigma_index = sigma_index, $ plotstr = plotstr , $ yrange = yrange @compile_opt.pro ; On error, return to caller InitVar, nmax, 10 InitVar, use_index, /key state = {STATE_QPLOT, $ wid_top : 0L, $ wid_done : 0L, $ wid_print : 0L, $ wid_read : 0L, $ wid_write : 0L, $ wid_xysize : [0L,0L], $ wid_margin : [0L,0L], $ wid_chars : 0L, $ wid_title : 0L, $ wid_ymd : 0L, $ wid_ydoy : 0L, $ wid_degree : 0L, $ wid_scalefit : 0L, $ wid_badvalue : 0L, $ wid_xbase : 0L, $ wid_ybase : 0L, $ wid_draw : 0L, $ wid_sequence : lonarr(nmax), $ wid_isx : lonarr(nmax), $ wid_ymin : lonarr(nmax), $ wid_ymax : lonarr(nmax), $ wid_skip : lonarr(nmax), $ wid_newyaxis : lonarr(nmax), $ wid_exact : lonarr(nmax), $ wid_ynozero : lonarr(nmax), $ wid_ylog : lonarr(nmax), $ wid_linestyle : lonarr(nmax), $ wid_ytitle : lonarr(nmax), $ wid_use_sigma : lonarr(nmax), $ wid_fit : lonarr(nmax), $ wid_sigma_index : lonarr(nmax), $ nmax : nmax, $ n : 0, $ y : ptr_new(/allocate_heap), $ t : ptr_new(/allocate_heap), $ plotstr : ptr_new(/allocate_heap) $ } IF IsTime(time) THEN (*state.t) = time IF IsType(plotstr, /defined) THEN (*state.plotstr) = plotstr InitVar, xysize , [600, 360] InitVar, xmargin , [ 10, 5] InitVar, charsize, 1.0 CASE IsType(x, /defined) OR use_index OF 0: n_curves = 0 1: BEGIN sz = size(x) n_points = sz[sz[0]] ; Last dimension of x n_curves = sz[sz[0]+2]/n_points yy = reform(x, n_curves, n_points) CASE use_index OF 0: IF IsType(y,/defined) THEN yy = [yy, reform(y, n_elements(y)/n_points, n_points)] 1: IF use_index THEN yy = [reform(lindgen(n_points),1,n_points),reform(x, n_elements(x)/n_points, n_points)] ENDCASE n_curves = n_elements(yy)/n_points *state.y = yy END ENDCASE InitVar, isx, 0 isx = (isx > 0) < (n_curves-1) state.n = n_curves base = widget_base(title='qLine', /column, /tlb_kill_request) state.wid_top = widget_base(base, /column) dummy = widget_base(state.wid_top, /row) state.wid_done = widget_button(dummy, value=filepath(root=getenv('SSW_SMEI_UCSD'),subdir='image','done.ico'),/bitmap) state.wid_print = widget_button(dummy, value='Print') state.wid_read = widget_button(dummy, value='Read') state.wid_write = widget_button(dummy, value='Write') state.wid_xysize[0] = cw_field(dummy, value=xysize[0], /integer, title='size', /row, xsize=3, /return_ev) state.wid_xysize[1] = cw_field(dummy, value=xysize[1], /integer, title='x' , /row, xsize=3, /return_ev) state.wid_margin[0] = cw_field(dummy, value=xmargin[0], /integer, title='margin', /row, xsize=3, /return_ev) state.wid_margin[1] = cw_field(dummy, value=xmargin[1], /integer, title='--', /row, xsize=3, /return_ev) state.wid_chars = cw_field(dummy, value=charsize, /float , title='charsize', /row, xsize=2 , /return_ev) state.wid_title = cw_field(dummy, value=title , /string, title='title' , /row, xsize=20, /return_ev) ; If curve data are available, then complete the widget before realizing it. IF n_curves NE 0 THEN BEGIN ; 'base' is the id of the base widget. This is used as the parent. ; 'xysize' is the size of the draw widget, and needs to be specified explicitly even though the values have ; already been stored in the value fields of state.wid_xysize (these values apparently become accessible only ; after the widget has been realized??) qLine_XBase, state, xysize=xysize ; Set up a structure with all information about the curves. ; The /noplot keyword suppresses a call to qLine_Curve (plotting can be done only after realizing the widget??) sequence = indgen(n_curves) ymin = fltarr(n_curves) FOR i=0,n_curves-1 DO ymin[i] = min(yy[i,*], /nan) ymax = fltarr(n_curves) FOR i=0,n_curves-1 DO ymax[i] = max(yy[i,*], /nan) IF IsType(yrange,/defined) THEN BEGIN n = n_elements(yrange)/2 ymin[0:n-1] = yrange[0,*] ymax[0:n-1] = yrange[1,*] ENDIF event = qLine_Structure(isx=isx, nmax=state.nmax, sequence=sequence, $ ymin=ymin, ymax=ymax, exact=exact, ynozero=ynozero, ylog=ylog, $ newyaxis=newyaxis, skip=skip, linestyle=linestyle, ytitle=ytitle, $ use_sigma=use_sigma, sigma_index=sigma_index) qLine_YBase, state, event ENDIF widget_control, base, set_uvalue=state, no_copy=n_curves EQ 0 widget_control, base, /realize ; Now that the widget is realized we can plot the curves IF n_curves NE 0 THEN qLine_Curve, state xmanager, 'qLine', base, group=Group, /no_block, event_handler='qLine_Event' RETURN & END