diff --git a/workflows/gobrowser.py b/workflows/gobrowser.py index 40a7bc6..37c48ff 100644 --- a/workflows/gobrowser.py +++ b/workflows/gobrowser.py @@ -491,7 +491,7 @@ class PlotDagFunction(workflow.Function): ds = dataset.GraphDataset(networkx.adj_matrix(g), [('go-terms', g.nodes()), ('_go-terms', g.nodes())], name="DAG") - return [DagPlot(g)] + return [ThresholdDagPlot(g)] def get_network(self, terms, subtree='bp'): """Returns a DAG connecting the given terms by including their parents @@ -558,13 +558,117 @@ class VolcanoPlot(plots.ScatterPlot): name="Volcano plot", sel_dim_2='_p', **kw) - + +class PlotThresholder: + """Mixin class for plots that needs to filter nodes within a threshold + range. + """ + def __init__(self, text="x"): + """Constructor. + + @param text: Name of the variable the threshold is on. + """ + self._threshold_ds = None + self._add_spin_buttons(text) + self._sb_min.set_sensitive(False) + self._sb_max.set_sensitive(False) + + def set_threshold_dataset(self, ds): + """Sets the dataset to threshold on. + + @param ds: A dataset where one dimension corresponds to the select dimension + in the plot, and any other dimensions have length 1 + """ + self._threshold_ds = ds + self._sb_min.set_sensitive(True) + self._sb_max.set_sensitive(True) + + def _add_spin_buttons(self, text): + """Adds spin buttons to the toolbar for selecting minimum and maximum + threshold values on information content.""" + sb_min = gtk.SpinButton(digits=2) + sb_min.set_range(0, 100) + sb_min.set_value(0) + sb_min.set_increments(.1, 1.) + sb_min.connect('value-changed', self._on_value_changed) + self._sb_min = sb_min + + sb_max = gtk.SpinButton(digits=2) + sb_max.set_range(0, 100) + sb_max.set_value(1) + sb_max.set_increments(.1, 1.) + sb_max.connect('value-changed', self._on_value_changed) + self._sb_max = sb_max + + label = gtk.Label(" < %s < " % text) + hbox = gtk.HBox() + hbox.pack_start(sb_min) + hbox.pack_start(label) + hbox.pack_start(sb_max) + ti = gtk.ToolItem() + ti.set_expand(False) + ti.add(hbox) + sb_min.show() + sb_max.show() + label.show() + hbox.show() + ti.show() + self._toolbar.insert(ti, -1) + ti.set_tooltip(self._toolbar.tooltips, "Set threshold") + + def set_threshold(self, min, max): + """Sets min and max to the given values. + Updates the plot accordingly to show only values that have a + value within the boundaries. Other values are + also excluded from being selected from the plot. + @param ic_min Do not show nodes with IC below this value. + @param ic_max Do not show nodes with IC above this value. + """ + ds = self._threshold_ds + if ds == None: + return + + icnodes = ds.existing_identifiers('go-terms', self.nodes) + icindices = ds.get_indices('go-terms', icnodes) + a = ravel(ds.asarray()[icindices]) + good = set(array(icnodes)[(a>=min) & (a<=max)]) + + sizes = zeros(len(self.nodes)) + visible = set() + for i, n in enumerate(self.nodes): + if n in good: + sizes[i] = 50 + visible.add(n) + else: + sizes[i] = 0 + self.visible = visible + + self.node_collection._sizes = sizes + self.canvas.draw() + + def get_nodes_within_bounds(self): + """Get a list of all nodes within the bounds of the selection in the + seleted dataset. + """ + pass + + def filter_nodes(self, nodes): + """Filter a list of nodes and return only those that are within the + threshold boundaries.""" + pass + + def _on_value_changed(self, sb): + """Callback on spin button value changes.""" + min = self._sb_min.get_value() + max = self._sb_max.get_value() + self.set_threshold(min, max) + + class DagPlot(plots.Plot): def __init__(self, graph, dim='go-terms', pos=None, nodecolor='b', nodesize=40, with_labels=False, name='DAG Plot'): plots.Plot.__init__(self, name) - self._add_ic_spin_buttons() self.nodes = graph.nodes() self.graph = graph self._pos = pos @@ -630,39 +734,6 @@ class DagPlot(plots.Plot): self.axes.set_frame_on(False) self.fig.subplots_adjust(left=0, right=1, bottom=0, top=1) - def _add_ic_spin_buttons(self): - """Adds spin buttons to the toolbar for selecting minimum and maximum - threshold values on information content.""" - sb_min = gtk.SpinButton(digits=2) - sb_min.set_range(0, 100) - sb_min.set_value(0) - sb_min.set_increments(.1, 1.) - sb_min.connect('value-changed', self._on_ic_value_changed) - self._ic_sb_min = sb_min - - sb_max = gtk.SpinButton(digits=2) - sb_max.set_range(0, 100) - sb_max.set_value(1) - sb_max.set_increments(.1, 1.) - sb_max.connect('value-changed', self._on_ic_value_changed) - self._ic_sb_max = sb_max - - label = gtk.Label(" < IC < ") - hbox = gtk.HBox() - hbox.pack_start(sb_min) - hbox.pack_start(label) - hbox.pack_start(sb_max) - ti = gtk.ToolItem() - ti.set_expand(False) - ti.add(hbox) - sb_min.show() - sb_max.show() - label.show() - hbox.show() - ti.show() - self._toolbar.insert(ti, -1) - ti.set_tooltip(self._toolbar.tooltips, "Set information content threshold") - def _calc_pos(self, graph): """Calculates position for graph nodes using 'dot' layout.""" gv_graph = networkx.DiGraph() @@ -678,44 +749,7 @@ class DagPlot(plots.Plot): pos[k] = v return pos - def set_ic_threshold(self, ic_min, ic_max): - """Sets Information Content min and max to the given values. - Updates the plot accordingly to show only values that have an - information content within the boundaries. Other values are - also excluded from being selected from the plot. - @param ic_min Do not show nodes with IC below this value. - @param ic_max Do not show nodes with IC above this value. - """ - ic = getattr(main.workflow, 'current_ic', None) - if ic == None: - print "no ic set" - return - - icnodes = ic.existing_identifiers('go-terms', self.nodes) - icindices = ic.get_indices('go-terms', icnodes) - a = ravel(ic.asarray()[icindices]) - ic_good = set(array(icnodes)[(a>=ic_min) & (a<=ic_max)]) - - sizes = zeros(len(self.nodes)) - visible = set() - for i, n in enumerate(self.nodes): - if n in ic_good: - sizes[i] = 50 - visible.add(n) - else: - sizes[i] = 0 - self.visible = visible - - self.node_collection._sizes = sizes - self.canvas.draw() - - def _on_ic_value_changed(self, sb): - """Callback on spin button value changes.""" - ic_min = self._ic_sb_min.get_value() - ic_max = self._ic_sb_max.get_value() - self.set_ic_threshold(ic_min, ic_max) - - def rectangle_select_callback(self, x1, y1, x2, y2, key): + def points_in_rect(self, x1, y1, x2, y2, key): ydata = self.yaxis_data xdata = self.xaxis_data @@ -732,7 +766,12 @@ class DagPlot(plots.Plot): ids = self.visible.intersection([self.nodes[i] for i in index]) else: ids = set([self.nodes[i] for i in index]) + return ids + + def rectangle_select_callback(self, x1, y1, x2, y2, key): + ids = self.points_in_rect(x1, y1, x2, y2, key) ids = self.update_selection(ids, key) + self.selection_listener(self.current_dim, ids) def lasso_select_callback(self, verts, key=None): @@ -807,9 +846,34 @@ class DagPlot(plots.Plot): self.node_collection.set_array(map_vec) self.node_collection.set_clim(vec_min, vec_max) self.node_collection.update_scalarmappable() #sets facecolors from array - self._ic_sb_min.set_range(0, vec_max) - self._ic_sb_min.set_value(vec_min) - self._ic_sb_max.set_range(0, vec_max) - self._ic_sb_max.set_value(vec_max) self.canvas.draw() + + +class ThresholdDagPlot(DagPlot, PlotThresholder): + def __init__(self, graph, dim='go-terms', pos=None, nodecolor='b', nodesize=40, + with_labels=False, name='DAG Plot'): + DagPlot.__init__(self, graph, dim='go-terms', pos=None, + nodecolor='b', nodesize=40, + with_labels=False, name='DAG Plot') + PlotThresholder.__init__(self, "IC") + + def rectangle_select_callback(self, x1, y1, x2, y2, key): + ids = self.points_in_rect(x1, y1, x2, y2, key) + ids = self.visible.intersection(ids) + ids = self.update_selection(ids, key) + + self.selection_listener(self.current_dim, ids) + + def _update_color_from_dataset(self, ds): + DagPlot._update_color_from_dataset(self, ds) + self.set_threshold_dataset(ds) + a = ds.asarray() + a_max = max(a[a-inf]) + self._sb_min.set_range(0, a_max) + self._sb_min.set_value(a_min) + self._sb_max.set_range(0, a_max) + self._sb_max.set_value(a_max) + +