
;+
; NAME:
;     EIS_SPIKE_VIEWER
;
; PURPOSE:
;     This tool is for browsing EIS data arrays that have been cleaned of
;     cosmic ray hits. An EIS Software Note on cosmic rays and
;     residual warm pixels gives more details.
;
; CATEGORY:
;     Hinode; EIS; graphics.
;
; INPUTS:
;     ARR_IN    Either a 3D data array or a 'windata' structure. For
;               the former, it is assumed that the 1st dimension is 
;               wavelength, the 2nd is spatial-Y, and the 3rd
;               is spatial-X (exposures). Use the /swap_xy keyword if
;               the array has X and Y swapped. If the 'windata'
;               structure is input then the routine automatically
;               handles this input.
;
;     ARR_OUT   The cleaned version of ARR_IN.
;
;     SPIKES    An array of the same size as ARR_IN, containing 1's at the
;               locations of cosmic rays, and 0's otherwise.
;
; KEYWORD PARAMETERS:
;     SWAP_XY:  If set, then X and Y dimensions are swapped.
;
; OUTPUTS:
;     Creates a graphical user interface for browsing cosmic ray hits in
;     EIS data.
;
; EXAMPLE:
;     The recommended way of calling this routine is as follows. First
;     prep the level-0 file with the /nocr, /norwp and /noabs options:
;
;     IDL> eis_prep,l0name,/quiet,/save,/default,/retain,/nocr,/norwp,/noabs
;
;     Then load a data window with eis_getwindata (do not use /refill
;     option) and clean it:
;
;     IDL> wd=eis_getwindata(l1name,wvl)
;     IDL> wdout=eis_clean_windata(wd,swtch=swtch)
;
;     Then run eis_spike_viewer:
;
;     IDl> eis_spike_viewer,wd,wdout,swtch
; 
; INTERNAL ROUTINES:
;     PLOT_EXPOSURE, SPIKE_BASE_EVENT, SPIKE_WIDGET, SPIKE_PROFILE,
;     SPIKE_FONT, OPLOT_DIFF, SPIKE_DRAWBOX
;
; CALLS:
;     PLOT_IMAGE, GET_IJ
;
; MODIFICATION HISTORY:
;     Ver.1, 13-Jun-2007, Peter Young
;        modified from the original CDS routine (spike_viewer)
;     Ver.2, 29-Aug-2019, Peter Young
;        many updates!
;-


;------------------
PRO spike_font, font, big=big, fixed=fixed
;+
;  Defines the fonts to be used in the widgets. Allows for Windows and Unix 
;  operating systems.
;-
CASE !version.os_family OF

  'unix': BEGIN
    IF keyword_set(fixed) THEN fstr='-*-courier-' ELSE $
         fstr='-adobe-helvetica-'
    IF keyword_set(big) THEN str='18' ELSE str='12'
    font=fstr+'bold-r-*-*-'+str+'-*'
  END

  ELSE: BEGIN
    IF keyword_set(fixed) THEN fstr='Courier' ELSE $
         fstr='Arial'
    IF keyword_set(big) THEN str='20' ELSE str='16'
    font=fstr+'*bold*'+str
  END

ENDCASE

END


;-------------
PRO oplot_diff, state, point, lamb=lamb, exp=exp, yy=yy

in=state.data.in
out=state.data.out

l1=point[0]
l2=point[1]
l3=point[2]

CASE 1 OF
  keyword_set(lamb): BEGIN
    y1=reform(in[*,l2,l3])
    y2=reform(out[*,l2,l3])
  END
  keyword_set(exp): BEGIN
    y1=reform(in[l1,*,l3])
    y2=reform(out[l1,*,l3])
  END
  keyword_set(yy): BEGIN
    y1=reform(in[l1,l2,*])
    y2=reform(out[l1,l2,*])
  END
  ELSE:
ENDCASE

n=n_elements(y1)
FOR i=0,n-1 DO BEGIN
  IF y1[i] NE y2[i] THEN BEGIN
    x=[i-.5,i+.5]
    y=[!y.crange[0],y1[i]]
    polyfill,[x[0],x[1],x[1],x[0]],[y[0],y[0],y[1],y[1]]
  ENDIF
ENDFOR

END


;-----------------------------------------------------
PRO spike_profile, state, wid=wid, event=event

IF n_elements(event) NE 0 THEN BEGIN 
  wset,wid

  x=event.x
  y=event.y
  result=convert_coord(x,y,/device,/to_data)
  x=result[0]
  y=result[1]
  IF x GE !x.crange[0] AND x LE !x.crange[1] AND y GE !y.crange[0] AND y LE !y.crange[1] AND event.release EQ 1 THEN BEGIN
    state.wid_data.x=round(x)
    state.wid_data.y=round(y)
    widget_control,state.spike_base,set_uval=state
  ENDIF ELSE BEGIN
    return
  ENDELSE
ENDIF

x=state.wid_data.x
y=state.wid_data.y

n=state.wid_data.n
IF state.wid_data.exp_img EQ 0 THEN BEGIN
  l1=x
  l2=n
  l3=y
ENDIF ELSE BEGIN
  l1=n
  l2=x
  l3=y
ENDELSE

siz=size(state.data.in,/dim)


;
; Plot along the wavelength direction
;
wset,state.wid_data.lamb_id
IF state.wid_data.exp_img EQ 0 THEN BEGIN
  xrange=state.wid_data.xrange
ENDIF ELSE BEGIN
  n=state.wid_data.n
  xrange=[max([n-16,0]),min([n+16,siz[0]-1])]
  state.wid_data.zrange=xrange
ENDELSE
 ;
usersym,[-1,1,1,-1,-1],[-1,-1,1,1,-1],/fill
 ;
plot,state.data.in[*,l2,l3]>0,psym=10,tit='WAVELENGTH',xrange=xrange, $
     xtitle='Pixel', ytitle='Intensity / DN',xsty=1, $
     xticklen=-0.015
oplot_diff,state,[l1,l2,l3],lamb=1
plots,l1,state.data.in[l1,l2,l3],psym=8,col=127

;
; Plot along the exposure direction.
;
wset,state.wid_data.x_id
IF state.wid_data.exp_img EQ 1 THEN BEGIN
  xrange=state.wid_data.xrange
ENDIF ELSE BEGIN
  n=state.wid_data.n
  xrange=[max([n-16,0]),min([n+16,siz[2]-1])]
  state.wid_data.zrange=xrange
ENDELSE
plot,state.data.in[l1,*,l3]>0,psym=10,tit='EXPOSURE',xrange=xrange, $
     xtitle='Pixel', ytitle='Intensity / DN',xsty=1, $
     xticklen=-0.015
oplot_diff,state,[l1,l2,l3],exp=1
plots,l2,state.data.in[l1,l2,l3],psym=8,col=127

;
; Plot along the Y-direction
;
wset,state.wid_data.y_id
plot,state.data.in[l1,l2,*]>0,psym=10,tit='Y',xrange=state.wid_data.yrange, $
     xtitle='Pixel', ytitle='Intensity / DN',xsty=1, $
     xticklen=-0.015
oplot_diff,state,[l1,l2,l3],yy=1
plots,l3,state.data.in[l1,l2,l3],psym=8,col=127

plot_exposure,state,point=[x,y]
widget_control,state.spike_base,set_uval=state

END



;-----------------------------------
PRO spike_drawbox, event, state, wid

s=size(state.data.in,/dim)
ny=s[2]
IF state.wid_data.exp_img EQ 1 THEN nx=s[1] ELSE nx=s[0]

CASE 1 OF
  event.press EQ 1 AND state.box.flag EQ 0: BEGIN
    state.box.flag=1
    state.box.x0=event.x
    state.box.y0=event.y
    state.box.wid=wid
    wset,wid
    Window, /Pixmap, /Free, XSize=state.box.xsiz, YSize=state.box.ysiz
    state.box.pixid = !D.Window
    Device, Copy=[0, 0, state.box.xsiz, state.box.ysiz, 0, 0, wid]
    wset,wid
    widget_control,state.spike_base,set_uvalue=state
  END

  event.release EQ 1 AND state.box.flag EQ 1: BEGIN
    WDelete, state.box.pixid
    state.box.flag=0
    state.box.x1=event.x
    state.box.y1=event.y
    widget_control,state.spike_base,set_uvalue=state
    result=convert_coord([state.box.x0,state.box.x1], $
                         [state.box.y0,state.box.y1],/device,/to_data)
    result=fix(result)
    xra=[result[0,0],result[0,1]]
    xra=xra[sort(xra)]>0 < (nx-1)
    yra=[result[1,0],result[1,1]]
    yra=yra[sort(yra)] > 0 < (ny-1)
    IF xra[0] NE xra[1] AND yra[0] NE yra[1] THEN BEGIN
      state.wid_data.xrange=xra
      state.wid_data.yrange=yra
      widget_control,state.spike_base,set_uvalue=state
    ENDIF
    plot_exposure,state,over=over
    spike_profile,state
  END

  state.box.flag EQ 1: BEGIN
    Device, Copy=[0, 0, state.box.xsiz, state.box.ysiz, 0, 0, state.box.pixid]
    PlotS, [state.box.x0, state.box.x0, event.x, event.x, state.box.x0], $
         [state.box.y0, event.y, event.y, state.box.y0, state.box.y0], $
         /Device
  END
  
  ELSE:
  
ENDCASE

END


;----------------
PRO plot_exposure, state, over=over, reset=reset, point=point

;+
;  RESET   Sets the XRANGE and YRANGE of the image plots to their full
;          size.
;  POINT   Plots a symbol for the selected pixel.
;-

data=state.data
wid_data=state.wid_data
n=state.wid_data.n

IF wid_data.exp_img EQ 0 THEN BEGIN
  spike=reform(data.spike[*,n,*])
  in=reform(data.in[*,n,*])
  out=reform(data.out[*,n,*])
  IF n_elements(data.comp) GT 1 THEN spike=spike+reform(data.comp[*,n,*])
  xtitle='Wavelength pixel'
  ytitle='Y pixel'
ENDIF ELSE BEGIN
  spike=reform(data.spike[n,*,*])
  in=reform(data.in[n,*,*])
  out=reform(data.out[n,*,*])
  IF n_elements(data.comp) GT 1 THEN spike=spike+reform(data.comp[n,*,*])
  xtitle='Exposure pixel'
  ytitle='Y pixel'
ENDELSE


siz=size(in)
IF keyword_set(reset) THEN BEGIN
  xrange=[0,siz[1]-1]
  yrange=[0,siz[2]-1]
  state.wid_data.xrange=xrange
  state.wid_data.yrange=yrange
  widget_control,state.spike_base,set_uval=state
ENDIF ELSE BEGIN
  xrange=wid_data.xrange
  yrange=wid_data.yrange
  IF xrange[0] LT 0 THEN xrange[0]=0
  IF xrange[1] GT siz[1]-1 THEN xrange[1]=siz[1]-1
  IF yrange[0] LT 0 THEN yrange[0]=0
  IF yrange[1] GT siz[2]-1 THEN yrange[1]=siz[2]-1
ENDELSE

orig=[xrange[0],yrange[0]]

in=in[xrange[0]:xrange[1],yrange[0]:yrange[1]]
out=out[xrange[0]:xrange[1],yrange[0]:yrange[1]]
spike=spike[xrange[0]:xrange[1],yrange[0]:yrange[1]]

IF keyword_set(over) THEN BEGIN
  ind=where(spike EQ 1)
  IF ind[0] NE -1 THEN BEGIN
    siz=size(spike)
    ij=get_ij(ind,siz[1])
  ENDIF
ENDIF

xtl=-0.02
ytl=-0.02

IF wid_data.autoint EQ 1 THEN BEGIN
  max_value=max(in)
  state.wid_data.maxint=max_value
  widget_control,state.max_text,set_value=trim(max_value)
ENDIF ELSE BEGIN
  max_value=wid_data.maxint
ENDELSE 

wset,wid_data.in_id
plot_image,in>0,xticklen=xtl,yticklen=ytl,orig=orig, $
           title='Original', xtitle=xtitle, ytitle=ytitle, $
           charsiz=1.2,max=max_value
IF keyword_set(over) THEN oplot,ij[0,*],ij[0,*],psym=2
IF n_elements(point) NE 0 THEN BEGIN
  plots,point[0],point[1],psym=1,symsize=2
  plots,point[0],point[1],psym=7,symsize=2,color=0
ENDIF 
;
wset,wid_data.out_id
IF wid_data.autoint EQ 1 THEN max_value=max(out)
plot_image,out>0,xticklen=xtl,yticklen=ytl,orig=orig, $
           title='De-spiked', xtitle=xtitle, ytitle=ytitle, $
           charsiz=1.2,max=max_value
IF keyword_set(over) THEN oplot,ij[0,*],ij[0,*],psym=2
IF n_elements(point) NE 0 THEN BEGIN
  plots,point[0],point[1],psym=1,symsize=2
  plots,point[0],point[1],psym=7,symsize=2,color=0
ENDIF 
;
wset,wid_data.spike_id
plot_image,spike,xticklen=xtl,yticklen=ytl,orig=orig,max=2, $
           title='Spike locations', xtitle=xtitle, ytitle=ytitle, $
           charsiz=1.2
IF n_elements(point) NE 0 THEN BEGIN
  plots,point[0],point[1],psym=1,symsize=2
  plots,point[0],point[1],psym=7,symsize=2,color=0
ENDIF 

END

;------------------------------------
PRO spike_base_event, event

WIDGET_CONTROL,Event.top, get_uvalue=state


CASE event.id OF

  state.exp_img: BEGIN
    widget_control,state.exp_img,get_val=val
    IF val NE state.wid_data.exp_img THEN BEGIN 
      state.wid_data.exp_img=val
      widget_control,state.spike_base,set_uval=state
      n=state.wid_data.n
      x=state.wid_data.x
      y=state.wid_data.y
      siz=size(state.data.in,/dim)
      IF val EQ 1 THEN BEGIN   ; plot X-Y
        widget_control,state.n_slider,set_slider_max=siz[0]-1,set_value=x
      ENDIF ELSE BEGIN
        widget_control,state.n_slider,set_slider_max=siz[1]-1,set_value=x
      ENDELSE
      zra=state.wid_data.zrange
      xra=state.wid_data.xrange
      state.wid_data.xrange=zra
      state.wid_data.zrange=xra
     ;
      state.wid_data.x=n
      state.wid_data.n=x
     ;
;      widget_control,state.n_slider,get_value=val
;      state.wid_data.n=val
      options=['Exposure number','Wavelength pixel']
      widget_control,state.slider_title,set_value=options[val]
      widget_control,state.spike_base,set_uval=state
      plot_exposure,state,over=over,reset=reset
      spike_profile, state
    ENDIF 
  END

  state.zoom_pix: BEGIN
    widget_control,state.zoom_pix,get_val=val
    state.wid_data.zm_pix=val
    widget_control,state.spike_base,set_uval=state
    IF val EQ 1 THEN BEGIN
      widget_control,state.in_plot,draw_motion_events=0
      widget_control,state.out_plot,draw_motion_events=0
      widget_control,state.spike_plot,draw_motion_events=0
    ENDIF ELSE BEGIN
      widget_control,state.in_plot,draw_motion_events=1
      widget_control,state.out_plot,draw_motion_events=1
      widget_control,state.spike_plot,draw_motion_events=1
    ENDELSE
  END

;
; MANUAL INTENSITY SCALING OF IMAGES - MAXIMUM VALUE
; --------------------------------------------------
  state.max_text: BEGIN
    state.wid_data.autoint=0
    widget_control,state.max_text,get_value=value
    state.wid_data.maxint=value
    widget_control,state.spike_base,set_uvalue=state
    spike_profile,state
  END 


;
; AUTOMATIC INTENSITY SCALING OF IMAGES
; -------------------------------------
  state.auto_int: BEGIN
    state.wid_data.autoint=1
    widget_control,state.spike_base,set_uvalue=state
    spike_profile,state
  END 
  
  state.n_slider: BEGIN
    widget_control,state.n_slider,get_val=val
    state.wid_data.n=val
    state.wid_data.zm_pix=0
    widget_control,state.spike_base,set_uval=state
    spike_profile, state
  END

  state.slid_butts: BEGIN
    CASE event.value OF
      0: BEGIN
        widget_control,state.n_slider,get_val=val
        IF val NE 0 THEN BEGIN
          state.wid_data.n=val-1
          widget_control,state.spike_base,set_uval=state
          widget_control,state.n_slider,set_val=val-1
          plot_exposure,state,over=over
          spike_profile, state
        ENDIF
      END
      1: BEGIN 
        widget_control,state.n_slider,get_val=val
        siz=size(state.data.in)
        IF state.wid_data.exp_img EQ 0 THEN chck=siz[2]-1 ELSE chck=siz[1]-1
        IF val NE chck THEN BEGIN
          state.wid_data.n=val+1
          widget_control,state.spike_base,set_uval=state
          widget_control,state.n_slider,set_val=val+1
          plot_exposure,state,over=over
          spike_profile, state
        ENDIF
      END
      2:
      3: BEGIN
        siz=size(state.data.in)
        IF state.wid_data.exp_img EQ 0 THEN chck=siz[2]-1 ELSE chck=siz[1]-1
        widget_control,state.n_slider,get_val=val
        FOR i=val+1,chck DO BEGIN
          wait,0.3
          state.wid_data.n=i
          widget_control,state.spike_base,set_uval=state
          widget_control,state.n_slider,set_val=i
          plot_exposure,state,over=over
          spike_profile, state
         ENDFOR
      END
    ENDCASE
  END

  state.in_plot: BEGIN
    IF state.wid_data.zm_pix EQ 0 THEN BEGIN
      spike_drawbox, event, state, state.wid_data.in_id
    ENDIF ELSE BEGIN
      spike_profile, state, event=event, wid=state.wid_data.in_id
    ENDELSE
  END

  state.out_plot: BEGIN
    IF state.wid_data.zm_pix EQ 0 THEN BEGIN
      spike_drawbox, event, state, state.wid_data.out_id
    ENDIF ELSE BEGIN
      spike_profile, state, event=event, wid=state.wid_data.in_id
    ENDELSE
  END

  state.spike_plot: BEGIN
    IF state.wid_data.zm_pix EQ 0 THEN BEGIN
      spike_drawbox, event, state, state.wid_data.spike_id
    ENDIF ELSE BEGIN
      spike_profile, state, event=event, wid=state.wid_data.in_id
    ENDELSE
  END

  state.butts: BEGIN
    CASE event.value OF

      0: BEGIN
        plot_exposure,state,/reset
        spike_profile, state
      END 

      1: widget_control, event.top, /destroy
    ENDCASE
  END

ENDCASE

END


PRO spike_widget, data, group=group

;
; "zrange" is the range for the 3rd dimension. Initially X and Y are
; wavelength and Y, and so Z is exposure number. If the user wants to
; plot X-Y images, then Z becomes wavelength.
; 
siz=size(data.in)
xrange=[0,siz[1]-1]
yrange=[0,siz[3]-1]
zrange=[0,siz[2]-1]
x=round(mean(xrange))
y=round(mean(yrange))

spike_font,font
spike_font,bigfont,/big
spike_font,fixfont,/fixed

wid_data={in_id: 0, out_id: 0, spike_id: 0, x_id: 0, y_id: 0, lamb_id:0, $
          exp_img: 0, over: 0, n: 0, x: x, y: y, zm_pix: 0, $
          xrange: xrange, yrange: yrange, zrange: zrange, $
          autoint: 1, $
          maxint: -1. }

spike_base=widget_base(/col,map=1,title='SPIKE_VIEWER')

row_base=widget_base(spike_base,/row,map=1)

exp_img=cw_bgroup(row_base,/exclusive,['Exposure','Image'], $
                  set_value=wid_data.exp_img,/row,/frame,font=font)

zoom_pix=cw_bgroup(row_base,/exclusive,['Zoom','Pixel'], $
                  set_value=wid_data.zm_pix,/row,/frame,font=font)

max_lbl=widget_label(row_base,value='Max intensity:',font=font)
max_text=widget_text(row_base,value=trim(0.), $
                        font=font,xsiz=7,/editable)
auto_int=widget_button(row_base,value='Auto',font=font)

butts=cw_bgroup(row_base,['UNZOOM','EXIT'],/row,font=bigfont)

siz=size(data.in)
slid_base1=widget_base(spike_base,/row)
slid_base2=widget_base(slid_base1,/col)
n_slider=widget_slider(slid_base2,min=0,max=siz[2]-1, $
                       font=font,xsiz=300)
slider_title=widget_label(slid_base2,font=font,value='Exposure number')
slid_butts=cw_bgroup(slid_base1,['<','>','[]','Step'],font=bigfont,/row)

xsiz=400
ysiz=450
;
plot_base1=widget_base(spike_base,/row)
in_plot=widget_draw(plot_base1,xsiz=xsiz,ysiz=ysiz,/sens, $
                    /motion_events,/button_events)
out_plot=widget_draw(plot_base1,xsiz=xsiz,ysiz=ysiz,/sens, $
                    /motion_events,/button_events)
spike_plot=widget_draw(plot_base1,xsiz=xsiz,ysiz=ysiz,/sens, $
                    /motion_events,/button_events)
;
plot_base2=widget_base(spike_base,/row)
lamb_plot=widget_draw(plot_base2,xsiz=xsiz,ysiz=ysiz)
x_plot=widget_draw(plot_base2,xsiz=xsiz,ysiz=ysiz)
y_plot=widget_draw(plot_base2,xsiz=xsiz,ysiz=ysiz)


box={flag: 0, wid: 0, x0: 0, y0: 0, x1:0, y1:0, $
     xsiz:xsiz, ysiz: ysiz, pixid:0}

state={data: data, wid_data: wid_data,box:box, $
       spike_base:spike_base, $
       in_plot: in_plot, out_plot: out_plot, spike_plot: spike_plot, $
       butts: butts, exp_img:exp_img, n_slider:n_slider, $
       zoom_pix: zoom_pix, slid_butts: slid_butts, $
       max_text: max_text, $
       auto_int: auto_int, $
       slider_title: slider_title}

WIDGET_CONTROL, spike_base, /REALIZE, set_uvalue=state

WIDGET_CONTROL, in_plot, GET_VALUE=in_plot_id
WIDGET_CONTROL, out_plot, GET_VALUE=out_plot_id
WIDGET_CONTROL, spike_plot, GET_VALUE=spike_plot_id
WIDGET_CONTROL, x_plot, GET_VALUE=x_plot_id
WIDGET_CONTROL, y_plot, GET_VALUE=y_plot_id
WIDGET_CONTROL, lamb_plot, GET_VALUE=lamb_plot_id
;
wid_data.in_id=in_plot_id
wid_data.out_id=out_plot_id
wid_data.spike_id=spike_plot_id
wid_data.x_id=x_plot_id
wid_data.y_id=y_plot_id
wid_data.lamb_id=lamb_plot_id

state.wid_data=wid_data
widget_control,spike_base,set_uvalue=state

plot_exposure, state
spike_profile, state


XMANAGER, 'spike_base', spike_base, group=group

END



PRO eis_spike_viewer, A_IN, A_OUT, A_SPIKES, COMPSPIKE=COMPSPIKE, swap_xy=swap_xy

IF n_params() EQ 0 THEN BEGIN
  print,'Use: IDL> spike_viewer, arr_in, arr_out, spikes, compspike='
  return
ENDIF

;
; It's often convenient to input a WINDATA structure instead of
; a 3D array (see the eis_clean_windata routine). The following checks
; if A_IN and A_OUT are structures. 
;
; The /SWAP_XY keyword is a little confusing. The routine was modified
; from an earlier version for CDS for which the arrays are
; WVL*X*Y. When you extract arrays from the data object for EIS, they
; are WVL*Y*X format. By default I assume the user is giving these
; latter arrays, and then I swap X and Y (using transpose) so that I
; can re-use the CDS code. When the user gives /swap_xy it tells the
; routine that the arrays are in WVL*X*Y format. Thus I don't
; have to use transpose. Note that WINDATA arrays are in
; the WVL*X*Y format so I set swap_xy=1, which prevents the A_SPIKES
; input from being transposed.
;
IF n_tags(a_in) NE 0 THEN BEGIN
  IF n_tags(a_out) EQ 0 THEN BEGIN
    print,'% EIS_SPIKE_VIEWER: The input A_IN seems to be a windata structure, but A_OUT is not. '
    print,'                    Both inputs should be either structures or arrays. Returning...'
    return
  ENDIF 
  arr_in=a_in.int
  err_in=a_in.err
  k=where(err_in EQ a_in.missing,nk)
  IF nk NE 0 THEN arr_in[k]=a_in.missing
  swap_xy=1   ; this means 'spikes' is assumed to be WVL*X*Y format
ENDIF ELSE BEGIN
  arr_in=a_in
  IF NOT keyword_set(swap_xy) THEN arr_in=transpose(a_in,[0,2,1])
ENDELSE 
;
IF n_tags(a_out) NE 0 THEN BEGIN
  arr_out=a_out.int
  err_out=a_out.err
  k=where(err_out EQ a_out.missing,nk)
  IF nk NE 0 THEN arr_out[k]=a_out.missing
  arr_out=transpose(arr_out,[0,2,1])
  arr_out=transpose(arr_out,[0,2,1])
ENDIF ELSE BEGIN
  arr_out=a_out
  IF NOT keyword_set(swap_xy) THEN arr_out=transpose(a_out,[0,2,1])
ENDELSE 

IF NOT keyword_set(swap_xy) THEN BEGIN 
  spikes=transpose(a_spikes,[0,2,1])
ENDIF ELSE BEGIN
  spikes=a_spikes
ENDELSE


siz=size(spikes)
siz2=size(compspike)

IF total(siz2) NE total(siz) THEN BEGIN
  data={in: arr_in, out: arr_out, spike: spikes, comp: 0}
ENDIF ELSE BEGIN
  data={in: arr_in, out: arr_out, spike: spikes, comp: compspike}
ENDELSE

spike_widget,data


END
