Beispiel #1
0
    def __init__(self, database=None, parent=None, app=None, minima=None):
        QWidget.__init__(self, parent=parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.database = database
        self.minima = minima
        self.app = app

        self.canvas = self.ui.canvas.canvas

        self.axes = self.canvas.axes
        self.fig = self.canvas.fig

        self.on_minima_picked = Signal()

        self.from_minima = set()
        self.positions = dict()
        self.boundary_nodes = set()

        self._selected_minimum = None
        self._mpl_cid = None

        self._minima_color_value = None
Beispiel #2
0
 def __init__(self, database=None, parent=None, app=None, minima=None):
     QWidget.__init__(self, parent=parent)
     self.ui = Ui_Form()
     self.ui.setupUi(self)
     self.database = database
     self.minima = minima
     self.app = app
     
     self.canvas = self.ui.canvas.canvas
     
     self.axes = self.canvas.axes
     self.fig = self.canvas.fig
     
     self.on_minima_picked = Signal()
     
     self.from_minima = set()
     self.positions = dict()
     self.boundary_nodes = set()
     
     self._selected_minimum = None
     self._mpl_cid = None
     
     self._minima_color_value = None
Beispiel #3
0
class GraphViewWidget(QWidget):
    def __init__(self, database=None, parent=None, app=None, minima=None):
        QWidget.__init__(self, parent=parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.database = database
        self.minima = minima
        self.app = app

        self.canvas = self.ui.canvas.canvas

        self.axes = self.canvas.axes
        self.fig = self.canvas.fig

        self.on_minima_picked = Signal()

        self.from_minima = set()
        self.positions = dict()
        self.boundary_nodes = set()

        self._selected_minimum = None
        self._mpl_cid = None

        self._minima_color_value = None

    def on_btn_show_all_clicked(self, clicked=None):
        if clicked is None: return
        self.show_all()

    def _reset_minima_lists(self):
        self.from_minima.clear()
        self.positions.clear()
        self.boundary_nodes.clear()
        self._minima_color_value = None

    def show_all(self):
        self.ui.label_status.setText("showing full graph")
        self._reset_minima_lists()
        self.make_graph()
        self.show_graph()

    def make_graph_from(self, minima, cutoff=1):
        """rebuild the graph using only the passed minima and those in self.from_minima"""
        #        cutoff += 1
        self.from_minima.update(minima)
        minima = self.from_minima
        nodes = set()
        # make a graph from the minima in self.minima and nearest neighbors
        outer_layer = set()
        for m in minima:
            nodesdir = nx.single_source_shortest_path(self.full_graph,
                                                      m,
                                                      cutoff=cutoff)
            for n, path in nodesdir.items():
                d = len(path) - 1
                if d < cutoff:
                    # n is close to m, remove it from outer layer
                    outer_layer.discard(n)
                elif d == cutoff:
                    if n not in nodes:
                        # n is in the outer layer of m and not near any other nodes.
                        outer_layer.add(n)
            nodes.update(nodesdir)

        self.boundary_nodes = outer_layer
        self.graph = self.full_graph.subgraph(nodes)

        # remove nodes not in the graph from the dictionary positions
        difference = set(self.positions.keys())
        difference.difference_update(self.graph.nodes())
        for m in difference:
            self.positions.pop(m)

        print("boundary nodes", len(self.boundary_nodes),
              self.graph.number_of_nodes())

    def make_graph(self, database=None, minima=None):
        """build an nx graph from the database"""
        if database is None:
            database = self.database
        if minima is None:
            minima = self.minima

        print("making graph", database, minima)
        # get the graph object, eliminate nodes without edges
        graph = database2graph(database)
        if minima is not None:
            to_remove = set(graph.nodes()).difference(set(minima))
            graph.remove_nodes_from(to_remove)
        self.full_graph = graph
        print(graph.number_of_nodes())
        degree = graph.degree()
        nodes = [n for n, nedges in degree.items() if nedges > 0]
        self.graph = graph.subgraph(nodes)
        print(self.graph.number_of_nodes(), self.graph.number_of_edges())

    def _show_minimum_energy_path(self, m1, m2):
        """show only the minima in the path from m1 to m2"""
        self._reset_minima_lists()
        path = minimum_energy_path(self.full_graph, m1, m2)
        self.make_graph_from(path)
        print("there are", len(path), "minima in the path from", m1._id, "to",
              m2._id)
        status = "showing path from minimum %d to %d" % (m1._id, m2._id)
        self.ui.label_status.setText(status)
        self.show_graph()

    def _color_by_committor(self, min1, min2, T=1.):
        print("coloring by the probability that a trajectory gets to minimum",
              min1._id, "before", min2._id)
        # get a list of transition states in the same cluster as min1
        edges = nx.bfs_edges(self.graph, min1)
        transition_states = [
            self.graph.get_edge_data(u, v)["ts"] for u, v in edges
        ]
        if not check_thermodynamic_info(transition_states):
            raise Exception(
                "The thermodynamic information is not yet computed.  Use the main menu of the gui under 'Actions'"
            )

        A = [min2]
        B = [min1]
        committors = compute_committors(transition_states, A, B, T=T)
        self._minima_color_value = committors

        def get_committor(m):
            try:
                return committors[m]
            except KeyError:
                return 1.

        self._minima_color_value = get_committor
        self.show_graph()

    def _on_right_click_minimum(self, minimum):
        """create a menu with the list of available actions"""
        print("you right clicked on minimum with id", minimum._id,
              "and energy", minimum.energy)
        menu = QtGui.QMenu("list menu", parent=self)

        if self._selected_minimum is not None:
            menu.addAction(
                ShowPathAction(minimum, self._selected_minimum, parent=self))
            menu.addAction(
                ColorByCommittorAction(minimum,
                                       self._selected_minimum,
                                       parent=self))

        menu.exec_(QtGui.QCursor.pos())

    def _on_left_click_minimum(self, min1):
        self._selected_minimum = min1
        print("you clicked on minimum with id", min1._id, "and energy",
              min1.energy)
        self.on_minima_picked(min1)
        if self.ui.checkBox_zoom.isChecked():
            self.make_graph_from([min1])
            text = "showing graph near minima "
            for m in self.from_minima:
                text += " " + str(m._id)
            self.ui.label_status.setText(text)
            self.show_graph()

    def _on_mpl_pick_event(self, event):
        """matplotlib event called when a minimum is clicked on"""
        artists = {self._boundary_points, self._minima_points}
        if event.artist not in artists:
            #                print "you clicked on something other than a node"
            return True
        ind = event.ind[0]
        if event.artist == self._minima_points:
            min1 = self._mimima_layout_list[ind][0]
        else:
            min1 = self._boundary_layout_list[ind][0]
        if event.mouseevent.button == 3:
            self._on_right_click_minimum(min1)
        else:
            self._on_left_click_minimum(min1)

    def show_graph(self, fixed=False, show_ids=True):
        """draw the graph"""
        import pylab as pl
        if not hasattr(self, "graph"):
            self.make_graph()

        print("showing graph")
        # I need to clear the figure and make a new axes object because
        # I can't find any other way to remove old colorbars
        self.fig.clf()
        self.axes = self.fig.add_subplot(111)
        ax = self.axes
        ax.clear()
        graph = self.graph

        # get the layout of the nodes from networkx
        oldlayout = self.positions
        layout = nx.spring_layout(graph, pos=oldlayout)
        self.positions.update(layout)
        layout = self.positions

        # draw the edges as lines
        from matplotlib.collections import LineCollection
        linecollection = LineCollection([
            (layout[u], layout[v]) for u, v in graph.edges()
            if u not in self.boundary_nodes and v not in self.boundary_nodes
        ])
        linecollection.set_color('k')
        ax.add_collection(linecollection)

        if self.boundary_nodes:
            # draw the edges connecting the boundary nodes as thin lines
            from matplotlib.collections import LineCollection
            linecollection = LineCollection([
                (layout[u], layout[v]) for u, v in graph.edges()
                if u in self.boundary_nodes or v in self.boundary_nodes
            ])
            linecollection.set_color('k')
            linecollection.set_linewidth(0.2)
            ax.add_collection(linecollection)

        markersize = 8**2

        # draw the interior nodes
        interior_nodes = set(graph.nodes()) - self.boundary_nodes
        layoutlist = [
            nxy for nxy in layout.items() if nxy[0] in interior_nodes
        ]
        xypos = np.array([xy for n, xy in layoutlist])
        if self._minima_color_value is None:
            #color the nodes by energy
            color_values = [m.energy for m, xy in layoutlist]
        else:
            color_values = [
                self._minima_color_value(m) for m, xy in layoutlist
            ]
        #plot the nodes
        self._minima_points = ax.scatter(xypos[:, 0],
                                         xypos[:, 1],
                                         picker=5,
                                         s=markersize,
                                         c=color_values,
                                         cmap=pl.cm.autumn)
        self._mimima_layout_list = layoutlist
        #        if not hasattr(self, "colorbar"):
        self.colorbar = self.fig.colorbar(self._minima_points)

        self._boundary_points = None
        self._boundary_list = []
        if self.boundary_nodes:
            # draw the boundary nodes as empty circles with thin lines
            boundary_layout_list = [
                nxy for nxy in layout.items() if nxy[0] in self.boundary_nodes
            ]
            xypos = np.array([xy for n, xy in boundary_layout_list])
            #plot the nodes
            #            marker = mpl.markers.MarkerStyle("o", fillstyle="none")
            #            marker.set_fillstyle("none")
            self._boundary_points = ax.scatter(xypos[:, 0],
                                               xypos[:, 1],
                                               picker=5,
                                               s=markersize,
                                               marker="o",
                                               facecolors="none",
                                               linewidths=.5)
            self._boundary_layout_list = boundary_layout_list

        #scale the axes so the points are not cutoff
        xmax = max((x for x, y in layout.values()))
        xmin = min((x for x, y in layout.values()))
        ymax = max((y for x, y in layout.values()))
        ymin = min((y for x, y in layout.values()))
        dx = (xmax - xmin) * .1
        dy = (ymax - ymin) * .1
        ax.set_xlim([xmin - dx, xmax + dx])
        ax.set_ylim([ymin - dy, ymax + dy])

        if self._mpl_cid is not None:
            self.canvas.mpl_disconnect(self._mpl_cid)
            self._mpl_cid = None
        self._mpl_cid = self.fig.canvas.mpl_connect('pick_event',
                                                    self._on_mpl_pick_event)

        self.canvas.draw()
        self.app.processEvents()
Beispiel #4
0
class GraphViewWidget(QWidget):
    def __init__(self, database=None, parent=None, app=None, minima=None):
        QWidget.__init__(self, parent=parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
#        self.widget = GraphDisplayWidget(parent=parent)
        self.database = database
        self.minima = minima
        self.app = app
        
        self.canvas = self.ui.canvas.canvas
        
        self.axes = self.canvas.axes
        self.fig = self.canvas.fig
        
        self.on_minima_picked = Signal()
        
        self.from_minima = set()
        self.positions = dict()
        self.boundary_nodes = set()
        
        self._selected_minimum = None
        self._mpl_cid = None
        
        self._minima_color_value = None
    
    
    def on_btn_show_all_clicked(self, clicked=None):
        if clicked is None: return
        self.show_all()
    
    def _reset_minima_lists(self):
        self.from_minima.clear()
        self.positions.clear()
        self.boundary_nodes.clear()
        self._minima_color_value = None
    
    def show_all(self):
        self.ui.label_status.setText("showing full graph")
        self._reset_minima_lists()
        self.make_graph()
        self.show_graph()
    
    def make_graph_from(self, minima, cutoff=1):
        """rebuild the graph using only the passed minima and those in self.from_minima"""
#        cutoff += 1
        self.from_minima.update(minima)
        minima = self.from_minima
        nodes = set()
        # make a graph from the minima in self.minima and nearest neighbors
        outer_layer = set()
        for m in minima:
            nodesdir = nx.single_source_shortest_path(self.full_graph, m, cutoff=cutoff)
            for n, path in nodesdir.iteritems():
                d = len(path) - 1
                if d < cutoff:
                    # n is close to m, remove it from outer layer
                    outer_layer.discard(n)
                elif d == cutoff:
                    if n not in nodes:
                        # n is in the outer layer of m and not near any other nodes.
                        outer_layer.add(n)
            nodes.update(nodesdir)

        self.boundary_nodes = outer_layer
        self.graph = self.full_graph.subgraph(nodes)

        # remove nodes not in the graph from the dictionary positions
        difference = set(self.positions.viewkeys())
        difference.difference_update(self.graph.nodes())
        for m in difference:
            self.positions.pop(m)

        print "boundary nodes", len(self.boundary_nodes), self.graph.number_of_nodes()
    
    def make_graph(self, database=None, minima=None):
        """build an nx graph from the database"""
        if database is None:
            database = self.database
        if minima is None:
            minima = self.minima

        print "making graph", database, minima
        # get the graph object, eliminate nodes without edges
        graph = database2graph(database)
        if minima is not None:
            to_remove = set(graph.nodes()).difference(set(minima))
            graph.remove_nodes_from(to_remove)
        self.full_graph = graph
        print graph.number_of_nodes()
        degree = graph.degree()
        nodes = [n for n, nedges in degree.items() if nedges > 0]
        self.graph = graph.subgraph(nodes)
        print self.graph.number_of_nodes(), self.graph.number_of_edges()
    
    def _show_minimum_energy_path(self, m1, m2):
        """show only the minima in the path from m1 to m2"""
        self._reset_minima_lists()
        path = minimum_energy_path(self.full_graph, m1, m2)
        self.make_graph_from(path)
        print "there are", len(path), "minima in the path from", m1._id, "to", m2._id 
        status = "showing path from minimum %d to %d" % (m1._id, m2._id)
        self.ui.label_status.setText(status)
        self.show_graph()
    
    
    def _color_by_committor(self, min1, min2, T=1.):
        print "coloring by the probability that a trajectory gets to minimum", min1._id, "before", min2._id
        # get a list of transition states in the same cluster as min1
        edges = nx.bfs_edges(self.graph, min1)
        transition_states = [ self.graph.get_edge_data(u, v)["ts"] for u, v in edges ]
        if not check_thermodynamic_info(transition_states):
            raise Exception("The thermodynamic information is not yet computed.  Use the main menu of the gui under 'Actions'")
        
        A = [min2]
        B = [min1]
        committors = compute_committors(transition_states, A, B, T=T)
        self._minima_color_value = committors
        def get_committor(m):
            try:
                return committors[m]
            except KeyError:
                return 1.
        self._minima_color_value = get_committor
        self.show_graph()

    
    def _on_right_click_minimum(self, minimum):
        """create a menu with the list of available actions"""
        print "you right clicked on minimum with id", minimum._id, "and energy", minimum.energy
        menu = QtGui.QMenu("list menu", parent=self)
        
        if self._selected_minimum is not None:
            menu.addAction(ShowPathAction(minimum, self._selected_minimum, parent=self))
            menu.addAction(ColorByCommittorAction(minimum, self._selected_minimum, parent=self))

        menu.exec_(QtGui.QCursor.pos())

    def _on_left_click_minimum(self, min1):
        self._selected_minimum = min1
        print "you clicked on minimum with id", min1._id, "and energy", min1.energy
        self.on_minima_picked(min1)
        if self.ui.checkBox_zoom.isChecked():
            self.make_graph_from([min1])
            text = "showing graph near minima "
            for m in self.from_minima: 
                text += " " + str(m._id)
            self.ui.label_status.setText(text)
            self.show_graph()
    
    def _on_mpl_pick_event(self, event):
        """matplotlib event called when a minimum is clicked on"""
        artists = set([self._boundary_points, self._minima_points])
        if event.artist not in artists:
#                print "you clicked on something other than a node"
            return True
        ind = event.ind[0]
        if event.artist == self._minima_points:
            min1 = self._mimima_layout_list[ind][0]
        else:
            min1 = self._boundary_layout_list[ind][0]
        if event.mouseevent.button == 3:
            self._on_right_click_minimum(min1)
        else:
            self._on_left_click_minimum(min1)


    
    def show_graph(self, fixed=False, show_ids=True):
        """draw the graph"""
        import pylab as pl
        if not hasattr(self, "graph"):
            self.make_graph()
        
        print "showing graph"
        # I need to clear the figure and make a new axes object because
        # I can't find any other way to remove old colorbars
        self.fig.clf()
        self.axes = self.fig.add_subplot(111)
        ax = self.axes
        ax.clear()
        graph = self.graph
        
        #get the layout of the nodes from networkx
        oldlayout = self.positions
        layout = nx.spring_layout(graph, pos=oldlayout)#, fixed=fixed)
        self.positions.update(layout)
        layout = self.positions
        
        # draw the edges as lines
        from matplotlib.collections import LineCollection
        linecollection = LineCollection([(layout[u], layout[v]) for u, v in graph.edges()
                 if u not in self.boundary_nodes and v not in self.boundary_nodes])
        linecollection.set_color('k')
        ax.add_collection(linecollection)

        if self.boundary_nodes:
            # draw the edges connecting the boundary nodes as thin lines
            from matplotlib.collections import LineCollection
            linecollection = LineCollection([(layout[u], layout[v]) for u, v in graph.edges()
                     if u in self.boundary_nodes or v in self.boundary_nodes])
            linecollection.set_color('k')
            linecollection.set_linewidth(0.2)
            ax.add_collection(linecollection)

        markersize = 8**2
        
        # draw the interior nodes
        interior_nodes = set(graph.nodes()) - self.boundary_nodes
        layoutlist = filter(lambda nxy: nxy[0] in interior_nodes, layout.items())
        xypos = np.array([xy for n, xy in layoutlist])
        if self._minima_color_value is None:
            #color the nodes by energy
            color_values = [m.energy for m, xy in layoutlist]
        else:
            color_values = [self._minima_color_value(m) for m, xy in layoutlist]
        #plot the nodes
        self._minima_points = ax.scatter(xypos[:,0], xypos[:,1], picker=5, 
                            s=markersize, c=color_values, cmap=pl.cm.autumn)
        self._mimima_layout_list = layoutlist
#        if not hasattr(self, "colorbar"):
        self.colorbar = self.fig.colorbar(self._minima_points)
        
        self._boundary_points = None
        self._boundary_list = []
        if self.boundary_nodes:
            # draw the boundary nodes as empty circles with thin lines
            boundary_layout_list = filter(lambda nxy: nxy[0] in self.boundary_nodes, layout.items())
            xypos = np.array([xy for n, xy in boundary_layout_list])
            #plot the nodes
            import matplotlib as mpl
#            marker = mpl.markers.MarkerStyle("o", fillstyle="none")
#            marker.set_fillstyle("none")
            self._boundary_points = ax.scatter(xypos[:,0], xypos[:,1], picker=5, 
                                s=markersize, marker="o", facecolors="none", linewidths=.5)
            self._boundary_layout_list = boundary_layout_list

        
        #scale the axes so the points are not cutoff
        xmax = max((x for x,y in layout.itervalues() ))
        xmin = min((x for x,y in layout.itervalues() ))
        ymax = max((y for x,y in layout.itervalues() ))
        ymin = min((y for x,y in layout.itervalues() ))
        dx = (xmax - xmin)*.1
        dy = (ymax - ymin)*.1
        ax.set_xlim([xmin-dx, xmax+dx])
        ax.set_ylim([ymin-dy, ymax+dy])
        import matplotlib.pyplot as plt
#        self.fig.relim()
#        self.fig.tight_layout()
#        plt.tight_layout()
#        self.fig.set_tight_layout(True)
        
        
#        def on_pick(event):
#            ind = event.ind[0]
#            if event.artist == points:
#                min1 = layoutlist[ind][0]
#            elif event.artist == boundary_points:
#                min1 = boundary_layout_list[ind][0]
#            else:
#                return True
#            print "you clicked on minimum with id", min1._id, "and energy", min1.energy
#            self._on_minima_picked(min1)

        
        if self._mpl_cid is not None:
            self.canvas.mpl_disconnect(self._mpl_cid)
            self._mpl_cid = None
        self._mpl_cid = self.fig.canvas.mpl_connect('pick_event', self._on_mpl_pick_event)

        
        self.canvas.draw()
        self.app.processEvents()