Пример #1
0
    def galaxy_extra(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import above_min_amplitude_peaks
        from qtools.lib.mplot import galaxy_extracluster, cleanup, render as plt_render
        from qtools.lib.nstats.peaks import extracluster_peaks

        response.content_type = 'image/png'

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel_idx = int(request.params.get("channel", 0))

        peaks = above_min_amplitude_peaks(qlwell)
        threshold = c.vic_threshold if channel_idx == 1 else c.fam_threshold
        extra_data = extracluster_peaks(qlwell, channel_idx, threshold=threshold)
        extra_peaks, rain_boundaries, width_gates = extra_data
        pos, midhigh, midlow, neg = rain_boundaries
        min_gate, max_gate = width_gates
        title = 'GalaxyEX - %s, %s, %s' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if channel_idx == 1 else 'FAM')
        fig = galaxy_extracluster(title, peaks, channel_idx, threshold, min_gate, max_gate,
                                  pos, midhigh, midlow, neg,
                                  extra_peaks,
                                  min_amplitude_excluded=True)
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #2
0
    def air_hist(self, id=None, channel_num=0, *args, **kwargs):
        from qtools.lib.nstats.peaks import gap_air
        from pyqlb.nstats.well import accepted_peaks
        from pyqlb.nstats.peaks import color_uncorrected_peaks, channel_amplitudes, peak_times
        from qtools.lib.mplot import air_hist, cleanup, render as plt_render

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        c.channel_num = int(channel_num)
        threshold = c.vic_threshold if c.channel_num == 1 else c.fam_threshold
        cutoff = request.params.get('cutoff', 500)

        # can detect air on either channel (especially if VICs super low)
        # but always report VIC amplitude
        air_drops = gap_air(qlwell, c.channel_num, threshold=threshold)
        uncorrected_air = color_uncorrected_peaks(air_drops, qlwell.color_compensation_matrix)

        # count number of accepted peak times
        air_drop_times = peak_times(air_drops)
        accepted_times = peak_times(accepted_peaks(qlwell))
        num_air_accepted = len([t for t in air_drop_times if t in accepted_times])

        # always gate on VIC
        air_amps = channel_amplitudes(uncorrected_air, 1)

        title = 'Air Droplet Histogram - %s, %s (%s)' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if c.channel_num == 1 else 'FAM')
        fig = air_hist(title, air_amps, cutoff=cutoff, num_accepted=num_air_accepted)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #3
0
    def galaxy_disperse_revb(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import above_min_amplitude_peaks
        from qtools.lib.mplot import galaxy_polydisperse_revb, cleanup, render as plt_render, empty_fig
        from qtools.lib.nstats.peaks import revb_polydisperse_peaks

        response.content_type = 'image/png'

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel_idx = int(request.params.get("channel", 0))

        peaks = above_min_amplitude_peaks(qlwell)
        threshold = c.vic_threshold if channel_idx == 1 else c.fam_threshold

        title = 'GalaxyPDB - %s, %s, %s' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if channel_idx == 1 else 'FAM')
        if hasattr(qlwell, 'sum_amplitude_bins') and len(qlwell.sum_amplitude_bins) > 0:
            polydisperse_data = revb_polydisperse_peaks(qlwell, channel_idx, threshold=threshold)
            poly_peaks, rain_boundaries, mean_amplitudes = polydisperse_data
            pos_peaks, midhigh_peaks, midlow_peaks, neg_peaks = poly_peaks
            pos, midhigh, midlow, neg = rain_boundaries
            fam_mean, vic_mean = mean_amplitudes
            
            fig = galaxy_polydisperse_revb(title, peaks, channel_idx, threshold,
                                           pos, midhigh, midlow, neg,
                                           pos_peaks, midhigh_peaks, midlow_peaks, neg_peaks,
                                           min_amplitude_excluded=True,
                                           sum_amplitude_bins=qlwell.sum_amplitude_bins, other_channel_mean=fam_mean if channel_idx == 1 else vic_mean)
            
        else:
            fig = empty_fig()
            ax = fig.add_subplot(111, title=title)
            ax.text(0.33,0.5, "No amplitude bins for this well.")
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #4
0
    def svilen(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import accepted_peaks
        from pyqlb.nstats.peaks import cluster_2d, peak_times, fam_widths
        from pyqlb.factory import QLNumpyObjectFactory
        from qtools.lib.mplot import svilen, cleanup, render as plt_render

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        well_path = self.__well_path()
        # oh shit
        factory = QLNumpyObjectFactory()
        raw_well = factory.parse_well(well_path)

        crap, crap, gold, crap = cluster_2d(accepted_peaks(qlwell), c.fam_threshold,
                                            c.vic_threshold)
        
        times = peak_times(gold)
        widths = fam_widths(gold)

        title = "VIC+/FAM- droplet traces (accepted events)"
        ranges = [(int(t-(w*2)), int(t+(w*2))) for t, w in zip(times, widths)]
        if c.fam_threshold == 0 or c.vic_threshold == 0:
            ranges = []
            title = "%s (no events in quadrant)" % title
        elif len(ranges) > 100:
            ranges = ranges[:100]
            title = "%s (truncated at first 100)" % title

        
        fig = svilen(title, raw_well.samples, ranges, widths)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #5
0
    def bscore_trend(self, id=None, *args, **kwargs):
        from qtools.lib.mplot import plot_bscore_rolling_window, cleanup, render as plt_render

        response.content_type = 'image/png'
        qlwell = self.__qlwell_from_threshold_form(id)

        fig = plot_bscore_rolling_window(qlwell, title="%s - %s" % (c.well.plate.plate.name, c.well.well_name))
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #6
0
 def conc_trend(self, id=None, channel_num=0, *args, **kwargs):
     from qtools.lib.mplot import plot_conc_rolling_window, cleanup, render as plt_render
     
     response.content_type = 'image/png'
     c.channel_num = int(channel_num)
     qlwell = self.__qlwell_from_threshold_form(id)
     
     chan = 'FAM' if c.channel_num == 0 else 'VIC'
     fig = plot_conc_rolling_window(qlwell, c.channel_num, title="%s - %s (%s)" % (c.well.plate.plate.name, c.well.well_name, chan))
     imgdata = plt_render(fig, dpi=72)
     cleanup(fig)
     return imgdata
Пример #7
0
    def galaxy_sum_bins(self, id=None, *args, **kwargs):
        from qtools.lib.mplot import galaxy_sum_width_bins, cleanup, render as plt_render
        response.content_type = 'image/png'

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)

        title = 'Sum Amps/Width Bins - %s, %s' % (c.well.plate.plate.name, c.well.well_name)
        fig = galaxy_sum_width_bins(title, qlwell)
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #8
0
 def noreject(self, id=None, *args, **kwargs):
     from qtools.lib.mplot import plot_gated_types, cleanup, render as plt_render
     response.content_type = 'image/png'
     
     qlwell = self.__qlwell_from_threshold_form(id)
     self.__set_threshold_context(qlwell)
     max_amplitudes = [self.form_result['max_fam_amplitude'], self.form_result['max_vic_amplitude']]
     
     fig = plot_gated_types(qlwell,
                            max_amplitudes=max_amplitudes)
     response.content_type = 'image/png'
     imgdata = plt_render(fig, dpi=72)
     cleanup(fig)
     return imgdata
Пример #9
0
    def nds(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import above_min_amplitude_peaks, NARROW_NORMALIZED_DROPLET_SPACING
        from qtools.lib.mplot import nds, cleanup, render as plt_render

        qlwell = self.__qlwell_from_threshold_form(id)

        title = 'NDS Histogram - %s - %s' % (c.well.plate.plate.name, c.well.well_name)

        ok_peaks = above_min_amplitude_peaks(qlwell)
        fig = nds(title, ok_peaks, NARROW_NORMALIZED_DROPLET_SPACING)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #10
0
    def outliers(self, id=None, *args, **kwargs):
        from qtools.lib.nstats.peaks import total_events_amplitude_vals
        from qtools.lib.mplot import plot_cluster_outliers, cleanup, render as plt_render

        qlwell = self.__qlwell_from_threshold_form(id)
        means0,stds0 = total_events_amplitude_vals(qlwell,0) 
        means1,stds1 = total_events_amplitude_vals(qlwell,1) 
        title = 'Outliers - Well:%s FAM:(Mean: %.0f, Stdev:%.0f) \n                   VIC/HEX:(Mean: %.0f, Stdev: %.0f)' % (c.well.well_name,means0,stds0,means1,stds1)

	peaks = qlwell.peaks
        fig = plot_cluster_outliers(title, peaks)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #11
0
    def width(self, id=None, *args, **kwargs):
        from qtools.lib.mplot import plot_widths, cleanup, render as plt_render

        response.content_type = 'image/png'
        qlwell = self.__qlwell_from_threshold_form(id)
        
        # assume widths are same on channel 0 as on 1
        fig = plot_widths(qlwell.peaks,
                          min_width_gate=qlwell.channels[0].statistics.min_width_gate,
                          max_width_gate=qlwell.channels[0].statistics.max_width_gate,
                          max_width=20,
                          background_rgbs=self.__get_1d_background_rgbs(qlwell))
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #12
0
    def amptime(self, id=None, channel_num=0, *args, **kwargs):
        from qtools.lib.mplot import amptime, cleanup, render as plt_render

        response.content_type = 'image/png'
        c.channel_num = int(channel_num)
        qlwell = self.__qlwell_from_threshold_form(id)

        self.__set_threshold_context(qlwell)
        peaks = qlwell.peaks

        title = 'Intensity/Time - %s - %s, %s' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if c.channel_num == 1 else 'FAM')
        fig = amptime(title, peaks, c.vic_threshold if c.channel_num == 1 else c.fam_threshold, c.channel_num)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #13
0
    def air_plot(self, id=None, channel_num=0, *args, **kwargs):
        from qtools.lib.nstats.peaks import gap_air
        from qtools.lib.mplot import airtime, cleanup, render as plt_render

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        c.channel_num = int(channel_num)
        threshold = c.vic_threshold if c.channel_num == 1 else c.fam_threshold
        #cutoff = request.params.get('cutoff', 500)

        air_drops = gap_air(qlwell, c.channel_num, threshold=threshold)
        title = 'Air - %s - %s, %s' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if c.channel_num == 1 else 'FAM')
        fig = airtime(title, qlwell.peaks, air_drops, c.vic_threshold if c.channel_num == 1 else c.fam_threshold, c.channel_num)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #14
0
    def amphist(self, id=None, channel_num=0, *args, **kwargs):
        from qtools.lib.mplot import plot_amp_hist, cleanup, render as plt_render
        from pyqlb.nstats.well import accepted_peaks

        response.content_type = 'image/png'
        c.channel_num = int(channel_num)
        qlwell = self.__qlwell_from_threshold_form(id)
        
        self.__set_threshold_context(qlwell)
        peaks = accepted_peaks(qlwell)
        fig = plot_amp_hist(peaks,
                            title='%s - %s' % (c.well.plate.plate.name, c.well.well_name),
                            channel_num=c.channel_num,
                            threshold=(c.vic_threshold if c.channel_num == 1 else c.fam_threshold))
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #15
0
    def cluster(self, id=None, *args, **kwargs):
        from qtools.lib.mplot import plot_threshold_2d, cleanup, render as plt_render
        from qtools.lib.nstats.peaks import accepted_peaks
        
        response.content_type = 'image/png'
        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        max_amplitudes = [self.form_result['max_fam_amplitude'], self.form_result['max_vic_amplitude']]
        boundaries = (-2000,-2000,max_amplitudes[1],max_amplitudes[0])

        # to emulate current behavior -- include gated events
        peaks = accepted_peaks(qlwell)
        fig = plot_threshold_2d(peaks,
                                thresholds=(c.fam_threshold, c.vic_threshold),
                                boundaries=boundaries)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #16
0
    def temporal(self, id=None, channel_num=0, *args, **kwargs):
        from qtools.lib.mplot import temporal, cleanup, render as plt_render
        
        response.content_type = 'image/png'
        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel = int(request.params.get("channel", 0))
        
        if not request.params.get('threshold', None):
            threshold = c.vic_threshold if channel == 1 else c.fam_threshold
        else:
            threshold = float(request.params.get('threshold'))

        title = 'Temporal Width Lite - %s - %s' % (c.well.plate.plate.name, c.well.well_name)
        fig = temporal(title, qlwell.peaks, threshold, qlwell.channels[channel].statistics.min_width_gate,
                       qlwell.channels[channel].statistics.max_width_gate, channel)
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #17
0
    def galaxy(self, id=None, channel_num=0, *args, **kwargs):
        from qtools.lib.nstats.peaks import above_min_amplitude_peaks
        from pyqlb.nstats.well import well_static_width_gates

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel_idx = int(request.params.get("channel", 0))

        from qtools.lib.mplot import galaxy, cleanup, render as plt_render

        peaks = above_min_amplitude_peaks(qlwell)
        title = 'Galaxy Lite - %s - %s, %s' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if channel_idx == 1 else 'FAM')
        threshold = c.vic_threshold if channel_idx == 1 else c.fam_threshold
        min_width_gate, max_width_gate = well_static_width_gates(qlwell)
        fig = galaxy(title, peaks, threshold, min_width_gate, max_width_gate, channel_idx)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #18
0
    def widthbin(self, id=None, *args, **kwargs):
        from qtools.lib.nstats.peaks import above_min_amplitude_peaks
        from qtools.lib.mplot import plot_cluster_widthbins, cleanup, render as plt_render

        qlwell = self.__qlwell_from_threshold_form(id)
        title = 'Width Bins - %s, %s' % (c.well.plate.plate.name, c.well.well_name)

        min_gate = qlwell.channels[0].statistics.min_width_gate
        max_gate = qlwell.channels[0].statistics.max_width_gate

        peaks = above_min_amplitude_peaks(qlwell)
        fam_threshold = qlwell.channels[0].statistics.threshold
        vic_threshold = qlwell.channels[1].statistics.threshold
        fig = plot_cluster_widthbins(title, peaks, qlwell.sum_amplitude_bins, min_gate, max_gate,
                                     fam_threshold=fam_threshold, vic_threshold=vic_threshold)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #19
0
    def cluster2d(self, id=None, *args, **kwargs):
        from qtools.lib.mplot import plot_cluster_2d, cleanup, render as plt_render
        from qtools.lib.nstats.peaks import accepted_peaks
        
        response.content_type = 'image/png'
        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        max_amplitudes = [self.form_result['max_fam_amplitude'], self.form_result['max_vic_amplitude']]
        boundaries = (-2000,-2000,max_amplitudes[1],max_amplitudes[0])

        # to emulate current behavior -- include gated events
        peaks = accepted_peaks(qlwell)
        threshold_fallback = qlwell.clustering_method == QLWell.CLUSTERING_TYPE_THRESHOLD
        fig = plot_cluster_2d(peaks,
                              thresholds=(c.fam_threshold, c.vic_threshold),
                              boundaries=boundaries,
                              use_manual_clusters=not well_channel_automatic_classification(qlwell),
                              highlight_thresholds=threshold_fallback)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #20
0
    def galaxy_extra_region(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import above_min_amplitude_peaks
        from qtools.lib.mplot import graph_extracluster_by_region, cleanup, render as plt_render
        from qtools.lib.nstats.peaks import revb_extracluster_peaks_by_region

        response.content_type = 'image/png'

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel_idx = int(request.params.get("channel", 0))
        peaks = above_min_amplitude_peaks(qlwell)
        threshold = c.vic_threshold if channel_idx == 1 else c.fam_threshold
        extra_data = revb_extracluster_peaks_by_region(qlwell, channel_idx, threshold=threshold)
        peaks_by_region, rain_gates, means = extra_data
        title = "GalaxyEXR - %s, %s, %s" % (c.well.plate.plate.name, c.well.well_name, 'VIC' if channel_idx == 1 else 'FAM')
        fig = graph_extracluster_by_region(title, peaks, channel_idx, threshold,
                                           peaks_by_region, rain_gates,
                                           sum_amplitude_bins=qlwell.sum_amplitude_bins,
                                           other_channel_mean=means[channel_idx])
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #21
0
 def threshold(self, id=None, show_only_gated=True, *args, **kwargs):
     from qtools.lib.mplot import plot_fam_vic_peaks, cleanup, render as plt_render
     from qtools.lib.nstats.peaks import accepted_peaks
     response.content_type = 'image/png'
     
     qlwell = self.__qlwell_from_threshold_form(id)
     self.__set_threshold_context(qlwell)
     max_amplitudes = [self.form_result['max_fam_amplitude'], self.form_result['max_vic_amplitude']]
     
     # to emulate current behavior -- include gated events
     if show_only_gated != 'False':
         peaks = accepted_peaks(qlwell)
     else:
         peaks = qlwell.peaks
     
     fig = plot_fam_vic_peaks(peaks, thresholds=(c.fam_threshold, c.vic_threshold),
                              max_amplitudes=max_amplitudes,
                              background_rgbs=self.__get_1d_background_rgbs(qlwell))
     response.content_type = 'image/png'
     imgdata = plt_render(fig, dpi=72)
     cleanup(fig)
     return imgdata
Пример #22
0
    def dg_trend(self, prop, view, dg_id):
        from qtools.lib.mplot import dg_vacuum_time, dg_vacuum_runs, dg_pressure_time, dg_pressure_runs, dg_spike_runs, dg_spike_time
        from qtools.lib.mplot import cleanup, render as plt_render
        if id is None:
            abort(404)
        
        dg = Session.query(DropletGenerator).get(int(dg_id))
        if not dg:
            abort(404)
        
        func_map = dict([(('vacuum', 'time'), dg_vacuum_time),
                         (('vacuum', 'runs'), dg_vacuum_runs),
                         (('pressure', 'time'), dg_pressure_time),
                         (('pressure', 'runs'), dg_pressure_runs),
                         (('spike', 'runs'), dg_spike_runs),
                         (('spike', 'time'), dg_spike_time)])

        good_runs = get_good_dg_runs(int(dg_id))
        fig = func_map[(prop, view)](dg.name, good_runs)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Пример #23
0
    def fft(self, id=None):
        from qtools.lib.mplot import cleanup, render as plt_render
        # make it better?
        if not deps_loaded:
            abort(500)
        
        if not id:
            abort(404)
        
        well = Session.query(QLBWell).get(id)
        if not well:
            abort(404)
        
        file = well.file
        if not file:
            abort(404)
            
        storage = QLStorageSource(config)
        path = storage.qlbwell_path(well)
        wellobj = get_well(path)
        
        fam_samples = wellobj.samples[:,0][::FFT_DOWNSAMPLE].astype('float')
        vic_samples = wellobj.samples[:,1][::FFT_DOWNSAMPLE].astype('float')

        # normalize to 0->1
        fam_samples /= np.max(fam_samples)
        vic_samples /= np.max(vic_samples)

        Sf = np.fft.fft(fam_samples)
        numpy.fft.fftpack._fft_cache = {}
        ff = np.fft.fftfreq(len(Sf), d=FFT_DOWNSAMPLE/wellobj.data_acquisition_params.sample_rate)

        # only consider positive half of frequency domain, normalize by num of samples
        Yf = abs(Sf[0:len(ff)/2])/len(fam_samples)

        # make X-axis in terms of Hz
        Wf = int((len(ff)/2)/max(ff)) # group by 1 Hz

        Sv = np.fft.fft(vic_samples)
        numpy.fft.fftpack._fft_cache = {}
        fv = np.fft.fftfreq(len(Sv), d=FFT_DOWNSAMPLE/wellobj.data_acquisition_params.sample_rate)
        Yv = abs(Sv[0:len(fv)/2])/len(vic_samples)
        Wv = int((len(fv)/2)/max(fv)) # group by 1 Hz

        # find peaks
        fam_peak_indices = fft.find_peak_indices(Yf, Wf*2) # group by 2Hz
        vic_peak_indices = fft.find_peak_indices(Yv, Wv*2) # group by 2Hz

        ftops = ff.take(fam_peak_indices)[0:10]
        vtops = fv.take(vic_peak_indices)[0:10]

        fig = plt.figure()
        fig.set_figwidth(8)
        fig.set_figheight(6)
        plt.subplot(211)

        plt.title('FAM Channel FFT (0-150Hz)')
        plt.plot(ff[0:len(ff)/2], Yf)
        plt.axis([-10, 150, -0.002, 0.04])
        plt.text(70, 0.03, "Top Peaks (2 Hz windows):", weight='bold')
        for i, val in enumerate(ftops):
            plt.text(70 if i < 5 else 90, 0.027-(0.003*(i % 5)), "%.2f" % val, size=10)

        # todo render text func?
        
        
        plt.subplot(212)
        plt.title('VIC Channel FFT (0-150Hz)')
        plt.plot(fv[0:len(fv)/2], Yv)
        plt.axis([-10, 150, -0.002, 0.04])
        plt.text(70, 0.03, "Top Peaks (2 Hz windows):", weight='bold')
        for i, val in enumerate(vtops):
            plt.text(70 if i < 5 else 90, 0.027-(0.003*(i % 5)), "%.2f" % val, size=10)

        # fft leaves cache-- not good for threaded server
        imgdata = self.__render(fig)
        cleanup(fig)
        del fig, wellobj, fam_samples, vic_samples, Sf, ff, Yf, Wf, Sv, fv, Yv, Wv, ftops, vtops
        gc.collect()
        return imgdata