def plot(self, experiment, **kwargs): """Plot a bar chart""" if not experiment: raise util.CytoflowViewError("No experiment specified") if not self.variable: raise util.CytoflowViewError("variable not set") if self.variable not in experiment.conditions: raise util.CytoflowViewError("variable {0} not in the experiment" .format(self.variable)) if not (experiment.conditions[self.variable] == "float" or experiment.conditions[self.variable] == "int"): raise util.CytoflowViewError("variable {0} isn't numeric" .format(self.variable)) if not self.xchannel: raise util.CytoflowViewError("X channel isn't set.") if self.xchannel not in experiment.data: raise util.CytoflowViewError("X channel {0} isn't in the experiment" .format(self.xchannel)) if not self.xfunction: raise util.CytoflowViewError("X summary function isn't set") if not self.ychannel: raise util.CytoflowViewError("Y channel isn't set.") if self.ychannel not in experiment.data: raise util.CytoflowViewError("Y channel {0} isn't in the experiment" .format(self.ychannel)) if not self.yfunction: raise util.CytoflowViewError("Y summary function isn't set") if self.xfacet and self.xfacet not in experiment.conditions: raise util.CytoflowViewError("X facet {0} not in the experiment") if self.yfacet and self.yfacet not in experiment.conditions: raise util.CytoflowViewError("Y facet {0} not in the experiment") if self.huefacet and self.huefacet not in experiment.metadata: raise util.CytoflowViewError("Hue facet {0} not in the experiment") if self.x_error_bars and self.x_error_bars != 'data' \ and self.x_error_bars not in experiment.conditions: raise util.CytoflowViewError("x_error_bars must be either 'data' or " "a condition in the experiment") if self.x_error_bars and not self.x_error_function: raise util.CytoflowViewError("didn't set an x error function") if self.y_error_bars and self.y_error_bars != 'data' \ and self.y_error_bars not in experiment.conditions: raise util.CytoflowViewError("y_error_bars must be either 'data' or " "a condition in the experiment") if self.y_error_bars and not self.y_error_function: raise util.CytoflowViewError("didn't set an error function") kwargs.setdefault('antialiased', True) 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 = [self.variable] if self.xfacet: group_vars.append(self.xfacet) if self.yfacet: group_vars.append(self.yfacet) if self.huefacet: group_vars.append(self.huefacet) g = data.groupby(by = group_vars) plot_data = pd.DataFrame( {self.xchannel : g[self.xchannel].aggregate(self.xfunction), self.ychannel : g[self.ychannel].aggregate(self.yfunction)}) \ .reset_index() # compute the x error statistic if self.x_error_bars: if self.x_error_bars == 'data': # compute the error statistic on the same subsets as the summary # statistic error_stat = g[self.xchannel].aggregate(self.x_error_function).reset_index() else: # subdivide the data set further by the error_bars condition err_vars = list(group_vars) err_vars.append(self.x_error_bars) # apply the summary statistic to each subgroup data_g = data.groupby(by = err_vars) data_stat = data_g[self.xchannel].aggregate(self.xfunction).reset_index() # apply the error function to the summary statistics err_g = data_stat.groupby(by = group_vars) error_stat = err_g[self.xchannel].aggregate(self.x_error_function).reset_index() x_err_name = util.random_string(6) plot_data[x_err_name] = error_stat[self.xchannel] # compute the y error statistic if self.y_error_bars: if self.y_error_bars == 'data': # compute the error statistic on the same subsets as the summary # statistic error_stat = g[self.ychannel].aggregate(self.y_error_function).reset_index() else: # subdivide the data set further by the error_bars condition err_vars = list(group_vars) err_vars.append(self.y_error_bars) # apply the summary statistic to each subgroup data_g = data.groupby(by = err_vars) data_stat = data_g[self.ychannel].aggregate(self.yfunction).reset_index() # apply the error function to the summary statistics err_g = data_stat.groupby(by = group_vars) error_stat = err_g[self.ychannel].aggregate(self.y_error_function).reset_index() y_err_name = util.random_string(6) plot_data[y_err_name] = error_stat[self.ychannel] grid = sns.FacetGrid(plot_data, size = 6, aspect = 1.5, col = (self.xfacet if self.xfacet else None), row = (self.yfacet if self.yfacet else None), hue = (self.huefacet if self.huefacet else None), col_order = (np.sort(data[self.xfacet].unique()) if self.xfacet else None), row_order = (np.sort(data[self.yfacet].unique()) if self.yfacet else None), hue_order = (np.sort(data[self.huefacet].unique()) if self.huefacet else None), legend_out = False, sharex = False, sharey = False) xscale = util.scale_factory(self.xscale, experiment, self.xchannel) yscale = util.scale_factory(self.yscale, experiment, self.ychannel) for ax in grid.axes.flatten(): ax.set_xscale(self.xscale, **xscale.mpl_params) ax.set_yscale(self.yscale, **yscale.mpl_params) # plot the error bars first so the axis labels don't get overwritten if self.x_error_bars: grid.map(_x_error_bars, self.xchannel, x_err_name, self.ychannel) if self.y_error_bars: grid.map(_y_error_bars, self.xchannel, self.ychannel, y_err_name) grid.map(plt.plot, self.xchannel, self.ychannel, **kwargs) # if we have a hue facet and a lot of hues, make a color bar instead # of a super-long legend. if self.huefacet: current_palette = mpl.rcParams['axes.color_cycle'] if len(grid.hue_names) > len(current_palette): plot_ax = plt.gca() cmap = mpl.colors.ListedColormap(sns.color_palette("husl", n_colors = len(grid.hue_names))) cax, _ = mpl.colorbar.make_axes(plt.gca()) norm = mpl.colors.Normalize(vmin = np.min(grid.hue_names), vmax = np.max(grid.hue_names), clip = False) mpl.colorbar.ColorbarBase(cax, cmap = cmap, norm = norm, label = self.huefacet) plt.sca(plot_ax) else: grid.add_legend(title = self.huefacet)
def plot(self, experiment, plot_name=None, **kwargs): """Plot a bar chart""" if not experiment: raise util.CytoflowViewError("No experiment specified") if not self.variable: raise util.CytoflowViewError("variable not set") if self.variable not in experiment.conditions: raise util.CytoflowViewError( "variable {0} not in the experiment".format(self.variable)) if not self.xstatistic: raise util.CytoflowViewError("X statistic not set") if self.xstatistic not in experiment.statistics: raise util.CytoflowViewError( "Can't find X statistic {} in experiment".format( self.ystatistic)) else: xstat = experiment.statistics[self.xstatistic] if not self.ystatistic: raise util.CytoflowViewError("Y statistic not set") if self.ystatistic not in experiment.statistics: raise util.CytoflowViewError( "Can't find Y statistic {} in experiment".format( self.ystatistic)) else: ystat = experiment.statistics[self.ystatistic] if not xstat.index.equals(ystat.index): raise util.CytoflowViewError( "X statistic and Y statistic must have " "the same indices: {}".format(xstat.index.names)) if self.x_error_statistic[0]: if self.x_error_statistic not in experiment.statistics: raise util.CytoflowViewError( "X error statistic not in experiment") else: x_error_stat = experiment.statistics[self.x_error_statistic] if not x_error_stat.index.equals(xstat.index): raise util.CytoflowViewError( "X error statistic doesn't have the " "same indices as the X statistic") else: x_error_stat = None if self.y_error_statistic[0]: if self.y_error_statistic not in experiment.statistics: raise util.CytoflowViewError( "Y error statistic not in experiment") else: y_error_stat = experiment.statistics[self.y_error_statistic] if not y_error_stat.index.equals(ystat.index): raise util.CytoflowViewError( "Y error statistic doesn't have the " "same indices as the Y statistic") else: y_error_stat = None col_wrap = kwargs.pop('col_wrap', None) if col_wrap and self.yfacet: raise util.CytoflowViewError( "Can't set yfacet and col_wrap at the same time.") data = pd.DataFrame(index=xstat.index) xname = util.random_string(6) data[xname] = xstat yname = util.random_string(6) data[yname] = ystat if x_error_stat is not None: #x_error_data = x_error_stat.reset_index() x_error_name = util.random_string(6) data[x_error_name] = x_error_stat if y_error_stat is not None: y_error_name = util.random_string(6) data[y_error_name] = y_error_stat if y_error_stat is not None: y_error_data = y_error_stat.reset_index() y_error_name = util.random_string() data[y_error_name] = y_error_data[y_error_stat.name] if self.subset: try: # TODO - either sanitize column names, or check to see that # all conditions are valid Python variables data = data.query(self.subset) except: raise util.CytoflowViewError( "Subset string '{0}' isn't valid".format(self.subset)) if len(data) == 0: raise util.CytoflowViewError( "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: raise util.CytoflowViewError("Must have more than one " "value to plot.") names = list(data.index.names) if not self.variable in experiment.conditions: raise util.CytoflowViewError( "Variable {} not in experiment".format(self.variable)) if not self.variable in data.index.names: raise util.CytoflowViewError( "Variable {} not in statistic; must be one of {}".format( self.variable, data.index.names)) if self.xfacet and self.xfacet not in experiment.conditions: raise util.CytoflowViewError( "X facet {} not in the experiment".format(self.xfacet)) if self.xfacet and self.xfacet not in data.index.names: raise util.CytoflowViewError( "X facet {} not in statistics; must be one of {}".format( self.xfacet, data.index.names)) if self.yfacet and self.yfacet not in experiment.conditions: raise util.CytoflowViewError( "Y facet {} not in the experiment".format(self.yfacet)) if self.yfacet and self.yfacet not in data.index.names: raise util.CytoflowViewError( "Y facet {} not in statistics; must be one of {}".format( self.yfacet, data.index.names)) if self.huefacet and self.huefacet not in experiment.metadata: raise util.CytoflowViewError( "Hue facet {} not in the experiment".format(self.huefacet)) if self.huefacet and self.huefacet not in data.index.names: raise util.CytoflowViewError( "Hue facet {} not in statistics; must be one of {}".format( self.huefacet, data.index.names)) col_wrap = kwargs.pop('col_wrap', None) if col_wrap and self.yfacet: raise util.CytoflowViewError( "Can't set yfacet and col_wrap at the same time.") if col_wrap and not self.xfacet: raise util.CytoflowViewError("Must set xfacet to use col_wrap.") facets = filter( lambda x: x, [self.variable, self.xfacet, self.yfacet, self.huefacet]) if len(facets) != len(set(facets)): raise util.CytoflowViewError("Can't reuse facets") unused_names = list(set(names) - set(facets)) if plot_name is not None and not unused_names: raise util.CytoflowViewError("You specified a plot name, but all " "the facets are already used") data.reset_index(inplace=True) if unused_names: groupby = data.groupby(unused_names) if plot_name is None: raise util.CytoflowViewError( "You must use facets {} in either the " "plot variables or the plot name. " "Possible plot names: {}".format(unused_names, groupby.groups.keys())) if plot_name not in set(groupby.groups.keys()): raise util.CytoflowViewError( "Plot {} not from plot_enum; must " "be one of {}".format(plot_name, groupby.groups.keys())) data = groupby.get_group(plot_name) if self.x_error_statistic is not None: xscale = util.scale_factory(self.xscale, experiment, statistic=self.xstatistic) else: xscale = util.scale_factory(self.xscale, experiment, statistic=self.x_error_statistic) if self.y_error_statistic is not None: yscale = util.scale_factory(self.yscale, experiment, statistic=self.ystatistic) else: yscale = util.scale_factory(self.yscale, experiment, statistic=self.y_error_statistic) xlim = kwargs.pop("xlim", None) if xlim is None: xlim = (xscale.clip(data[xname].min() * 0.9), xscale.clip(data[xname].max() * 1.1)) if x_error_stat is not None: try: xlim = (xscale.clip( min([x[0] for x in x_error_stat]) * 0.9), xscale.clip( max([x[1] for x in x_error_stat]) * 1.1)) except IndexError: xlim = (xscale.clip(x_error_stat.min() * 0.9), xscale.clip(x_error_stat.max() * 1.1)) ylim = kwargs.pop("ylim", None) if ylim is None: ylim = (yscale.clip(data[yname].min() * 0.9), yscale.clip(data[yname].max() * 1.1)) if y_error_stat is not None: try: ylim = (yscale.clip( min([x[0] for x in y_error_stat]) * 0.9), yscale.clip( max([x[1] for x in y_error_stat]) * 1.1)) except IndexError: ylim = (yscale.clip(y_error_stat.min() * 0.9), yscale.clip(y_error_stat.max() * 1.1)) kwargs.setdefault('antialiased', True) cols = col_wrap if col_wrap else \ len(data[self.xfacet].unique()) if self.xfacet else 1 sharex = kwargs.pop('sharex', True) sharey = kwargs.pop('sharey', True) grid = sns.FacetGrid(data, size=(6 / cols), aspect=1.5, col=(self.xfacet if self.xfacet else None), row=(self.yfacet if self.yfacet else None), hue=(self.huefacet if self.huefacet else None), col_order=(np.sort(data[self.xfacet].unique()) if self.xfacet else None), row_order=(np.sort(data[self.yfacet].unique()) if self.yfacet else None), hue_order=(np.sort(data[self.huefacet].unique()) if self.huefacet else None), col_wrap=col_wrap, legend_out=False, sharex=sharex, sharey=sharey, xlim=xlim, ylim=ylim) for ax in grid.axes.flatten(): ax.set_xscale(self.xscale, **xscale.mpl_params) ax.set_yscale(self.yscale, **yscale.mpl_params) # plot the error bars first so the axis labels don't get overwritten if x_error_stat: grid.map(_x_error_bars, xname, yname, x_error_name) if y_error_stat: grid.map(_y_error_bars, xname, yname, y_error_name) grid.map(plt.plot, xname, yname, **kwargs) # if we have an xfacet, make sure the y scale is the same for each fig = plt.gcf() fig_y_min = float("inf") fig_y_max = float("-inf") for ax in fig.get_axes(): ax_y_min, ax_y_max = ax.get_ylim() if ax_y_min < fig_y_min: fig_y_min = ax_y_min if ax_y_max > fig_y_max: fig_y_max = ax_y_max for ax in fig.get_axes(): ax.set_ylim(fig_y_min, fig_y_max) # if we have a yfacet, make sure the x scale is the same for each fig = plt.gcf() fig_x_min = float("inf") fig_x_max = float("-inf") for ax in fig.get_axes(): ax_x_min, ax_x_max = ax.get_xlim() if ax_x_min < fig_x_min: fig_x_min = ax_x_min if ax_x_max > fig_x_max: fig_x_max = ax_x_max # if we have a hue facet and a lot of hues, make a color bar instead # of a super-long legend. if self.huefacet: current_palette = mpl.rcParams['axes.color_cycle'] if util.is_numeric(experiment.data[self.huefacet]) and \ len(grid.hue_names) > len(current_palette): plot_ax = plt.gca() cmap = mpl.colors.ListedColormap( sns.color_palette("husl", n_colors=len(grid.hue_names))) cax, _ = mpl.colorbar.make_axes(plt.gca()) hue_scale = util.scale_factory(self.huescale, experiment, condition=self.huefacet) mpl.colorbar.ColorbarBase(cax, cmap=cmap, norm=hue_scale.color_norm(), label=self.huefacet) plt.sca(plot_ax) else: grid.add_legend(title=self.huefacet) plt.xlabel(self.xstatistic) plt.ylabel(self.ystatistic) if unused_names and plot_name is not None: plt.title("{0} = {1}".format(unused_names, plot_name))
def plot(self, experiment, plot_name=None, **kwargs): """Plot a bar chart""" if not experiment: raise util.CytoflowViewError("No experiment specified") if self.statistic not in experiment.statistics: raise util.CytoflowViewError( "Can't find the statistic {} in the experiment".format( self.statistic)) else: stat = experiment.statistics[self.statistic] if self.error_statistic[0]: if self.error_statistic not in experiment.statistics: raise util.CytoflowViewError( "Can't find the error statistic in the experiment") else: error_stat = experiment.statistics[self.error_statistic] else: error_stat = None if error_stat is not None: if not stat.index.equals(error_stat.index): raise util.CytoflowViewError( "Data statistic and error statistic " " don't have the same index.") data = pd.DataFrame(index=stat.index) data[stat.name] = stat if error_stat is not None: error_name = util.random_string(6) data[error_name] = error_stat else: error_name = None if self.subset: try: data = data.query(self.subset) except: raise util.CytoflowViewError( "Subset string '{0}' isn't valid".format(self.subset)) if len(data) == 0: raise util.CytoflowViewError( "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: raise util.CytoflowViewError("Must have more than one " "value to plot.") names = list(data.index.names) if not self.variable: raise util.CytoflowViewError("variable not specified") if not self.variable in names: raise util.CytoflowViewError("Variable {} isn't in the statistic; " "must be one of {}".format( self.variable, names)) if self.xfacet and self.xfacet not in experiment.conditions: raise util.CytoflowViewError( "X facet {0} isn't in the experiment".format(self.xfacet)) if self.xfacet and self.xfacet not in names: raise util.CytoflowViewError( "X facet {} is not a statistic index; " "must be one of {}".format(self.xfacet, names)) if self.yfacet and self.yfacet not in experiment.conditions: raise util.CytoflowViewError( "Y facet {0} isn't in the experiment".format(self.yfacet)) if self.yfacet and self.yfacet not in names: raise util.CytoflowViewError( "Y facet {} is not a statistic index; " "must be one of {}".format(self.yfacet, names)) if self.huefacet and self.huefacet not in experiment.conditions: raise util.CytoflowViewError( "Hue facet {0} isn't in the experiment".format(self.huefacet)) if self.huefacet and self.huefacet not in names: raise util.CytoflowViewError( "Hue facet {} is not a statistic index; " "must be one of {}".format(self.huefacet, names)) col_wrap = kwargs.pop('col_wrap', None) if col_wrap and self.yfacet: raise util.CytoflowViewError( "Can't set yfacet and col_wrap at the same time.") if col_wrap and not self.xfacet: raise util.CytoflowViewError("Must set xfacet to use col_wrap.") facets = filter( lambda x: x, [self.variable, self.xfacet, self.yfacet, self.huefacet]) if len(facets) != len(set(facets)): raise util.CytoflowViewError("Can't reuse facets") unused_names = list(set(names) - set(facets)) if plot_name is not None and not unused_names: raise util.CytoflowViewError("You specified a plot name, but all " "the facets are already used") data.reset_index(inplace=True) if unused_names: groupby = data.groupby(unused_names) if plot_name is None: raise util.CytoflowViewError( "You must use facets {} in either the " "plot variables or the plot name. " "Possible plot names: {}".format(unused_names, groupby.groups.keys())) if plot_name not in set(groupby.groups.keys()): raise util.CytoflowViewError( "Plot {} not from plot_enum; must " "be one of {}".format(plot_name, groupby.groups.keys())) data = groupby.get_group(plot_name) sharex = kwargs.pop('sharex', True) sharey = kwargs.pop('sharey', True) cols = col_wrap if col_wrap else \ len(data[self.xfacet].unique()) if self.xfacet else 1 g = sns.FacetGrid(data, size=(6 / cols), aspect=1.5, col=(self.xfacet if self.xfacet else None), row=(self.yfacet if self.yfacet else None), col_order=(np.sort(data[self.xfacet].unique()) if self.xfacet else None), row_order=(np.sort(data[self.yfacet].unique()) if self.yfacet else None), col_wrap=col_wrap, legend_out=False, sharex=sharex, sharey=sharey) scale = util.scale_factory(self.scale, experiment, statistic=self.statistic) # because the bottom of a bar chart is "0", masking out bad # values on a log scale doesn't work. we must clip instead. if self.scale == "log": scale.mode = "clip" # set the scale for each set of axes; can't just call plt.xscale() for ax in g.axes.flatten(): if self.orientation == 'horizontal': ax.set_xscale(self.scale, **scale.mpl_params) else: ax.set_yscale(self.scale, **scale.mpl_params) map_args = [self.variable, stat.name] if self.huefacet: map_args.append(self.huefacet) if error_stat is not None: map_args.append(error_name) g.map(_barplot, *map_args, view=self, stat_name=stat.name, error_name=error_name, **kwargs) if sharex: # if are sharing axes make sure the x scale is the same for each fig = plt.gcf() fig_x_min = float("inf") fig_x_max = float("-inf") for ax in fig.get_axes(): ax_x_min, ax_x_max = ax.get_xlim() if ax_x_min < fig_x_min: fig_x_min = ax_x_min if ax_x_max > fig_x_max: fig_x_max = ax_x_max for ax in fig.get_axes(): ax.set_xlim(fig_x_min, fig_x_max) if sharey: # if we are sharing y axes, make sure the y scale is the same for each fig = plt.gcf() fig_y_min = float("inf") fig_y_max = float("-inf") for ax in fig.get_axes(): ax_y_min, ax_y_max = ax.get_ylim() if ax_y_min < fig_y_min: fig_y_min = ax_y_min if ax_y_max > fig_y_max: fig_y_max = ax_y_max for ax in fig.get_axes(): ax.set_ylim(fig_y_min, fig_y_max) if self.huefacet: labels = np.sort(data[self.huefacet].unique()) labels = [str(x) for x in labels] g.add_legend(title=self.huefacet, label_order=labels) if self.orientation == 'horizontal': plt.sca(fig.get_axes()[0]) plt.xlabel(self.statistic) else: plt.sca(fig.get_axes()[0]) plt.ylabel(self.statistic) if unused_names and plot_name is not None: plt.title("{0} = {1}".format(unused_names, plot_name))
def enum_plots(self, experiment): """ Returns an iterator over the possible plots that this View can produce. The values returned can be passed to "plot". """ # TODO - all this is copied from below. can we abstract it out somehow? if not experiment: raise util.CytoflowViewError("No experiment specified") if not self.variable: raise util.CytoflowViewError("variable not set") if self.variable not in experiment.conditions: raise util.CytoflowViewError( "variable {0} not in the experiment".format(self.variable)) if not self.xstatistic: raise util.CytoflowViewError("X statistic not set") if self.xstatistic not in experiment.statistics: raise util.CytoflowViewError( "Can't find X statistic {} in experiment".format( self.ystatistic)) else: xstat = experiment.statistics[self.xstatistic] if not self.ystatistic: raise util.CytoflowViewError("Y statistic not set") if self.ystatistic not in experiment.statistics: raise util.CytoflowViewError( "Can't find Y statistic {} in experiment".format( self.ystatistic)) else: ystat = experiment.statistics[self.ystatistic] if not xstat.index.equals(ystat.index): raise util.CytoflowViewError( "X statistic and Y statistic must have " "the same indices: {}".format(xstat.index.names)) if self.x_error_statistic[0]: if self.x_error_statistic not in experiment.statistics: raise util.CytoflowViewError( "X error statistic not in experiment") else: x_error_stat = experiment.statistics[self.x_error_statistic] if not x_error_stat.index.equals(xstat.index): raise util.CytoflowViewError( "X error statistic doesn't have the " "same indices as the X statistic") else: x_error_stat = None if self.y_error_statistic[0]: if self.y_error_statistic not in experiment.statistics: raise util.CytoflowViewError( "Y error statistic not in experiment") else: y_error_stat = experiment.statistics[self.y_error_statistic] if not y_error_stat.index.equals(ystat.index): raise util.CytoflowViewError( "Y error statistic doesn't have the " "same indices as the Y statistic") else: y_error_stat = None data = pd.DataFrame(index=xstat.index) xname = util.random_string(6) data[xname] = xstat yname = util.random_string(6) data[yname] = ystat if x_error_stat is not None: #x_error_data = x_error_stat.reset_index() x_error_name = util.random_string(6) data[x_error_name] = x_error_stat if y_error_stat is not None: y_error_name = util.random_string(6) data[y_error_name] = y_error_stat if y_error_stat is not None: y_error_data = y_error_stat.reset_index() y_error_name = util.random_string() data[y_error_name] = y_error_data[y_error_stat.name] if self.subset: try: # TODO - either sanitize column names, or check to see that # all conditions are valid Python variables data = data.query(self.subset) except: raise util.CytoflowViewError( "Subset string '{0}' isn't valid".format(self.subset)) if len(data) == 0: raise util.CytoflowViewError( "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: raise util.CytoflowViewError("Must have more than one " "value to plot.") names = list(data.index.names) if not self.variable in experiment.conditions: raise util.CytoflowViewError( "Variable {} not in experiment".format(self.variable)) if not self.variable in data.index.names: raise util.CytoflowViewError( "Variable {} not in statistic; must be one of {}".format( self.variable, data.index.names)) if self.xfacet and self.xfacet not in experiment.conditions: raise util.CytoflowViewError( "X facet {} not in the experiment".format(self.xfacet)) if self.xfacet and self.xfacet not in data.index.names: raise util.CytoflowViewError( "X facet {} not in statistics; must be one of {}".format( self.xfacet, data.index.names)) if self.yfacet and self.yfacet not in experiment.conditions: raise util.CytoflowViewError( "Y facet {} not in the experiment".format(self.yfacet)) if self.yfacet and self.yfacet not in data.index.names: raise util.CytoflowViewError( "Y facet {} not in statistics; must be one of {}".format( self.yfacet, data.index.names)) if self.huefacet and self.huefacet not in experiment.metadata: raise util.CytoflowViewError( "Hue facet {} not in the experiment".format(self.huefacet)) if self.huefacet and self.huefacet not in data.index.names: raise util.CytoflowViewError( "Hue facet {} not in statistics; must be one of {}".format( self.huefacet, data.index.names)) facets = filter( lambda x: x, [self.variable, self.xfacet, self.yfacet, self.huefacet]) if len(facets) != len(set(facets)): raise util.CytoflowViewError("Can't reuse facets") by = list(set(names) - set(facets)) class plot_enum(object): def __init__(self, experiment, by): self._iter = None self._returned = False if by: self._iter = experiment.data.groupby(by).__iter__() def __iter__(self): return self def next(self): if self._iter: return self._iter.next()[0] else: if self._returned: raise StopIteration else: self._returned = True return None return plot_enum(experiment, by)
def enum_plots(self, experiment): """ Returns an iterator over the possible plots that this View can produce. The values returned can be passed to "plot". """ # TODO - all this is copied from below. can we abstract it out somehow? if not experiment: raise util.CytoflowViewError("No experiment specified") if self.statistic not in experiment.statistics: raise util.CytoflowViewError( "Can't find the statistic {} in the experiment".format( self.statistic)) else: stat = experiment.statistics[self.statistic] if self.error_statistic[0]: if self.error_statistic not in experiment.statistics: raise util.CytoflowViewError( "Can't find the error statistic in the experiment") else: error_stat = experiment.statistics[self.error_statistic] else: error_stat = None if error_stat is not None: if not stat.index.equals(error_stat.index): raise util.CytoflowViewError( "Data statistic and error statistic " " don't have the same index.") data = pd.DataFrame(index=stat.index) data[stat.name] = stat if error_stat is not None: error_name = util.random_string(6) data[error_name] = error_stat else: error_name = None if self.subset: try: data = data.query(self.subset) except: raise util.CytoflowViewError( "Subset string '{0}' isn't valid".format(self.subset)) if len(data) == 0: raise util.CytoflowViewError( "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: raise util.CytoflowViewError("Must have more than one " "value to plot.") names = list(data.index.names) if not self.variable: raise util.CytoflowViewError("variable not specified") if not self.variable in data.index.names: raise util.CytoflowViewError("Variable {} isn't in the statistic; " "must be one of {}".format( self.variable, data.index.names)) if self.xfacet and self.xfacet not in experiment.conditions: raise util.CytoflowViewError( "X facet {0} isn't in the experiment".format(self.xfacet)) if self.xfacet and self.xfacet not in data.index.names: raise util.CytoflowViewError( "X facet {} is not a statistic index; " "must be one of {}".format(self.xfacet, data.index.names)) if self.yfacet and self.yfacet not in experiment.conditions: raise util.CytoflowViewError( "Y facet {0} isn't in the experiment".format(self.yfacet)) if self.yfacet and self.yfacet not in data.index.names: raise util.CytoflowViewError( "Y facet {} is not a statistic index; " "must be one of {}".format(self.yfacet, data.index.names)) if self.huefacet and self.huefacet not in experiment.conditions: raise util.CytoflowViewError( "Hue facet {0} isn't in the experiment".format(self.huefacet)) if self.huefacet and self.huefacet not in data.index.names: raise util.CytoflowViewError( "Hue facet {} is not a statistic index; " "must be one of {}".format(self.huefacet, data.index.names)) facets = filter( lambda x: x, [self.variable, self.xfacet, self.yfacet, self.huefacet]) if len(facets) != len(set(facets)): raise util.CytoflowViewError("Can't reuse facets") by = list(set(names) - set(facets)) class plot_enum(object): def __init__(self, experiment, by): self._iter = None self._returned = False if by: self._iter = experiment.data.groupby(by).__iter__() def __iter__(self): return self def next(self): if self._iter: return self._iter.next()[0] else: if self._returned: raise StopIteration else: self._returned = True return None return plot_enum(experiment, by)