def make_mask_figures(self):
        #  self.ops_plot[1] = 0
        #   self.ops_plot[2] = 0
        self.ops_plot[3] = []
        self.ops_plot[4] = []
        self.ops_plot[5] = []
        self.ops_plot[6] = []

        ncells = len(self.stat)
        for n in range(0, ncells):
            ypix = self.stat[n]["ypix"].flatten()
            xpix = self.stat[n]["xpix"].flatten()
            iext = fig.boundary(ypix, xpix)
            self.stat[n]["yext"] = ypix[iext]
            self.stat[n]["xext"] = xpix[iext]
            ycirc, xcirc = fig.circle(self.stat[n]["med"],
                                      self.stat[n]["radius"])
            goodi = ((ycirc >= 0)
                     & (xcirc >= 0)
                     & (ycirc < self.ops["Ly"])
                     & (xcirc < self.ops["Lx"]))
            self.stat[n]["ycirc"] = ycirc[goodi]
            self.stat[n]["xcirc"] = xcirc[goodi]


#         # make color arrays for various views
        fig.make_colors(self)
        #         # colorbar
        self.colormat = fig.make_colorbar()
        self.init_all_masks()
示例#2
0
 def make_masks_and_buttons(self):
     self.loadBeh.setEnabled(True)
     self.bloaded = False
     self.ROI_remove()
     self.isROI = False
     self.ops_plot[1] = 0
     self.ops_plot[2] = 0
     self.ops_plot[3] = []
     self.ops_plot[4] = []
     self.setWindowTitle(self.fname)
     # set bin size to be 0.5s by default
     self.bin = int(self.ops['tau'] * self.ops['fs'] / 2)
     self.binedit.setText(str(self.bin))
     # add boundaries to stat for ROI overlays
     ncells = len(self.stat)
     for n in range(0, ncells):
         ypix = self.stat[n]['ypix'].flatten()
         xpix = self.stat[n]['xpix'].flatten()
         iext = fig.boundary(ypix, xpix)
         self.stat[n]['yext'] = ypix[iext]
         self.stat[n]['xext'] = xpix[iext]
         ycirc, xcirc = fig.circle(self.stat[n]['med'],
                                   self.stat[n]['radius'])
         goodi = (ycirc >= 0) & (xcirc >= 0) & (ycirc < self.ops['Ly']) & (
             xcirc < self.ops['Lx'])
         self.stat[n]['ycirc'] = ycirc[goodi]
         self.stat[n]['xcirc'] = xcirc[goodi]
     # enable buttons
     self.enable_views_and_classifier()
     # make color arrays for various views
     fig.make_colors(self)
     self.ichosen = int(0)
     self.imerge = [int(0)]
     self.iflip = int(0)
     self.ichosen_stats()
     self.comboBox.setCurrentIndex(2)
     # colorbar
     self.colormat = fig.make_colorbar()
     fig.plot_colorbar(self, self.ops_plot[2])
     tic = time.time()
     fig.init_masks(self)
     print(time.time() - tic)
     M = fig.draw_masks(self)
     fig.plot_masks(self, M)
     self.lcell1.setText('%d' % (ncells - self.iscell.sum()))
     self.lcell0.setText('%d' % (self.iscell.sum()))
     fig.init_range(self)
     fig.plot_trace(self)
     if (type(self.ops['diameter'])
             is not int) and (len(self.ops['diameter']) > 1):
         self.xyrat = self.ops['diameter'][0] / self.ops['diameter'][1]
     else:
         self.xyrat = 1.0
     self.p1.setAspectLocked(lock=True, ratio=self.xyrat)
     self.p2.setAspectLocked(lock=True, ratio=self.xyrat)
     self.loaded = True
     self.mode_change(2)
     self.show()
     # no classifier loaded
     classifier.activate(self, False)
示例#3
0
    def openFile(self, fileName, fromgui):
        try:
            ops = np.load(fileName, allow_pickle=True).item()
            self.LY = 0
            self.LX = 0
            self.Ly = ops['Ly']
            self.Lx = ops['Lx']
            if os.path.isfile(ops['reg_file']):
                self.reg_loc = ops['reg_file']
                self.reg_file = open(self.reg_loc, 'rb')
                self.reg_file.close()
            else:
                self.reg_loc = os.path.join(os.path.dirname(fileName),
                                            'data.bin')
                self.reg_file = open(self.reg_loc, 'rb')
                self.reg_file.close()
            if not fromgui:
                if os.path.isfile(
                        os.path.join(os.path.dirname(fileName), 'F.npy')):
                    self.Fcell = np.load(
                        os.path.join(os.path.dirname(fileName), 'F.npy'))
                    self.stat = np.load(
                        os.path.join(os.path.dirname(fileName), 'stat.npy'))
                    self.Floaded = True
                else:
                    self.Floaded = False
            if self.Floaded:
                ncells = len(self.stat)
                for n in range(0, ncells):
                    ypix = self.stat[n]['ypix'].flatten()
                    xpix = self.stat[n]['xpix'].flatten()
                    iext = fig.boundary(ypix, xpix)
                    yext = ypix[iext]
                    xext = xpix[iext]
                    #yext = np.hstack((yext,yext+1,yext+1,yext-1,yext-1))
                    #xext = np.hstack((xext,xext+1,xext-1,xext+1,xext-1))
                    goodi = (yext >= 0) & (xext >= 0) & (yext < self.Ly) & (
                        xext < self.Lx)
                    self.stat[n]['yext'] = yext[goodi]
                    self.stat[n]['xext'] = xext[goodi]
            good = True
        except Exception as e:
            print(
                "ERROR: ops.npy incorrect / missing ops['reg_file'] and others"
            )
            print(e)
            good = False
        if good:
            self.p1.clear()
            self.p2.clear()
            self.ichosen = 0
            self.ROIedit.setText('0')
            # get scaling from 100 random frames
            frames = subsample_frames(ops, np.minimum(ops['nframes'] - 1, 100),
                                      self.reg_loc)
            self.srange = frames.mean() + frames.std() * np.array([-2, 5])
            #self.srange = [np.percentile(frames.flatten(),8), np.percentile(frames.flatten(),99)]
            self.reg_file = open(self.reg_loc, 'rb')
            self.wraw = False
            self.wred = False
            self.wraw_wred = False
            if 'reg_file_raw' in ops or 'raw_file' in ops:
                if self.reg_loc == ops['reg_file']:
                    if 'reg_file_raw' in ops:
                        self.reg_loc_raw = ops['reg_file_raw']
                    else:
                        self.reg_loc_raw = ops['raw_file']
                else:
                    self.reg_loc_raw = os.path.join(os.path.dirname(fileName),
                                                    'data_raw.bin')
                self.reg_file_raw = open(self.reg_loc_raw, 'rb')
                self.wraw = True

            if 'reg_file_chan2' in ops:
                if self.reg_loc == ops['reg_file']:
                    self.reg_loc_red = ops['reg_file_chan2']
                else:
                    self.reg_loc_red = os.path.join(os.path.dirname(fileName),
                                                    'data_chan2.bin')
                self.reg_file_chan2 = open(self.reg_loc_red, 'rb')
                self.wred = True
            if 'reg_file_raw_chan2' in ops or 'raw_file_chan2' in ops:
                if self.reg_loc == ops['reg_file']:
                    if 'reg_file_raw_chan2' in ops:
                        self.reg_loc_raw_chan2 = ops['reg_file_raw_chan2']
                    else:
                        self.reg_loc_raw_chan2 = ops['raw_file_chan2']
                else:
                    self.reg_loc_raw_chan2 = os.path.join(
                        os.path.dirname(fileName), 'data_raw_chan2.bin')
                self.reg_file_raw_chan2 = open(self.reg_loc_raw_chan2, 'rb')
                self.wraw_wred = True
            self.movieLabel.setText(self.reg_loc)
            self.nbytesread = 2 * self.Ly * self.Lx

            #aspect ratio
            if 'aspect' in ops:
                self.xyrat = ops['aspect']
            elif 'diameter' in ops and (type(ops["diameter"]) is not int) and (
                    len(ops["diameter"]) > 1):
                self.xyrat = ops["diameter"][0] / ops["diameter"][1]
            else:
                self.xyrat = 1.0
            self.p0.setAspectLocked(lock=True, ratio=self.xyrat)

            self.nframes = ops['nframes']
            self.time_step = 1. / ops['fs'] * 1000 / 5  # 5x real-time
            self.frameDelta = int(np.maximum(5, self.nframes / 200))
            self.frameSlider.setSingleStep(self.frameDelta)
            self.currentMovieDirectory = QtCore.QFileInfo(fileName).path()
            if self.nframes > 0:
                self.updateFrameSlider()
                self.updateButtons()
            # plot ops X-Y offsets
            if 'yoff' in ops:
                self.yoff = ops['yoff']
                self.xoff = ops['xoff']
            else:
                self.yoff = np.zeros((ops['nframes'], ))
                self.xoff = np.zeros((ops['nframes'], ))
            self.p1.plot(self.yoff, pen='g')
            self.p1.plot(self.xoff, pen='y')
            self.p1.setRange(xRange=(0, self.nframes),
                             yRange=(np.minimum(self.yoff.min(),
                                                self.xoff.min()),
                                     np.maximum(self.yoff.max(),
                                                self.xoff.max())),
                             padding=0.0)
            self.p1.setLimits(xMin=0, xMax=self.nframes)
            self.scatter1 = pg.ScatterPlotItem()
            self.p1.addItem(self.scatter1)
            self.scatter1.setData(
                [self.cframe, self.cframe],
                [self.yoff[self.cframe], self.xoff[self.cframe]],
                size=10,
                brush=pg.mkBrush(255, 0, 0))
            if self.Floaded:
                self.cell_mask()
                self.ft = self.Fcell[self.ichosen, :]
                self.p2.plot(self.ft, pen='b')
                self.p2.setRange(xRange=(0, self.nframes),
                                 yRange=(self.ft.min(), self.ft.max()),
                                 padding=0.0)
                self.p2.setLimits(xMin=0, xMax=self.nframes)
                self.scatter2 = pg.ScatterPlotItem()
                self.p2.addItem(self.scatter2)
                self.scatter2.setData([self.cframe], [self.ft[self.cframe]],
                                      size=10,
                                      brush=pg.mkBrush(255, 0, 0))
                self.p2.setXLink('plot1')
            self.cframe = -1
            self.loaded = True
            self.next_frame()
示例#4
0
    def openCombined(self, fileName):
        try:
            ops1 = np.load(fileName, allow_pickle=True)
            basefolder = ops1[0]['save_path0']
            #opsCombined = np.load(os.path.join(basefolder, 'suite2p/combined/ops.npy'), allow_pickle=True).item()
            #self.LY = opsCombined['Ly']
            #self.LX = opsCombined['Lx']
            self.LY = 0
            self.LX = 0
            self.reg_loc = []
            self.reg_file = []
            self.Ly = []
            self.Lx = []
            self.dy = []
            self.dx = []
            self.yrange = []
            self.xrange = []
            self.ycrop = []
            self.xcrop = []
            # check that all binaries still exist
            for ipl, ops in enumerate(ops1):
                #if os.path.isfile(ops['reg_file']):
                if os.path.isfile(ops['reg_file']):
                    reg_file = ops['reg_file']
                else:
                    reg_file = os.path.join(os.path.dirname(fileName),
                                            'plane%d' % ipl, 'data.bin')
                print(reg_file, os.path.isfile(reg_file))
                self.reg_loc.append(reg_file)
                self.reg_file = open(self.reg_loc[-1], 'rb')
                self.reg_file.close()
                self.Ly.append(ops['Ly'])
                self.Lx.append(ops['Lx'])
                self.dy.append(ops['dy'])
                self.dx.append(ops['dx'])
                self.xrange.append(
                    np.arange(self.dx[-1], self.dx[-1] + self.Lx[-1], 1, int))
                self.yrange.append(
                    np.arange(self.dy[-1], self.dy[-1] + self.Ly[-1], 1, int))
                xrange = ops['xrange']
                yrange = ops['yrange']
                xcrop = np.zeros((ops['Lx'], ), dtype=np.bool)
                xcrop[np.arange(xrange[0], xrange[1], 1, int)] = True
                self.xcrop.append(xcrop.nonzero()[0])
                ycrop = np.zeros((ops['Ly'], ), dtype=np.bool)
                ycrop[np.arange(yrange[0], yrange[1], 1, int)] = True
                self.ycrop.append(ycrop.nonzero()[0])
                self.xrange[-1] = self.xrange[-1][xcrop]
                self.yrange[-1] = self.yrange[-1][ycrop]
                self.LY = np.maximum(self.LY, self.Ly[-1] + self.dy[-1])
                self.LX = np.maximum(self.LX, self.Lx[-1] + self.dx[-1])
            #if os.path.isfile(os.path.join(basefolder, 'suite2p/combined/','F.npy')):
            #    self.Fcell = np.load(os.path.join(basefolder, 'suite2p/combined/','F.npy'))
            #    self.stat =  np.load(os.path.join(basefolder, 'suite2p/combined/','stat.npy'))
            #    self.Floaded = True
            #else:
            self.Floaded = False
            if self.Floaded:
                ncells = len(self.stat)
                for n in range(0, ncells):
                    ypix = self.stat[n]['ypix'].flatten()
                    xpix = self.stat[n]['xpix'].flatten()
                    iext = fig.boundary(ypix, xpix)
                    yext = ypix[iext]
                    xext = xpix[iext]
                    #yext = np.hstack((yext,yext+1,yext+1,yext-1,yext-1))
                    #xext = np.hstack((xext,xext+1,xext-1,xext+1,xext-1))
                    goodi = (yext >= 0) & (xext >= 0) & (yext < self.LY) & (
                        xext < self.LX)
                    self.stat[n]['yext'] = yext[goodi]
                    self.stat[n]['xext'] = xext[goodi]
            good = True
        except Exception as e:
            print("ERROR: incorrect ops1.npy or missing binaries")
            good = False
        if good:
            # only show registered even if raw exists
            self.wraw = False
            self.wred = False
            self.wraw_wred = False
            self.p1.clear()
            self.p2.clear()
            self.ichosen = 0
            self.ROIedit.setText('0')
            # get scaling from 100 random frames
            frames = utils.sample_frames(
                ops,
                np.linspace(0, ops['nframes'] - 1,
                            np.minimum(ops['nframes'], 100)).astype(int),
                self.reg_loc[-1])
            self.srange = frames.mean() + frames.std() * np.array([-1, 5])
            self.srange[0] = max(0, self.srange[0])
            self.reg_file = []
            self.nbytesread = []
            for n in range(len(self.reg_loc)):
                self.reg_file.append(open(self.reg_loc[n], 'rb'))
                self.nbytesread.append(2 * self.Ly[n] * self.Lx[n])

            #aspect ratio
            if 'aspect' in ops:
                self.xyrat = ops['aspect']
            elif 'diameter' in ops and (type(ops["diameter"]) is not int) and (
                    len(ops["diameter"]) > 1):
                self.xyrat = ops["diameter"][0] / ops["diameter"][1]
            else:
                self.xyrat = 1.0
            self.p0.setAspectLocked(lock=True, ratio=self.xyrat)

            self.movieLabel.setText(self.reg_loc[0])
            self.nframes = ops['nframes']
            self.time_step = 1. / ops['fs'] * 1000 / 5  # 5x real-time
            self.frameDelta = int(np.maximum(5, self.nframes / 200))
            self.frameSlider.setSingleStep(self.frameDelta)
            self.currentMovieDirectory = QtCore.QFileInfo(fileName).path()
            if self.nframes > 0:
                self.updateFrameSlider()
                self.updateButtons()

            # plot ops X-Y offsets for the last plane
            if 'yoff' in ops:
                self.yoff = ops['yoff']
                self.xoff = ops['xoff']
            else:
                self.yoff = np.zeros((ops['nframes'], ))
                self.xoff = np.zeros((ops['nframes'], ))
            self.p1.plot(self.yoff, pen='g')
            self.p1.plot(self.xoff, pen='y')
            self.p1.setRange(xRange=(0, self.nframes),
                             yRange=(np.minimum(self.yoff.min(),
                                                self.xoff.min()),
                                     np.maximum(self.yoff.max(),
                                                self.xoff.max())),
                             padding=0.0)
            self.p1.setLimits(xMin=0, xMax=self.nframes)
            self.scatter1 = pg.ScatterPlotItem()
            self.p1.addItem(self.scatter1)
            self.scatter1.setData(
                [self.cframe, self.cframe],
                [self.yoff[self.cframe], self.xoff[self.cframe]],
                size=10,
                brush=pg.mkBrush(255, 0, 0))
            if self.Floaded:
                self.cell_mask()
                self.ft = self.Fcell[self.ichosen, :]
                self.p2.plot(self.ft, pen='b')
                self.p2.setRange(xRange=(0, self.nframes),
                                 yRange=(self.ft.min(), self.ft.max()),
                                 padding=0.0)
                self.p2.setLimits(xMin=0, xMax=self.nframes)
                self.scatter2 = pg.ScatterPlotItem()
                self.p2.addItem(self.scatter2)
                self.scatter2.setData([self.cframe], [self.ft[self.cframe]],
                                      size=10,
                                      brush=pg.mkBrush(255, 0, 0))
                self.p2.setXLink('plot1')
            self.cframe = -1
            self.loaded = True
            self.next_frame()
示例#5
0
文件: merge.py 项目: ogeesan/suite2p
def activity_stats(parent):
    i0 = int(1 - parent.iscell[parent.ichosen])
    ypix = np.array([])
    xpix = np.array([])
    lam = np.array([])
    footprints = np.array([])
    F = np.zeros((0, parent.Fcell.shape[1]), np.float32)
    Fneu = np.zeros((0, parent.Fcell.shape[1]), np.float32)
    for n in np.array(parent.imerge):
        ypix = np.append(ypix, parent.stat[n]["ypix"])
        xpix = np.append(xpix, parent.stat[n]["xpix"])
        lam = np.append(lam, parent.stat[n]["lam"])
        footprints = np.append(footprints, parent.stat[n]["footprint"])
        F = np.append(F, parent.Fcell[n, :][np.newaxis, :], axis=0)
        Fneu = np.append(Fneu, parent.Fneu[n, :][np.newaxis, :], axis=0)

    # remove overlaps
    ipix = np.concatenate((ypix[:, np.newaxis], xpix[:, np.newaxis]), axis=1)
    _, goodi = np.unique(ipix, return_index=True, axis=0)
    ypix = ypix[goodi]
    xpix = xpix[goodi]
    lam = lam[goodi]
    stat0 = {}
    stat0["ypix"] = ypix.astype(np.int32)
    stat0["xpix"] = xpix.astype(np.int32)
    stat0["lam"] = lam
    stat0['med'] = [np.median(stat0["ypix"]), np.median(stat0["xpix"])]
    stat0["npix"] = ypix.size
    d0 = parent.ops["diameter"]
    radius = utils.fitMVGaus(ypix / d0[0], xpix / d0[1], lam, 2)[2]
    stat0["radius"] = radius[0] * d0.mean()
    stat0["aspect_ratio"] = 2 * radius[0] / (.01 + radius[0] + radius[1])
    npix = np.array([parent.stat[n]['npix']
                     for n in range(len(parent.stat))]).astype('float32')
    stat0["npix_norm"] = stat0["npix"] / npix.mean()
    # compactness
    rs, dy, dx = sparsedetect.circleMask(d0)
    rsort = np.sort(rs.flatten())
    r2 = ((ypix - stat0["med"][0]) / d0[0])**2 + (
        (xpix - stat0["med"][1]) / d0[1])**2
    r2 = r2**.5
    stat0["mrs"] = np.mean(r2)
    stat0["mrs0"] = np.mean(rsort[:r2.size])
    stat0["compact"] = stat0["mrs"] / (1e-10 + stat0["mrs0"])
    # footprint
    stat0["footprint"] = footprints.mean()
    F = F.mean(axis=0)
    Fneu = Fneu.mean(axis=0)
    dF = F - parent.ops["neucoeff"] * Fneu
    # activity stats
    stat0["skew"] = stats.skew(dF)
    stat0["std"] = dF.std()
    # compute outline and circle around cell
    iext = fig.boundary(ypix, xpix)
    stat0["yext"] = ypix[iext]
    stat0["xext"] = xpix[iext]
    ycirc, xcirc = fig.circle(stat0["med"], stat0["radius"])
    goodi = ((ycirc >= 0)
             & (xcirc >= 0)
             & (ycirc < parent.ops["Ly"])
             & (xcirc < parent.ops["Lx"]))
    stat0["ycirc"] = ycirc[goodi]
    stat0["xcirc"] = xcirc[goodi]
    # deconvolve activity
    spks = dcnv.oasis(dF[np.newaxis, :], parent.ops)
    # add cell to structs
    parent.stat = np.concatenate((parent.stat, np.array([stat0])), axis=0)
    print(parent.stat[-1]["ypix"].shape)
    parent.Fcell = np.concatenate((parent.Fcell, F[np.newaxis, :]), axis=0)
    parent.Fneu = np.concatenate((parent.Fneu, Fneu[np.newaxis, :]), axis=0)
    parent.Spks = np.concatenate((parent.Spks, spks), axis=0)
    iscell = np.array([parent.iscell[parent.ichosen]], dtype=bool)
    parent.iscell = np.concatenate((parent.iscell, iscell), axis=0)
示例#6
0
文件: merge.py 项目: chrytsi/suite2p
def merge_activity_masks(parent):
    print('merging activity... this may take some time')
    i0      = int(1-parent.iscell[parent.ichosen])
    ypix = np.array([])
    xpix = np.array([])
    lam  = np.array([])
    footprints  = np.array([])
    F    = np.zeros((0,parent.Fcell.shape[1]), np.float32)
    Fneu = np.zeros((0,parent.Fcell.shape[1]), np.float32)
    probcell = []
    probredcell = []
    merged_cells = []
    remove_merged = []
    for n in np.array(parent.imerge):
        if len(parent.stat[n]['imerge']) > 0:
            remove_merged.append(n)
            for k in parent.stat[n]['imerge']:
                merged_cells.append(k)
        else:
            merged_cells.append(n)
    merged_cells = np.unique(np.array(merged_cells))

    for n in merged_cells:
        ypix = np.append(ypix, parent.stat[n]["ypix"])
        xpix = np.append(xpix, parent.stat[n]["xpix"])
        lam = np.append(lam, parent.stat[n]["lam"])
        footprints = np.append(footprints, parent.stat[n]["footprint"])
        F    = np.append(F, parent.Fcell[n,:][np.newaxis,:], axis=0)
        Fneu = np.append(Fneu, parent.Fneu[n,:][np.newaxis,:], axis=0)
        probcell.append(parent.probcell[n])
        probredcell.append(parent.probredcell[n])

    probcell = np.array(probcell)
    probredcell = np.array(probredcell)
    pmean = probcell.mean()
    prmean = probredcell.mean()

    # remove overlaps
    ipix = np.concatenate((ypix[:,np.newaxis], xpix[:,np.newaxis]), axis=1)
    _, goodi = np.unique(ipix, return_index=True, axis=0)
    ypix = ypix[goodi]
    xpix = xpix[goodi]
    lam = lam[goodi]

    stat0 = {}
    if 'aspect' in parent.ops:
        d0 = np.array([int(parent.ops['aspect']*10), 10])
    else:
        d0 = parent.ops['diameter']
        if isinstance(d0, int):
            d0 = [d0,d0]

    ### compute statistics of merges
    stat0["imerge"] = merged_cells
    stat0["ypix"] = ypix.astype(np.int32)
    stat0["xpix"] = xpix.astype(np.int32)
    stat0["lam"] = lam / lam.sum() * merged_cells.size
    stat0['med']  = [np.median(stat0["ypix"]), np.median(stat0["xpix"])]
    stat0["npix"] = ypix.size
    radius = utils.fitMVGaus(ypix/d0[0], xpix/d0[1], lam, 2)[2]
    stat0["radius"] = radius[0] * d0.mean()
    stat0["aspect_ratio"] = 2 * radius[0]/(.01 + radius[0] + radius[1])
    npix = np.array([parent.stat[n]['npix'] for n in range(len(parent.stat))]).astype('float32')
    stat0["npix_norm"] = stat0["npix"] / npix.mean()
    # compactness
    rs,dy,dx = sparsedetect.circleMask(d0)
    rsort = np.sort(rs.flatten())
    r2 = ((ypix - stat0["med"][0])/d0[0])**2 + ((xpix - stat0["med"][1])/d0[1])**2
    r2 = r2**.5
    stat0["mrs"]  = np.mean(r2)
    stat0["mrs0"] = np.mean(rsort[:r2.size])
    stat0["compact"] = stat0["mrs"] / (1e-10 + stat0["mrs0"])
    # footprint
    stat0["footprint"] = footprints.mean()
    # inmerge
    stat0["inmerge"] = 0

    ### compute activity of merged cells
    F = F.mean(axis=0)
    Fneu = Fneu.mean(axis=0)
    dF = F - parent.ops["neucoeff"]*Fneu
    # activity stats
    stat0["skew"] = stats.skew(dF)
    stat0["std"] = dF.std()

    ### for GUI drawing
    # compute outline and circle around cell
    iext = fig.boundary(ypix, xpix)
    stat0["yext"] = ypix[iext].astype(np.int32)
    stat0["xext"] = xpix[iext].astype(np.int32)
    ycirc, xcirc = fig.circle(stat0["med"], stat0["radius"])
    goodi = (
            (ycirc >= 0)
            & (xcirc >= 0)
            & (ycirc < parent.ops["Ly"])
            & (xcirc < parent.ops["Lx"])
            )
    stat0["ycirc"] = ycirc[goodi]
    stat0["xcirc"] = xcirc[goodi]
    # deconvolve activity
    spks = dcnv.oasis(dF[np.newaxis, :], parent.ops)

    ### remove previously merged cell (do not replace)
    for k in remove_merged:
        remove_mask(parent, k)
        np.delete(parent.stat, k, 0)
        np.delete(parent.Fcell, k, 0)
        np.delete(parent.Fneu, k, 0)
        np.delete(parent.Spks, k, 0)
        np.delete(parent.iscell, k, 0)
        np.delete(parent.probcell, k, 0)
        np.delete(parent.probredcell, k, 0)
        np.delete(parent.redcell, k, 0)
        np.delete(parent.notmerged, k, 0)

    # add cell to structs
    parent.stat = np.concatenate((parent.stat, np.array([stat0])), axis=0)
    parent.stat = sparsedetect.get_overlaps(parent.stat, parent.ops)
    parent.stat = np.array(parent.stat)
    parent.Fcell = np.concatenate((parent.Fcell, F[np.newaxis,:]), axis=0)
    parent.Fneu = np.concatenate((parent.Fneu, Fneu[np.newaxis,:]), axis=0)
    parent.Spks = np.concatenate((parent.Spks, spks), axis=0)
    iscell = np.array([parent.iscell[parent.ichosen]], dtype=bool)
    parent.iscell = np.concatenate((parent.iscell, iscell), axis=0)
    parent.probcell = np.append(parent.probcell, pmean)
    parent.probredcell = np.append(parent.probredcell, prmean)
    parent.redcell = np.append(parent.redcell, prmean > parent.chan2prob)
    parent.notmerged = np.append(parent.notmerged, False)

    # recompute binned F
    parent.mode_change(parent.activityMode)

    for n in merged_cells:
        parent.stat[n]['inmerge'] = parent.stat.size-1

    add_mask(parent, parent.iscell.size-1)