def plot_table(ax, data, float_format='{:.2f}', columns=None, bbox=None, cell_font_size=6): if columns is not None: if type(columns) is dict: data = data[columns.keys()] data = data.rename(columns) else: data = data[columns] if bbox is None: bbox = [0, 0, 1, 1] ax.set_axis_off() table = Table(ax, bbox=bbox) num_rows, num_cols = data.shape width = 1.0 / num_cols #height = 1.0 / num_rows height = table._approx_text_height() # Add cells for (i,j), val in np.ndenumerate(data): val = float_format.format(val) table.add_cell(i, j, width, height, text=val, loc='center') cells = table.get_celld() for index, val in np.ndenumerate(data): cells[index].set_fontsize(cell_font_size) # Row Labels... for i, label in enumerate(data.index): table.add_cell(i, -1, width, height, text=label, loc='right', edgecolor='none', facecolor='none') # Column Labels... for j, label in enumerate(data.columns): table.add_cell(-1, j, width, height/2, text=label, loc='center', edgecolor='none', facecolor='none') ax.add_table(table) table.set_fontsize(cell_font_size) return ax
def plot(self, experiment, **kwargs): """Plot a table""" if not experiment: raise util.CytoflowViewError("No experiment specified") if not self.channel or self.channel not in experiment.data: raise util.CytoflowViewError("Must set a channel") if not (self.row_facet or self.column_facet): raise util.CytoflowViewError("Must set at least one of row_facet " "or column_facet") if self.subrow_facet and not self.row_facet: raise util.CytoflowViewError("Must set row_facet before using " "subrow_facet") if self.subcolumn_facet and not self.column_facet: raise util.CytoflowViewError("Must set column_facet before using " "subcolumn_facet") if self.row_facet and self.row_facet not in experiment.conditions: raise util.CytoflowViewError("Row facet {0} not in the experiment" .format(self.row_facet)) if self.subrow_facet and self.subrow_facet not in experiment.conditions: raise util.CytoflowViewError("Subrow facet {0} not in the experiment" .format(self.subrow_facet)) if self.column_facet and self.column_facet not in experiment.conditions: raise util.CytoflowViewError("Column facet {0} not in the experiment" .format(self.column_facet)) if self.subcolumn_facet and self.subcolumn_facet not in experiment.conditions: raise util.CytoflowViewError("Subcolumn facet {0} not in the experiment" .format(self.subcolumn_facet)) if not self.function: raise util.CytoflowViewError("Summary function isn't set") row_groups = np.sort(pd.unique(experiment[self.row_facet])) \ if self.row_facet else [None] subrow_groups = np.sort(pd.unique(experiment[self.subrow_facet])) \ if self.subrow_facet else [None] col_groups = np.sort(pd.unique(experiment[self.column_facet])) \ if self.column_facet else [None] subcol_groups = np.sort(pd.unique(experiment[self.subcolumn_facet])) \ if self.subcolumn_facet else [None] if self.subset: try: data = experiment.query(self.subset).data.reset_index() except: raise util.CytoflowViewError("Subset string '{0}' isn't valid" .format(self.subset)) if len(data.index) == 0: raise util.CytoflowViewError("Subset string '{0}' returned no events" .format(self.subset)) else: data = experiment.data group_vars = [] if self.row_facet: group_vars.append(self.row_facet) if self.subrow_facet: group_vars.append(self.subrow_facet) if self.column_facet: group_vars.append(self.column_facet) if self.subcolumn_facet: group_vars.append(self.subcolumn_facet) agg = data.groupby(by = group_vars)[self.channel].aggregate(self.function) # agg is a multi-index series; we can get a particular value from it # with get(idx1, idx2...) row_offset = (self.column_facet != "") + (self.subcolumn_facet != "") col_offset = (self.row_facet != "") + (self.subrow_facet != "") num_cols = len(col_groups) * len(subcol_groups) + col_offset fig = plt.figure() ax = fig.add_subplot(111) # hide the plot axes that matplotlib tries to make ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) for sp in ax.spines.itervalues(): sp.set_color('w') sp.set_zorder(0) loc = 'best' bbox = None t = Table(ax, loc, bbox, **kwargs) width = [1.0 / num_cols] * num_cols height = t._approx_text_height() * 1.8 # make the main table for (ri, r) in enumerate(row_groups): for (rri, rr) in enumerate(subrow_groups): for (ci, c) in enumerate(col_groups): for (cci, cc) in enumerate(subcol_groups): row_idx = ri * len(subrow_groups) + rri + row_offset col_idx = ci * len(subcol_groups) + cci + col_offset agg_idx = [x for x in (r, rr, c, cc) if x is not None] agg_idx = tuple(agg_idx) if len(agg_idx) == 1: agg_idx = agg_idx[0] t.add_cell(row_idx, col_idx, width = width[col_idx], height = height, text = agg.get(agg_idx)) # row headers if self.row_facet: for (ri, r) in enumerate(row_groups): row_idx = ri * len(subrow_groups) + row_offset text = "{0} = {1}".format(self.row_facet, r) t.add_cell(row_idx, 0, width = width[0], height = height, text = text) # subrow headers if self.subrow_facet: for (ri, r) in enumerate(row_groups): for (rri, rr) in enumerate(subrow_groups): row_idx = ri * len(subrow_groups) + rri + row_offset text = "{0} = {1}".format(self.subrow_facet, rr) t.add_cell(row_idx, 1, width = width[1], height = height, text = text) # column headers if self.column_facet: for (ci, c) in enumerate(col_groups): col_idx = ci * len(subcol_groups) + col_offset text = "{0} = {1}".format(self.column_facet, c) t.add_cell(0, col_idx, width = width[col_idx], height = height, text = text) # column headers if self.subcolumn_facet: for (ci, c) in enumerate(col_groups): for (cci, cc) in enumerate(subcol_groups): col_idx = ci * len(subcol_groups) + cci + col_offset text = "{0} = {1}".format(self.subcolumn_facet, c) t.add_cell(1, col_idx, width = width[col_idx], height = height, text = text) ax.add_table(t)
def label_manual(self, display_elems, figsize=(15, 7.5), title="Sleep Stages"): """ Displays dialog for manual stage labeling args: displa_elems: list of lists of parameters used for display in format ((data_struct,{'parname1':parval1,'parname2':parval2,...}),...) where data_struct is of class containing plot method (such as EEGSpectralData) and 'parname1':parval1,... are name-value pairs supplied to the function. figsize: Size of the figure block: Blocks code execution until label dialog is closed """ self.saving = False sleep_stage_labels = [ 'NREM3', 'NREM2', 'REM', 'NREM1', 'WAKE', 'MASK OFF', '???' ] height_ratios = np.ones(len(display_elems)) * 3 height_ratios = np.append(height_ratios, 1) fig = plt.figure(figsize=figsize) gs = gridspec.GridSpec(len(display_elems) + 1, 1, height_ratios=height_ratios) ax_transforms = {} def format_time_period(val): m, s = divmod(int(round(val)), 60) h, m = divmod(m, 60) return "%d:%02d:%02d" % (h, m, s) def reset_labels(event=None): self.stage_times = [0] self.stage_labels = [5] if event is not None: redraw_labels(event) def reload_labels(event=None): self.stage_times = np.append([], self.loaded_stage_times) self.stage_labels = np.append([], self.loaded_stage_labels) if self.stage_times[0] is None or self.stage_labels[ 0] is None or self.stage_times.size != self.stage_labels.size: print("data is bad, resetting labels") reset_labels(event) else: print("stage_times size is " + str(self.stage_times.size)) print("stage_labels size is " + str(self.stage_labels.size)) if event is not None: redraw_labels(event) def redraw_labels(event=None): line1.set_xdata( np.concatenate((self.stage_times, [self.sleep_length]))) line1.set_ydata( np.concatenate((self.stage_labels, [self.stage_labels[-1]]))) data = [0, 0, 0, 0, 0, 0, 0, 0] for x in range(0, len(self.stage_times)): data_offset = int( len(sleep_stage_labels) - (self.stage_labels[x] + 1)) thisval = self.stage_times[x] nextval = self.sleep_length if x is len( self.stage_times) - 1 else self.stage_times[x + 1] diffval = nextval - thisval data[data_offset] = data[data_offset] + diffval data[len(data) - 1] = self.sleep_length for x in range(0, len(data)): table.get_celld()[x, 1].get_text().set_text( format_time_period(data[x])) fig.canvas.draw() def on_pick(figure, mouseevent): #print(ax_transforms) #print(mouseevent) #print(figure) #print(figure.get_axes()) if not mouseevent.inaxes in ax_transforms: return False, {} eegdata = ax_transforms[mouseevent.inaxes] xmouse, ymouse = mouseevent.xdata, mouseevent.ydata xmouse = eegdata.index_to_time(xmouse) #print('x, y of mouse: {:.2f},{:.2f}'.format(xmouse, ymouse)) larger = [ x[0] for x in enumerate(self.stage_times) if x[1] > xmouse ] if len(larger) > 0: idx = larger[0] if self.stage_labels[idx - 1] != self.stage_label: self.stage_times[idx] = xmouse self.stage_labels[idx] = self.stage_label else: self.stage_times = np.delete(self.stage_times, idx) self.stage_labels = np.delete(self.stage_labels, idx) else: if self.stage_labels[-1] != self.stage_label: self.stage_times = np.append(self.stage_times, xmouse) self.stage_labels = np.append(self.stage_labels, self.stage_label) #print(stage_times) #print(stage_labels) for i in range(1, len(self.stage_labels) - 1): if self.stage_labels[i] == self.stage_labels[i - 1]: self.stage_labels = np.delete(self.stage_labels, i) self.stage_times = np.delete(self.stage_times, i) redraw_labels() return True, {} for did in range(len(display_elems)): delem = display_elems[did] ax = plt.subplot(gs[did]) ax_transforms[ax] = delem[0] params = delem[1] params['axes'] = ax delem[0].plot(**params) if did == 0: plt.title(title) #TODO ax.set_picker(True) fig.canvas.mpl_connect('pick_event', on_pick) fig.set_picker(on_pick) xtickspacing = 300 if len(np.arange(0, self.sleep_length, 300)) > 20: xtickspacing = 600 if len(np.arange(0, self.sleep_length, 600)) > 20: xtickspacing = 1200 if len(np.arange(0, self.sleep_length, 1200)) > 20: xtickspacing = 1800 if len(np.arange(0, self.sleep_length, 1800)) > 20: xtickspacing = 3600 xticks = np.arange(0, self.sleep_length, xtickspacing) xticklabels = [str(int(i / 60)) for i in xticks] reload_labels() ax1 = plt.subplot(gs[-1]) line1, = ax1.plot(np.concatenate( (self.stage_times, [self.sleep_length])), np.concatenate( (self.stage_labels, [self.stage_labels[-1]])), drawstyle="steps-post") ax1.set_xlabel("Time (min)") ax1.set_ylabel("Sleep Stage") ax1.set_xlim(0, self.sleep_length) ax1.set_yticks(np.arange(7)) ax1.set_yticklabels(sleep_stage_labels) ax1.set_xticks(xticks) ax1.set_xticklabels(xticklabels) self.stage_label = 6 rax = plt.axes([0.0, 0.0, 0.2, 0.16], facecolor='lightgoldenrodyellow') radio = RadioButtons(rax, sleep_stage_labels[::-1], active=0) def stagepicker(label): self.stage_label = sleep_stage_labels.index(label) #print(plot_eeg_log_hist.stage_label) #fig.canvas.draw_idle() def done(event): self.saving = True plt.close() if self.loaded_stage_labels is not None: axreload = plt.axes([0.7, 0.0, 0.1, 0.075]) breload = Button(axreload, 'Reload') breload.on_clicked(reload_labels) axreset = plt.axes([0.8, 0.0, 0.1, 0.075]) breset = Button(axreset, 'Reset') breset.on_clicked(reset_labels) axdone = plt.axes([0.9, 0.0, 0.1, 0.075]) bdone = Button(axdone, 'Save &\n Quit') bdone.on_clicked(done) radio.on_clicked(stagepicker) tableax = plt.axes([0.2, 0.0, 0.25, 0.16], facecolor='lightblue') tableax.get_yaxis().set_visible(False) table = Table(tableax, bbox=[0, 0, 1, 1]) height = table._approx_text_height() lidx = 0 for label in sleep_stage_labels[::-1]: table.add_cell(lidx, 0, width=0.6, height=height, text=label) table.add_cell(lidx, 1, width=0.4, height=height, text='') lidx = lidx + 1 table.add_cell(lidx, 0, width=0.6, height=height, text='Total Sleep Time') table.add_cell(lidx, 1, width=0.4, height=height, text='') tableax.add_table(table) fig.canvas.callbacks.connect('pick_event', on_pick) fig.canvas.set_window_title('EEG Spectrogram Analysis') plt.subplots_adjust(left=0.15 if figsize[0] < 10 else 0.075, bottom=0.2, right=0.99, top=0.97) redraw_labels() plt.show() self.stage_times = np.array(self.stage_times) self.stage_times = np.concatenate( (self.stage_times, [self.sleep_length])) self.stage_labels = np.concatenate((self.stage_labels, [6]))
def plot(self, experiment, plot_name = None, **kwargs): """Plot a table""" if experiment is None: raise util.CytoflowViewError('experiment', "No experiment specified") if self.statistic not in experiment.statistics: raise util.CytoflowViewError('statistic', "Can't find the statistic {} in the experiment" .format(self.statistic)) else: stat = experiment.statistics[self.statistic] data = pd.DataFrame(index = stat.index) data[stat.name] = stat if self.subset: try: data = data.query(self.subset) except Exception as e: raise util.CytoflowViewError('subset', "Subset string '{0}' isn't valid" .format(self.subset)) from e if len(data) == 0: raise util.CytoflowViewError('subset', "Subset string '{0}' returned no values" .format(self.subset)) names = list(data.index.names) for name in names: unique_values = data.index.get_level_values(name).unique() if len(unique_values) == 1: warn("Only one value for level {}; dropping it.".format(name), util.CytoflowViewWarning) try: data.index = data.index.droplevel(name) except AttributeError as e: raise util.CytoflowViewError(None, "Must have more than one " "value to plot.") from e if not (self.row_facet or self.column_facet): raise util.CytoflowViewError('row_facet', "Must set at least one of row_facet " "or column_facet") if self.subrow_facet and not self.row_facet: raise util.CytoflowViewError('subrow_facet', "Must set row_facet before using " "subrow_facet") if self.subcolumn_facet and not self.column_facet: raise util.CytoflowViewError('subcolumn_facet', "Must set column_facet before using " "subcolumn_facet") if self.row_facet and self.row_facet not in experiment.conditions: raise util.CytoflowViewError('row_facet', "Row facet {} not in the experiment, " "must be one of {}" .format(self.row_facet, experiment.conditions)) if self.row_facet and self.row_facet not in data.index.names: raise util.CytoflowViewError('row_facet', "Row facet {} not a statistic index; " "must be one of {}" .format(self.row_facet, data.index.names)) if self.subrow_facet and self.subrow_facet not in experiment.conditions: raise util.CytoflowViewError('subrow_facet', "Subrow facet {} not in the experiment, " "must be one of {}" .format(self.subrow_facet, experiment.conditions)) if self.subrow_facet and self.subrow_facet not in data.index.names: raise util.CytoflowViewError('subrow_facet', "Subrow facet {} not a statistic index; " "must be one of {}" .format(self.subrow_facet, data.index.names)) if self.column_facet and self.column_facet not in experiment.conditions: raise util.CytoflowViewError('column_facet', "Column facet {} not in the experiment, " "must be one of {}" .format(self.column_facet, experiment.conditions)) if self.column_facet and self.column_facet not in data.index.names: raise util.CytoflowViewError('column_facet', "Column facet {} not a statistic index; " "must be one of {}" .format(self.column_facet, data.index.names)) if self.subcolumn_facet and self.subcolumn_facet not in experiment.conditions: raise util.CytoflowViewError('subcolumn_facet', "Subcolumn facet {} not in the experiment, " "must be one of {}" .format(self.subcolumn_facet, experiment.conditions)) if self.subcolumn_facet and self.subcolumn_facet not in data.index.names: raise util.CytoflowViewError('subcolumn_facet', "Subcolumn facet {} not a statistic index; " "must be one of {}" .format(self.subcolumn_facet, data.index.names)) facets = [x for x in [self.row_facet, self.subrow_facet, self.column_facet, self.subcolumn_facet] if x] if len(facets) != len(set(facets)): raise util.CytoflowViewError(None, "Can't reuse facets") if set(facets) != set(data.index.names): raise util.CytoflowViewError(None, "Must use all the statistic indices as variables or facets: {}" .format(data.index.names)) row_groups = data.index.get_level_values(self.row_facet).unique() \ if self.row_facet else [None] subrow_groups = data.index.get_level_values(self.subrow_facet).unique() \ if self.subrow_facet else [None] col_groups = data.index.get_level_values(self.column_facet).unique() \ if self.column_facet else [None] subcol_groups = data.index.get_level_values(self.subcolumn_facet).unique() \ if self.subcolumn_facet else [None] row_offset = (self.column_facet != "") + (self.subcolumn_facet != "") col_offset = (self.row_facet != "") + (self.subrow_facet != "") num_cols = len(col_groups) * len(subcol_groups) + col_offset fig = plt.figure() ax = fig.add_subplot(111) # hide the plot axes that matplotlib tries to make ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) for sp in ax.spines.values(): sp.set_color('w') sp.set_zorder(0) loc = 'upper left' bbox = None t = Table(ax, loc, bbox, **kwargs) t.auto_set_font_size(False) for c in range(num_cols): t.auto_set_column_width(c) width = [0.2] * num_cols height = t._approx_text_height() * 1.8 # make the main table for (ri, r) in enumerate(row_groups): for (rri, rr) in enumerate(subrow_groups): for (ci, c) in enumerate(col_groups): for (cci, cc) in enumerate(subcol_groups): row_idx = ri * len(subrow_groups) + rri + row_offset col_idx = ci * len(subcol_groups) + cci + col_offset # this is not pythonic, but i'm tired agg_idx = [] for data_idx in data.index.names: if data_idx == self.row_facet: agg_idx.append(r) elif data_idx == self.subrow_facet: agg_idx.append(rr) elif data_idx == self.column_facet: agg_idx.append(c) elif data_idx == self.subcolumn_facet: agg_idx.append(cc) agg_idx = tuple(agg_idx) if len(agg_idx) == 1: agg_idx = agg_idx[0] try: text = "{:g}".format(data.loc[agg_idx][stat.name]) except ValueError: text = data.loc[agg_idx][stat.name] t.add_cell(row_idx, col_idx, width = width[col_idx], height = height, text = text) # row headers if self.row_facet: for (ri, r) in enumerate(row_groups): row_idx = ri * len(subrow_groups) + row_offset try: text = "{0} = {1:g}".format(self.row_facet, r) except ValueError: text = "{0} = {1}".format(self.row_facet, r) t.add_cell(row_idx, 0, width = width[0], height = height, text = text) # subrow headers if self.subrow_facet: for (ri, r) in enumerate(row_groups): for (rri, rr) in enumerate(subrow_groups): row_idx = ri * len(subrow_groups) + rri + row_offset try: text = "{0} = {1:g}".format(self.subrow_facet, rr) except ValueError: text = "{0} = {1}".format(self.subrow_facet, rr) t.add_cell(row_idx, 1, width = width[1], height = height, text = text) # column headers if self.column_facet: for (ci, c) in enumerate(col_groups): col_idx = ci * len(subcol_groups) + col_offset try: text = "{0} = {1:g}".format(self.column_facet, c) except ValueError: text = "{0} = {1}".format(self.column_facet, c) t.add_cell(0, col_idx, width = width[col_idx], height = height, text = text) # subcolumn headers if self.subcolumn_facet: for (ci, c) in enumerate(col_groups): for (cci, cc) in enumerate(subcol_groups): col_idx = ci * len(subcol_groups) + cci + col_offset try: text = "{0} = {1:g}".format(self.subcolumn_facet, cc) except ValueError: text = "{0} = {1}".format(self.subcolumn_facet, cc) t.add_cell(1, col_idx, width = width[col_idx], height = height, text = text) ax.add_table(t)
def plot(self, experiment, plot_name=None, **kwargs): """Plot a table of the conditions, filenames, and number of events""" if experiment is None: raise util.CytoflowViewError('experiment', "No experiment specified") if self.subset: try: experiment = experiment.query(self.subset) except Exception as e: raise util.CytoflowViewError( 'subset', "Subset string '{0}' isn't valid".format( self.subset)) from e if len(experiment) == 0: raise util.CytoflowViewError( 'subset', "Subset string '{0}' returned no values".format( self.subset)) # if path is set, actually do an export. this isn't terribly elegant, # but this is the only place we have an experiment! ExportFCS.export() # raises CytoflowViewErrors, so it should be compatible with the # existing error reporting stuff. if self.path: self.export(experiment) return # otherwise, make a table showing what will be exported num_cols = len(self.by) + 2 fig = plt.figure() ax = fig.add_subplot(111) # hide the plot axes that matplotlib tries to make ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) for sp in ax.spines.values(): sp.set_color('w') sp.set_zorder(0) loc = 'upper left' bbox = None t = Table(ax, loc, bbox) t.auto_set_font_size(False) for c in range(num_cols): t.auto_set_column_width(c) width = [0.2] * num_cols height = t._approx_text_height() * 1.8 t.add_cell(0, 0, width=width[0], height=height, text="#") for ci, c in enumerate(self.by): ci = ci + 1 t.add_cell(0, ci, width=width[ci], height=height, text=c) ci = len(self.by) + 1 t.add_cell(0, ci, width=width[ci], height=height, text="Filename") # ci = len(self.by) + 2 # t.add_cell(0, ci, width = width[ci], height = height, text = "Events") for ri, row in enumerate(self.enum_conditions_and_files(experiment)): t.add_cell(ri + 1, 0, width=width[0], height=height, text="{:g}".format(ri + 1)) for ci, col in enumerate(row): t.add_cell(ri + 1, ci + 1, width=width[ci + 1], height=height, text=col) ax.add_table(t)