示例#1
0
   def copy_node(node_index, net_index):
       '''
 Creates a new node, translated 300 px down and to the right.
 Parameters: node index
 Returns: index of new node
 '''
       node = api.get_node_by_index(net_index, node_index)
       try:
           inx = api.add_node(net_index,
                              id='copy_{}'.format(node.id),
                              shape_index=node.shape_index,
                              size=Vec2(node.size[0] + 60, node.size[1]),
                              position=Vec2(node.position[0] + 300,
                                            node.position[1] + 300))
       except IDRepeatError:
           # find a unique id
           all_ids = []
           ns = api.get_nodes(net_index)
           for n in ns:
               all_ids.append(n.id)
           c = 1
           new_id = 'copy_{}_{}'.format(node.id, c)
           while new_id in all_ids:
               c += 1
               new_id = 'copy_{}_{}'.format(node.id, c)
           inx = api.add_node(net_index,
                              id=new_id,
                              shape_index=node.shape_index,
                              size=Vec2(node.size[0] + 60, node.size[1]),
                              position=Vec2(node.position[0] + 300,
                                            node.position[1] + 300))
       return inx
示例#2
0
 def OnLeftUp(self, evt: wx.MouseEvent):
     """
     Handler for mouse left button up event.
     """
     if self.dragging:
         assert self.dragged_point is not None
         drop = self.projected_landing(self.dragged_point)
         assert self.hover_idx != -1
         self.dragging = False
         self.arrow_tip.points[self.hover_idx] = Vec2(
             drop.x // self.csize, drop.y // self.csize)
         self.update_hover_idx(Vec2(evt.GetPosition()))
         self.Refresh()
示例#3
0
    def __init__(self, parent, arrow_tip: ArrowTip):
        """
        Initialize the arrow designer window with the given starting arrow tip.

        Args: 
            parent: The parent window.
            arrow_tip: ArrowTip object defining the arrow tip used.
        """
        dim = Vec2(22, 16)
        self.csize = 20
        size = dim * self.csize + Vec2.repeat(1)
        super().__init__(parent, size=size.as_tuple())
        # add 1 to range end, so that the grid rectangle side will be included.
        rows = [r for r in range(0, int(size.y), self.csize)]
        cols = [c for c in range(0, int(size.x), self.csize)]

        self.begin_points = list()
        self.end_points = list()

        for r in rows:
            self.begin_points.append(wx.Point2D(0, r))
            self.end_points.append(wx.Point2D(size.x - 1, r))

        for c in cols:
            self.begin_points.append(wx.Point2D(c, 0))
            self.end_points.append(wx.Point2D(c, size.y - 1))

        self.handle_c = api.get_theme('handle_color')
        self.hl_handle_c = api.get_theme('highlighted_handle_color')
        self.handle_pen = wx.Pen(self.handle_c)
        self.hl_handle_pen = wx.Pen(self.hl_handle_c)
        self.handle_brush = wx.Brush(self.handle_c)
        self.hl_handle_brush = wx.Brush(self.hl_handle_c)
        phantom_c = opacity_mul(self.handle_c, 0.5)
        self.phantom_pen = wx.Pen(phantom_c)
        self.phantom_brush = wx.Brush(phantom_c)

        self.arrow_tip = arrow_tip
        self.radius = 12
        self.radius_sq = self.radius**2
        self.hover_idx = -1
        self.dragged_point = None
        self.dragging = False
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
        self.Bind(wx.EVT_MOTION, self.OnMotion)
        self.SetDoubleBuffered(True)
示例#4
0
    def projected_landing(self, point: Vec2) -> Vec2:
        """
        Return the projected discrete landing point for the cursor.

        This is to make sure the user sees where the dragged arrow tip point will be dropped on
        the grid.

        Args: 
            point: The cursor position relative to the window.

        Returns:
            Vec2 : projected point for landing.
        """
        lx = point.x - point.x % self.csize
        ly = point.y - point.y % self.csize
        drop_x: float
        drop_y: float

        if point.x - lx < self.csize / 2:
            drop_x = lx
        else:
            drop_x = lx + self.csize

        if point.y - ly < self.csize / 2:
            drop_y = ly
        else:
            drop_y = ly + self.csize

        return Vec2(drop_x, drop_y)
示例#5
0
 def test_add_basic(self):
     node = Node('Charles',
                 self.neti,
                 pos=Vec2(50, 50),
                 size=Vec2(50, 30))
     api.add_node(self.neti, id=node.id,
                     position=node.position,
                     size=node.size,
                     # fill_color=api._to_color(wx.RED),  # HACK using API private methods
                     # border_color=api._to_color(wx.BLUE),
                     # border_width=2,
                     )
     nodes = api.get_nodes(self.neti)
     self.assertEqual(len(nodes), 1)
     self.assertEqual(0, nodes[0].index)
     expected = NodeData(id='Charles', net_index=self.neti, position=Vec2(50, 50), size=Vec2(50, 30), index=0)
     self.assertEqual(str(expected), str(nodes[0]))
     self.assertEqual(expected, nodes[0])
示例#6
0
    def draw_point(self, gc: wx.GraphicsContext, point: Vec2, radius: float):
        """
        Drawing a single point.

        Args: 
            gc: Graphics context to modify.
            point: Point to be drawn.
            radius: Radius of the point.
        """
        center = point - Vec2.repeat(radius / 2)
        gc.DrawEllipse(center.x, center.y, radius, radius)
示例#7
0
    def test_add_alias(self):
        size = Vec2(60, 60)
        nodei = api.add_node(self.neti, id='Hookie', size=size)
        api.add_alias(self.neti, nodei, size=size)

        nodes = api.get_nodes(self.neti)
        self.assertEqual(2, len(nodes))
        original = NodeData(net_index=self.neti, id='Hookie', index=0, original_index=-1, size=size)
        alias = NodeData(net_index=self.neti, id='Hookie', index=1, original_index=0, size=size)
        self.assertEqual(original, nodes[0])
        self.assertEqual(alias, nodes[1])
示例#8
0
    def test_separate_props(self):
        '''Test modifying the properties of node and alias that are separate, i.e. not shared.
        
        As in, if the position of an alias is changed, that of the node should remain the same,
        and vice versa.
        '''
        alias_pos = Vec2(100, 100)
        alias_size = Vec2(50, 50)
        nodei = api.add_node(self.neti, id='Hookie')
        aliasi = api.add_alias(self.neti, nodei, position=alias_pos, size=alias_size)

        new_pos = Vec2(33, 33)
        new_size = Vec2(66, 66)
        new_lockNode = True
        api.update_node(self.neti, nodei, position=Vec2(33, 33), size=Vec2(66, 66), lock_node=True)
        node = api.get_node_by_index(self.neti, nodei)
        alias = api.get_node_by_index(self.neti, aliasi)

        # alias remains the same
        self.assertEqual(alias_pos, alias.position)
        self.assertEqual(alias_size, alias.size)
        self.assertEqual(False, alias.lock_node)

        # node is updated
        self.assertEqual(new_pos, node.position)
        self.assertEqual(new_size, node.size)
        self.assertEqual(new_lockNode, node.lock_node)
示例#9
0
    def test_update_failure(self):
        api.add_node(self.neti, id='Zulu')
        # empty ID
        with self.assertRaises(ValueError):
            api.update_node(self.neti, 0, id='')

        # nodes don't exist
        with self.assertRaises(NetIndexError):
            api.update_node(-1, 0, size=Vec2(50, 60))
        with self.assertRaises(NodeIndexError):
            api.update_node(0, 2, size=Vec2(50, 60))

        # out of bounds
        with self.assertRaises(ValueError):
            api.update_node(self.neti, 0, position=Vec2(-1, 0))
        with self.assertRaises(ValueError):
            api.update_node(self.neti, 0, position=Vec2(0, -1))

        csize = api.canvas_size()
        # in bounds
        api.update_node(self.neti, 0, position=csize - Vec2(100, 100))

        # out of bounds
        with self.assertRaises(ValueError):
            api.update_node(self.neti, 0, position=csize - Vec2(1, 1))
示例#10
0
    def test_simple_handles(self):
        """Simple tests for Bezier handles."""
        api.add_reaction(self.neti, 'AB', [0], [1])
        api.set_reaction_center_handle(0, 0, Vec2(-10, 30))
        self.assertEqual(api.get_reaction_center_handle(0, 0), Vec2(-10, 30))

        api.set_reaction_node_handle(0, 0, 0, True, Vec2(40, 50))
        self.assertEqual(api.get_reaction_node_handle(0, 0, 0, True),
                         Vec2(40, 50))

        with self.assertRaises(NodeIndexError):
            api.get_reaction_node_handle(0, 0, 12, True)

        # test for the case where node exists but not reactant/product
        with self.assertRaises(ValueError):
            api.get_reaction_node_handle(0, 0, 1, True)

        with self.assertRaises(ValueError):
            api.get_reaction_node_handle(0, 0, 0, False)

        with self.assertRaises(ReactionIndexError):
            api.get_reaction_node_handle(0, 2, 0, True)
示例#11
0
 def get_new_position(self, node_index, r, theta):
     """
     Takes in the node index and outputs the new position for that node
     Parameters: r(double), theta(double in radians)
     Returns: (x,y) cartesian coordinate tuple
     """
     node = api.get_node_by_index(0, node_index)
     size = node.size  # (width, height)
     # accounting for slight offset, converting to cartesian
     nodeCenter = self.cart(r - size[0], theta)
     # accounting for node position being specified by top left corner
     x = r + nodeCenter[0] - size[0] / 2
     y = r + nodeCenter[1] + size[1] / 2
     return Vec2(x, y)
示例#12
0
    def OnMotion(self, evt: wx.MouseEvent):
        """
        Handler for mouse motion events.

        Args: 
            self: the Designer Window to initialize.
            evt: the event being executed.

        """
        pos = Vec2(evt.GetPosition())
        if self.dragging:
            self.dragged_point = pos
        else:
            self.update_hover_idx(pos)
            evt.Skip()
        self.Refresh()
示例#13
0
    def Apply(self, evt):
        if api.node_count(0) == 0:
            return
        G = nx.Graph()
        nodesInd = np.array(list(api.get_node_indices(0)))
        reactionsInd =  np.array(list(api.get_reaction_indices(0)))
        originalPos = {}
        def generateGraph():
            # add nodes and centroids as "nodes" for networkX
            nodes = np.array(list(api.get_node_indices(0)))
            #reactionsInd =  np.array(list(api.get_reaction_indices(0)))
            cStr = np.empty_like(reactionsInd, dtype=str)
            cStr[:,] = "c"
            centroidId = np.char.add(cStr, reactionsInd.astype(str))
            G.add_nodes_from(centroidId)
            nStr = np.empty_like(nodes, dtype=str)
            nStr[:,] = "n"
            nodesId = np.array(list(np.char.add(nStr, nodesInd.astype(str))))
            G.add_nodes_from(nodesId)
            '''
            for n in nodes:
                centroidsTo = np.array(list(api.get_reactions_as_product(0, n))) # Gets the reactions in which it is a product -> TO 
                cStr = np.empty_like(centroidsTo, dtype=str)
                cStr[:,] = "c"
                centroidsToIn = np.char.add(cStr, centroidsTo.astype(str)) # centroids from which the node is product
                centroidsFrom = np.array(list(api.get_reactions_as_reactant(0, n))) # reactions in which it is a reactanr -> FROM
                cStr = np.empty_like(centroidsFrom, dtype=str)
                cStr[:,] = "c"
                centroidsFromIn = np.char.add(cStr, centroidsFrom.astype(str)) # centroids to which the node is reactant
                nS = np.empty_like(centroidsToIn, dtype = str)
                nS[:,] = "n"
                numS = np.empty_like(centroidsToIn, dtype = int)
                numS[:,] = n
                nodeIndArrayTo = np.char.add(nS, numS.astype(str))
                nS = np.empty_like(centroidsFromIn, dtype = str)
                nS[:,] = "n"
                numS = np.empty_like(centroidsFromIn, dtype = int)
                numS[:,] = n
                nodeIndArrayFrom = np.char.add(nS, numS.astype(str))
                edgesTo = np.array(list(zip(centroidsToIn, nodeIndArrayTo)))
                edgesFrom = np.array(list(zip(nodeIndArrayFrom, centroidsFromIn)))
                G.add_edges_from(edgesTo)
                G.add_edges_from(edgesFrom)
            '''

            # Add edges from reactant to centroid and centroid to product (undirected)
            edges = list()
            for reaction in api.get_reactions(0):
                for s in reaction.sources:
                    edges.append(('n' + str(s), 'c' + str(reaction.index)))
                for t in reaction.targets:
                    edges.append(('c' + str(reaction.index), 'n' + str(t)))
                        
            G.add_edges_from(edges)
            cn = 0
            for rea in api.get_reactions(0):
                cent = api.compute_centroid(0, rea.sources, rea.targets)
                #originalPos[centroidId[cn]] = list([cent.x, cent.y])
                originalPos['c' + str(rea)] = list([random.randint(0,600), random.randint(0,600)])
                cn = cn + 1
            
            for nod in api.get_nodes(0):
                #originalPos[nodesId[cn]] = list([nod.position.x, nod.position.y])
                # random.randint(0,500), nod.position.y+random.randint (0,500)])
                originalPos['n' + str(nod)] = list([random.randint(0,600), random.randint (0,600)])
                cn = cn + 1
        generateGraph()
        #print(nx.to_dict_of_lists(G))
        #nodeIds = list (api.get_node_indices(0))
        with api.group_action():   
            for t in range(1):
                pos = (nx.fruchterman_reingold_layout(G, k = self.kValue, iterations = self.MaxIterValue, scale = self.scaleValue, pos = originalPos, weight=1))
                positions = np.array(list(pos.values()))
                minX = 0
                minY = 0
                for p in positions:
                    if p[0] < minX:
                        minX = p[0]
                    if p[1] < minY:
                        minY = p[1]
                positions = positions - np.array([minX, minY])
                centroids = positions[0: len(reactionsInd)]
                nodes = positions[len(reactionsInd): len(positions)]
                count = 0
                for n in nodes:
                    newX = float(n[0])
                    newY = float(n[1])
                    api.move_node(0, nodesInd[count], position = Vec2(newX, newY), allowNegativeCoordinates=True)   
                    count = count + 1
                
                if self.useCentroid:
                    count = 0
                    for c in centroids:
                        newX = float(c[0])
                        newY = float(c[1])
                        r = api.get_reaction_by_index(0, reactionsInd[count])
                        handles = api.default_handle_positions(0, r.index)
                        api.update_reaction(0, r.index, center_pos=Vec2(newX, newY), handle_positions=handles)  
                        count = count + 1
                else:
                    for index in api.get_reaction_indices(0):
                        api.update_reaction(0, index, center_pos=None)
                        handles = api.default_handle_positions(0, index)
                        api.update_reaction(0, index, handle_positions=handles)

                '''
                
                for r in api.get_reactions(0):
                    currCentroid = centroids[r.index]
                    newX = float(currCentroid[0])
                    newY = float(currCentroid[1])
                    api.update_reaction(0, r.index, center_pos=(Vec2(newX, newY)))
                    #api.update_reaction(0, r.index, center_pos=None)
                    handles = api.default_handle_positions(0, r.index)
                    api.set_reaction_center_handle(0, r.index, handles[0])
                    count = 1
                    for s in r.sources:
                        api.set_reaction_node_handle(0, r.index, s, True, handles[count])
                        count += 1
                    for t in r.targets:
                        api.set_reaction_node_handle(0, r.index, t, False, handles[count])
                        count += 1
                
                '''

            ws = api.window_size()
            offset = Vec2(ws.x/4, ws.y/4)
            api.translate_network(0, offset, check_bounds = True)
示例#14
0
    def Apply(self, evt):
        """
        Handler for the "apply" button. apply the random network.
        """
        if self.randomSeedValue != 0:
            _random.seed(self.randomSeedValue)

        class _TReactionType:
            UNIUNI = 0
            BIUNI = 1
            UNIBI = 2
            BIBI = 3

        def _pickReactionType():

            rt = _random.random()
            if rt < self.probUniUniValue:
                return _TReactionType.UNIUNI
            elif rt < self.probUniUniValue + self.probBiUniValue:
                return _TReactionType.BIUNI
            elif rt < self.probUniUniValue + self.probBiUniValue + self.probUniBiValue:
                return _TReactionType.UNIBI
            else:
                return _TReactionType.BIBI

        # Generates a reaction network in the form of a reaction list
        # reactionList = [nSpecies, reaction, reaction, ....]
        # reaction = [reactionType, [list of reactants], [list of products], rateConsta>
        # Disallowed reactions:
        # S1 -> S1
        # S1 + S2 -> S2  # Can't have the same reactant and product
        # S1 + S1 -> S1
        def _generateReactionList(nSpecies, nReactions):

            reactionList = []
            for r in range(nReactions):

                rateConstant = _random.random()
                rt = _pickReactionType()
                if rt == _TReactionType.UNIUNI:
                    # UniUni
                    reactant = _random.randint(0, nSpecies - 1)
                    product = _random.randint(0, nSpecies - 1)
                    # Disallow S1 -> S1 type of reaction
                    while product == reactant:
                        product = _random.randint(0, nSpecies - 1)
                    reactionList.append(
                        [rt, [reactant], [product], rateConstant])

                if rt == _TReactionType.BIUNI:
                    # BiUni
                    # Pick two reactants
                    reactant1 = _random.randint(0, nSpecies - 1)
                    reactant2 = _random.randint(0, nSpecies - 1)

                    # pick a product but only products that don't include the reactants
                    species = range(nSpecies)
                    # Remove reactant1 and 2 from the species list
                    species = _np.delete(species, [reactant1, reactant2],
                                         axis=0)
                    # Then pick a product from the reactants that are left
                    product = species[_random.randint(0, len(species) - 1)]

                    reactionList.append(
                        [rt, [reactant1, reactant2], [product], rateConstant])

                if rt == _TReactionType.UNIBI:
                    # UniBi
                    reactant1 = _random.randint(0, nSpecies - 1)

                    # pick a product but only products that don't include the reactant
                    species = range(nSpecies)
                    # Remove reactant1 from the species list
                    species = _np.delete(species, [reactant1], axis=0)
                    # Then pick a product from the reactants that are left
                    product1 = species[_random.randint(0, len(species) - 1)]
                    product2 = species[_random.randint(0, len(species) - 1)]

                    reactionList.append(
                        [rt, [reactant1], [product1, product2], rateConstant])

                if rt == _TReactionType.BIBI:
                    # BiBi
                    reactant1 = _random.randint(0, nSpecies - 1)
                    reactant2 = _random.randint(0, nSpecies - 1)

                    # pick a product but only products that don't include the reactant
                    species = range(nSpecies)
                    # Remove reactant1 and 2 from the species list
                    species = _np.delete(species, [reactant1, reactant2],
                                         axis=0)
                    # Then pick a product from the reactants that are left
                    product1 = species[_random.randint(0, len(species) - 1)]
                    product2 = species[_random.randint(0, len(species) - 1)]

                    element = [
                        rt, [reactant1, reactant2], [product1, product2],
                        rateConstant
                    ]
                    reactionList.append(element)

            reactionList.insert(0, nSpecies)
            return reactionList

        # Includes boundary and floating species
        # Returns a list:
        # [New Stoichiometry matrix, list of floatingIds, list of boundaryIds]
        def _getFullStoichiometryMatrix(reactionList):

            nSpecies = reactionList[0]
            reactionListCopy = _copy.deepcopy(reactionList)
            reactionListCopy.pop(0)
            st = _np.zeros((nSpecies, len(reactionListCopy)))

            for index, r in enumerate(reactionListCopy):
                if r[0] == _TReactionType.UNIUNI:
                    # UniUni
                    reactant = reactionListCopy[index][1][0]
                    st[reactant, index] = -1
                    product = reactionListCopy[index][2][0]
                    st[product, index] = 1

                if r[0] == _TReactionType.BIUNI:
                    # BiUni
                    reactant1 = reactionListCopy[index][1][0]
                    st[reactant1, index] = -1
                    reactant2 = reactionListCopy[index][1][1]
                    st[reactant2, index] = -1
                    product = reactionListCopy[index][2][0]
                    st[product, index] = 1

                if r[0] == _TReactionType.UNIBI:
                    # UniBi
                    reactant1 = reactionListCopy[index][1][0]
                    st[reactant1, index] = -1
                    product1 = reactionListCopy[index][2][0]
                    st[product1, index] = 1
                    product2 = reactionListCopy[index][2][1]
                    st[product2, index] = 1

                if r[0] == _TReactionType.BIBI:
                    # BiBi
                    reactant1 = reactionListCopy[index][1][0]
                    st[reactant1, index] = -1
                    reactant2 = reactionListCopy[index][1][1]
                    st[reactant2, index] = -1
                    product1 = reactionListCopy[index][2][0]
                    st[product1, index] = 1
                    product2 = reactionListCopy[index][2][1]
                    st[product2, index] = 1

            return st

        def _getRateLaw(floatingIds, boundaryIds, reactionList, isReversible):

            nSpecies = reactionList[0]
            # Remove the first element which is the nSpecies
            reactionListCopy = _copy.deepcopy(reactionList)
            reactionListCopy.pop(0)

            antStr_tot = []

            for index, r in enumerate(reactionListCopy):
                antStr = ''
                antStr = antStr + 'J' + str(index) + ': '
                if r[0] == _TReactionType.UNIUNI:
                    # UniUni
                    antStr = antStr + '(k' + str(index) + '*S' + str(
                        reactionListCopy[index][1][0])
                    if isReversible:
                        antStr = antStr + ' - k' + str(
                            index) + 'r' + '*S' + str(
                                reactionListCopy[index][2][0])
                    antStr = antStr + ')'
                if r[0] == _TReactionType.BIUNI:
                    # BiUni
                    antStr = antStr + '(k' + str(index) + '*S' + str(
                        reactionListCopy[index][1][0]) + '*S' + str(
                            reactionListCopy[index][1][1])
                    if isReversible:
                        antStr = antStr + ' - k' + str(
                            index) + 'r' + '*S' + str(
                                reactionListCopy[index][2][0])
                    antStr = antStr + ')'
                if r[0] == _TReactionType.UNIBI:
                    # UniBi
                    antStr = antStr + '(k' + str(index) + '*S' + str(
                        reactionListCopy[index][1][0])
                    if isReversible:
                        antStr = antStr + ' - k' + str(
                            index) + 'r' + '*S' + str(
                                reactionListCopy[index][2][0]) + '*S' + str(
                                    reactionListCopy[index][2][1])
                    antStr = antStr + ')'
                if r[0] == _TReactionType.BIBI:
                    # BiBi
                    antStr = antStr + '(k' + str(index) + '*S' + str(
                        reactionListCopy[index][1][0]) + '*S' + str(
                            reactionListCopy[index][1][1])
                    if isReversible:
                        antStr = antStr + ' - k' + str(
                            index) + 'r' + '*S' + str(
                                reactionListCopy[index][2][0]) + '*S' + str(
                                    reactionListCopy[index][2][1])
                    antStr = antStr + ')'

                antStr_tot.append(antStr)

            return antStr_tot

        test_prob = self.probUniUniValue + self.probBiUniValue + self.probUniBiValue + self.probBiBiValue

        if test_prob != 1:
            wx.MessageBox("The sum of probabilities should be one!", "Message",
                          wx.OK | wx.ICON_INFORMATION)

        else:
            net_index = 0
            api.clear_network(net_index)

            rl = _generateReactionList(self.numSpecsValue, self.numRxnsValue)
            st = _getFullStoichiometryMatrix(rl)
            antStr = _getRateLaw(st[1], st[2], rl, isReversible=True)
            numNodes = st.shape[0]
            numRxns = st.shape[1]

            nodeIdx = []
            for i in range(numNodes):
                nodeIdx.append(
                    api.add_node(net_index,
                                 'node_{}'.format(i),
                                 size=Vec2(60, 40),
                                 fill_color=api.Color(255, 204, 153),
                                 border_color=api.Color(255, 108, 9),
                                 position=Vec2(
                                     40 + math.trunc(_random.random() * 800),
                                     40 + math.trunc(_random.random() * 800))))

            for i in range(numRxns):
                src = []
                dest = []

                for j in range(numNodes):
                    if (st.item(j, i) == -1):
                        src.append(nodeIdx[j])
                    if (st.item(j, i) == 1):
                        dest.append(nodeIdx[j])
                r_idx = api.add_reaction(net_index,
                                         'reaction_{}'.format(i),
                                         src,
                                         dest,
                                         fill_color=api.Color(91, 176, 253))

            # Need to remove orphan nodes
            for i in range(numNodes):
                if _np.array_equal(st[i, :], _np.zeros(numRxns)):
                    api.delete_node(net_index, nodeIdx[i])
示例#15
0
    def DisplayModel(self, sbmlStr, showDialogues, useSeed):
        """
        Visualize an SBML string as a network shown on the canvas.
        Args:
          self
          document: SBMLDocument object created from the sbml string
          sbmlStr: sbml string to display
          showDialogues: if false, hides pop-up windows
          useSeed: if true, constant seed for random number generation used,
                   ensuring that different visualizations created from the same
                   file will always have the same layout
        """
        if useSeed:
            _random.seed(13)

        def hex_to_rgb(value):
            value = value.lstrip('#')
            return tuple(int(value[i:i + 2], 16) for i in (0, 2, 4))

        if len(sbmlStr) == 0:
            if showDialogues:
                wx.MessageBox("Please import an SBML file.", "Message",
                              wx.OK | wx.ICON_INFORMATION)
        else:
            net_index = 0
            api.clear_network(net_index)
            comp_id_list = []
            comp_dimension_list = []
            comp_position_list = []
            spec_id_list = []
            specGlyph_id_list = []
            spec_specGlyph_id_list = []
            spec_dimension_list = []
            spec_position_list = []

            shapeIdx = 0

            #set the default values without render info:
            comp_fill_color = (158, 169, 255)
            comp_border_color = (0, 29, 255)
            comp_border_width = 2.0
            spec_fill_color = (255, 204, 153)
            spec_border_color = (255, 108, 9)
            spec_border_width = 2.0
            reaction_line_color = (129, 123, 255)
            reaction_line_width = 3.0

            ### from here for layout ###
            document = readSBMLFromString(sbmlStr)
            model_layout = document.getModel()
            mplugin = (model_layout.getPlugin("layout"))

            if mplugin is None:
                if showDialogues:
                    wx.MessageBox(
                        "There is no layout information, so positions are randomly assigned.",
                        "Message", wx.OK | wx.ICON_INFORMATION)

            #
            # Get the first Layout object via LayoutModelPlugin object.
            #
            else:
                layout = mplugin.getLayout(0)
                if layout is None:
                    if showDialogues:
                        wx.MessageBox(
                            "There is no layout information, so positions are randomly assigned.",
                            "Message", wx.OK | wx.ICON_INFORMATION)
                else:
                    numCompGlyphs = layout.getNumCompartmentGlyphs()
                    numSpecGlyphs = layout.getNumSpeciesGlyphs()
                    numReactionGlyphs = layout.getNumReactionGlyphs()
                    flag_text_out = 0

                    for i in range(numCompGlyphs):
                        compGlyph = layout.getCompartmentGlyph(i)
                        temp_id = compGlyph.getCompartmentId()
                        comp_id_list.append(temp_id)
                        boundingbox = compGlyph.getBoundingBox()
                        height = boundingbox.getHeight()
                        width = boundingbox.getWidth()
                        pos_x = boundingbox.getX()
                        pos_y = boundingbox.getY()
                        comp_dimension_list.append([width, height])
                        comp_position_list.append([pos_x, pos_y])

                    # for i in range(numSpecGlyphs):
                    #     specGlyph = layout.getSpeciesGlyph(i)
                    #     spec_id = specGlyph.getSpeciesId()
                    #     spec_id_list.append(spec_id)
                    #     boundingbox = specGlyph.getBoundingBox()
                    #     height = boundingbox.getHeight()
                    #     width = boundingbox.getWidth()
                    #     pos_x = boundingbox.getX()
                    #     pos_y = boundingbox.getY()
                    #     spec_dimension_list.append([width,height])
                    #     spec_position_list.append([pos_x,pos_y])

                    reaction_id_list = []
                    kinetics_list = []
                    rct_specGlyph_list = []
                    prd_specGlyph_list = []

                    for i in range(numReactionGlyphs):
                        reactionGlyph = layout.getReactionGlyph(i)
                        reaction_id = reactionGlyph.getReactionId()
                        reaction_id_list.append(reaction_id)
                        reaction = model_layout.getReaction(reaction_id)
                        kinetics = reaction.getKineticLaw().getFormula()
                        kinetics_list.append(kinetics)
                        numSpecRefGlyphs = reactionGlyph.getNumSpeciesReferenceGlyphs(
                        )

                        rct_specGlyph_temp_list = []
                        prd_specGlyph_temp_list = []

                        for j in range(numSpecRefGlyphs):
                            specRefGlyph = reactionGlyph.getSpeciesReferenceGlyph(
                                j)
                            #specRefGlyph_id = specRefGlyph.getSpeciesReferenceGlyphId()
                            role = specRefGlyph.getRoleString()
                            specGlyph_id = specRefGlyph.getSpeciesGlyphId()
                            specGlyph = layout.getSpeciesGlyph(specGlyph_id)
                            #textGlyph = layout.getTextGlyph(textGlyph_id)
                            spec_id = specGlyph.getSpeciesId()
                            spec_boundingbox = specGlyph.getBoundingBox()
                            #text_boundingbox = textGlyph.getBoundingBox()
                            height = spec_boundingbox.getHeight()
                            width = spec_boundingbox.getWidth()
                            pos_x = spec_boundingbox.getX()
                            pos_y = spec_boundingbox.getY()
                            #text_pos_x = text_boundingbox.getX()
                            #text_pos_y = text_boundingbox.getY()
                            #if (pos_x,pos_y) !=(text_pos_x,text_pos_y):
                            #    flag_text_out = 1

                            if specGlyph_id not in specGlyph_id_list:
                                spec_id_list.append(spec_id)
                                specGlyph_id_list.append(specGlyph_id)
                                spec_specGlyph_id_list.append(
                                    [spec_id, specGlyph_id])
                                spec_dimension_list.append([width, height])
                                spec_position_list.append([pos_x, pos_y])

                            if role == "substrate":  #it is a rct
                                rct_specGlyph_temp_list.append(specGlyph_id)
                            elif role == "product":  #it is a prd
                                prd_specGlyph_temp_list.append(specGlyph_id)

                        rct_specGlyph_list.append(rct_specGlyph_temp_list)
                        prd_specGlyph_list.append(prd_specGlyph_temp_list)

                    rPlugin = layout.getPlugin("render")
                    if (rPlugin != None and
                            rPlugin.getNumLocalRenderInformationObjects() > 0):
                        #wx.MessageBox("The diversity of each graphical object is not shown.", "Message", wx.OK | wx.ICON_INFORMATION)
                        info = rPlugin.getRenderInformation(0)
                        color_list = []
                        for j in range(0, info.getNumColorDefinitions()):
                            color = info.getColorDefinition(j)
                            color_list.append(
                                [color.getId(),
                                 color.createValueString()])

                        for j in range(0, info.getNumStyles()):
                            style = info.getStyle(j)
                            group = style.getGroup()
                            typeList = style.createTypeString()
                            if 'COMPARTMENTGLYPH' in typeList:
                                for k in range(len(color_list)):
                                    if color_list[k][0] == group.getFill():
                                        comp_fill_color = hex_to_rgb(
                                            color_list[k][1])
                                    if color_list[k][0] == group.getStroke():
                                        comp_border_color = hex_to_rgb(
                                            color_list[k][1])
                                comp_border_width = group.getStrokeWidth()
                            elif 'SPECIESGLYPH' in typeList:
                                for k in range(len(color_list)):
                                    if color_list[k][0] == group.getFill():
                                        spec_fill_color = hex_to_rgb(
                                            color_list[k][1])
                                    if color_list[k][0] == group.getStroke():
                                        spec_border_color = hex_to_rgb(
                                            color_list[k][1])
                                spec_border_width = group.getStrokeWidth()
                                name_list = []
                                for element in group.getListOfElements():
                                    name = element.getElementName()
                                    name_list.append(name)
                                    try:
                                        NumRenderpoints = element.getListOfElements(
                                        ).getNumRenderPoints()
                                    except:
                                        NumRenderpoints = 0
                                if name == "ellipse":  #circel and text-outside
                                    shapeIdx = 1
                                elif name == "polygon" and NumRenderpoints == 6:
                                    shapeIdx = 2
                                elif name == "polygon" and NumRenderpoints == 2:
                                    shapeIdx = 3
                                elif name == "polygon" and NumRenderpoints == 3:
                                    shapeIdx = 4
                                elif name == "rectangle" and spec_fill_color == '#ffffff' and spec_border_color == '#ffffff':
                                    shapeIdx = 5
                                #elif name == "ellipse" and flag_text_out == 1:
                                #    shapeIdx = 6
                                else:  # name == "rectangle"/demo combo/others as default (rectangle)
                                    shapeIdx = 0

                            elif 'REACTIONGLYPH' in typeList:
                                for k in range(len(color_list)):
                                    if color_list[k][0] == group.getStroke():
                                        reaction_line_color = hex_to_rgb(
                                            color_list[k][1])
                                reaction_line_width = group.getStrokeWidth()

            model = simplesbml.loadSBMLStr(sbmlStr)

            numFloatingNodes = model.getNumFloatingSpecies()
            FloatingNodes_ids = model.getListOfFloatingSpecies()
            numBoundaryNodes = model.getNumBoundarySpecies()
            BoundaryNodes_ids = model.getListOfBoundarySpecies()
            numRxns = model.getNumReactions()
            Rxns_ids = model.getListOfReactionIds()
            numComps = model.getNumCompartments()
            Comps_ids = model.getListOfCompartmentIds()
            numNodes = numFloatingNodes + numBoundaryNodes

            for i in range(numComps):
                temp_id = Comps_ids[i]
                vol = model.getCompartmentVolume(i)
                if temp_id == "_compartment_default_":
                    api.add_compartment(net_index,
                                        id=temp_id,
                                        volume=vol,
                                        size=Vec2(3900, 2400),
                                        position=Vec2(10, 10),
                                        fill_color=api.Color(255, 255, 255),
                                        border_color=api.Color(255, 255, 255),
                                        border_width=comp_border_width)
                else:
                    if len(comp_id_list) != 0:
                        #if mplugin is not None:
                        #for j in range(numComps):
                        for j in range(numCompGlyphs):
                            if comp_id_list[j] == temp_id:
                                dimension = comp_dimension_list[j]
                                position = comp_position_list[j]

                    else:  # no layout info about compartment,
                        # then the whole size of the canvas is the compartment size
                        # modify the compartment size using the max_rec function above
                        # random assigned network:
                        # dimension = [800,800]
                        # position = [40,40]
                        # the whole size of the compartment: 4000*2500
                        dimension = [3900, 2400]
                        position = [10, 10]
                        comp_fill_color = (255, 255, 255)
                        comp_border_color = (255, 255, 255)

                    api.add_compartment(
                        net_index,
                        id=temp_id,
                        volume=vol,
                        size=Vec2(dimension[0], dimension[1]),
                        position=Vec2(position[0], position[1]),
                        fill_color=api.Color(comp_fill_color[0],
                                             comp_fill_color[1],
                                             comp_fill_color[2]),
                        border_color=api.Color(comp_border_color[0],
                                               comp_border_color[1],
                                               comp_border_color[2]),
                        border_width=comp_border_width)

            comp_node_list = [0] * numComps
            #comp_node_list = [0]*numCompGlyphs
            for i in range(numComps):
                #for i in range(numCompGlyphs):
                comp_node_list[i] = []

            #if there is layout info:
            if len(spec_id_list) != 0:
                id_list = []
                nodeIdx_list = [
                ]  #get_nodes idx do not follow the same order of add_node
                nodeIdx_specGlyph_list = []
                nodeIdx_specGlyph_alias_list = []
                numSpec_in_reaction = len(spec_specGlyph_id_list)
                #numSpecGlyphs is larger than numSpec_in_reaction if there orphan nodes
                if numSpecGlyphs > numSpec_in_reaction:
                    if showDialogues:
                        wx.MessageBox("Orphan nodes are removed.", "Message",
                                      wx.OK | wx.ICON_INFORMATION)
                for i in range(numSpec_in_reaction):
                    temp_id = spec_specGlyph_id_list[i][0]
                    tempGlyph_id = spec_specGlyph_id_list[i][1]
                    dimension = spec_dimension_list[i]
                    position = spec_position_list[i]
                    comp_id = model.getCompartmentIdSpeciesIsIn(temp_id)
                    for j in range(numFloatingNodes):
                        if temp_id == FloatingNodes_ids[j]:
                            if temp_id not in id_list:
                                nodeIdx_temp = api.add_node(
                                    net_index,
                                    id=temp_id,
                                    floating_node=True,
                                    size=Vec2(dimension[0], dimension[1]),
                                    position=Vec2(position[0], position[1]),
                                    fill_color=api.Color(
                                        spec_fill_color[0], spec_fill_color[1],
                                        spec_fill_color[2]),
                                    border_color=api.Color(
                                        spec_border_color[0],
                                        spec_border_color[1],
                                        spec_border_color[2]),
                                    border_width=spec_border_width,
                                    shape_index=shapeIdx)
                                id_list.append(temp_id)
                                nodeIdx_list.append(nodeIdx_temp)
                                nodeIdx_specGlyph_list.append(
                                    [nodeIdx_temp, tempGlyph_id])
                            else:
                                index = id_list.index(temp_id)
                                nodeIdx_temp = api.add_alias(
                                    net_index,
                                    original_index=index,
                                    size=Vec2(dimension[0], dimension[1]),
                                    position=Vec2(position[0], position[1]))
                                id_list.append(temp_id)
                                nodeIdx_list.append(nodeIdx_temp)
                                nodeIdx_specGlyph_alias_list.append(
                                    [nodeIdx_temp, tempGlyph_id])
                            #for k in range(numComps):
                            for k in range(numCompGlyphs):
                                if len(comp_id_list
                                       ) != 0 and comp_id == comp_id_list[k]:
                                    comp_node_list[k].append(nodeIdx_temp)
                    for j in range(numBoundaryNodes):
                        if temp_id == BoundaryNodes_ids[j]:
                            if temp_id not in id_list:
                                nodeIdx_temp = api.add_node(
                                    net_index,
                                    id=temp_id,
                                    floating_node=False,
                                    size=Vec2(dimension[0], dimension[1]),
                                    position=Vec2(position[0], position[1]),
                                    fill_color=api.Color(
                                        spec_fill_color[0], spec_fill_color[1],
                                        spec_fill_color[2]),
                                    border_color=api.Color(
                                        spec_border_color[0],
                                        spec_border_color[1],
                                        spec_border_color[2]),
                                    border_width=spec_border_width,
                                    shape_index=shapeIdx)
                                id_list.append(temp_id)
                                nodeIdx_list.append(nodeIdx_temp)
                                nodeIdx_specGlyph_list.append(
                                    [nodeIdx_temp, tempGlyph_id])
                            else:
                                index = id_list.index(temp_id)
                                nodeIdx_temp = api.add_alias(
                                    net_index,
                                    original_index=index,
                                    size=Vec2(dimension[0], dimension[1]),
                                    position=Vec2(position[0], position[1]))
                                id_list.append(temp_id)
                                nodeIdx_list.append(nodeIdx_temp)
                                nodeIdx_specGlyph_alias_list.append(
                                    [nodeIdx_temp, tempGlyph_id])
                            #for k in range(numComps):
                            for k in range(numCompGlyphs):
                                if len(comp_id
                                       ) != 0 and comp_id == comp_id_list[k]:
                                    comp_node_list[k].append(nodeIdx_temp)

                if len(comp_id_list) != 0:
                    for i in range(numComps):
                        temp_id = Comps_ids[i]
                        if temp_id == '_compartment_default_':
                            node_list_default = [
                                item for item in range(numNodes)
                            ]
                            for j in range(len(node_list_default)):
                                api.set_compartment_of_node(
                                    net_index=net_index,
                                    node_index=node_list_default[j],
                                    comp_index=i)
                        #for j in range(numComps):
                        for j in range(numCompGlyphs):
                            if comp_id_list[j] == temp_id:
                                node_list_temp = comp_node_list[j]
                            else:
                                node_list_temp = []
                            for k in range(len(node_list_temp)):
                                #print(node_list_temp)
                                api.set_compartment_of_node(
                                    net_index=net_index,
                                    node_index=node_list_temp[k],
                                    comp_index=i)
                else:
                    for i in range(len(nodeIdx_list)):
                        api.set_compartment_of_node(net_index=net_index,
                                                    node_index=nodeIdx_list[i],
                                                    comp_index=0)

                #handle_positions, center_pos was set as the default:
                #can not find a way from libsml to do this so far

                nodeIdx_specGlyph_whole_list = nodeIdx_specGlyph_list + nodeIdx_specGlyph_alias_list

                for i in range(numReactionGlyphs):
                    src = []
                    dst = []
                    temp_id = reaction_id_list[i]
                    kinetics = kinetics_list[i]
                    rct_num = len(rct_specGlyph_list[i])
                    prd_num = len(prd_specGlyph_list[i])

                    for j in range(rct_num):
                        temp_specGlyph_id = rct_specGlyph_list[i][j]
                        for k in range(numSpec_in_reaction):
                            if temp_specGlyph_id == nodeIdx_specGlyph_whole_list[
                                    k][1]:
                                rct_idx = nodeIdx_specGlyph_whole_list[k][0]
                        src.append(rct_idx)

                    for j in range(prd_num):
                        temp_specGlyph_id = prd_specGlyph_list[i][j]
                        for k in range(numSpec_in_reaction):
                            if temp_specGlyph_id == nodeIdx_specGlyph_whole_list[
                                    k][1]:
                                prd_idx = nodeIdx_specGlyph_whole_list[k][0]
                        dst.append(prd_idx)

                    api.add_reaction(net_index,
                                     id=temp_id,
                                     reactants=src,
                                     products=dst,
                                     rate_law=kinetics,
                                     fill_color=api.Color(
                                         reaction_line_color[0],
                                         reaction_line_color[1],
                                         reaction_line_color[2]),
                                     line_thickness=reaction_line_width)

            else:  # there is no layout information, assign position randomly and size as default
                comp_id_list = Comps_ids

                for i in range(numFloatingNodes):
                    temp_id = FloatingNodes_ids[i]
                    comp_id = model.getCompartmentIdSpeciesIsIn(temp_id)
                    nodeIdx_temp = api.add_node(
                        net_index,
                        id=temp_id,
                        size=Vec2(60, 40),
                        floating_node=True,
                        position=Vec2(40 + math.trunc(_random.random() * 800),
                                      40 + math.trunc(_random.random() * 800)),
                        fill_color=api.Color(spec_fill_color[0],
                                             spec_fill_color[1],
                                             spec_fill_color[2]),
                        border_color=api.Color(spec_border_color[0],
                                               spec_border_color[1],
                                               spec_border_color[2]),
                        border_width=spec_border_width,
                        shape_index=shapeIdx)
                    for j in range(numComps):
                        if comp_id == comp_id_list[j]:
                            comp_node_list[j].append(nodeIdx_temp)

                for i in range(numBoundaryNodes):
                    temp_id = BoundaryNodes_ids[i]
                    comp_id = model.getCompartmentIdSpeciesIsIn(temp_id)
                    nodeIdx_temp = api.add_node(
                        net_index,
                        id=temp_id,
                        size=Vec2(60, 40),
                        floating_node=False,
                        position=Vec2(40 + math.trunc(_random.random() * 800),
                                      40 + math.trunc(_random.random() * 800)),
                        fill_color=api.Color(spec_fill_color[0],
                                             spec_fill_color[1],
                                             spec_fill_color[2]),
                        border_color=api.Color(spec_border_color[0],
                                               spec_border_color[1],
                                               spec_border_color[2]),
                        border_width=spec_border_width,
                        shape_index=shapeIdx)
                    for j in range(numComps):
                        if comp_id == comp_id_list[j]:
                            comp_node_list[j].append(nodeIdx_temp)

                for i in range(numComps):
                    temp_id = Comps_ids[i]
                    for j in range(numComps):
                        if comp_id_list[j] == temp_id:
                            node_list_temp = comp_node_list[j]
                        for k in range(len(node_list_temp)):
                            api.set_compartment_of_node(
                                net_index=net_index,
                                node_index=node_list_temp[k],
                                comp_index=i)

                #handle_positions, center_pos was set as the default

                numNodes = api.node_count(net_index)
                allNodes = api.get_nodes(net_index)

                for i in range(numRxns):
                    src = []
                    dst = []
                    temp_id = Rxns_ids[i]
                    kinetics = model.getRateLaw(i)
                    rct_num = model.getNumReactants(i)
                    prd_num = model.getNumProducts(i)

                    for j in range(rct_num):
                        rct_id = model.getReactant(temp_id, j)
                        for k in range(numNodes):
                            if allNodes[k].id == rct_id:
                                src.append(allNodes[k].index)

                    for j in range(prd_num):
                        prd_id = model.getProduct(temp_id, j)
                        for k in range(numNodes):
                            if allNodes[k].id == prd_id:
                                dst.append(allNodes[k].index)

                    api.add_reaction(net_index,
                                     id=temp_id,
                                     reactants=src,
                                     products=dst,
                                     rate_law=kinetics,
                                     fill_color=api.Color(
                                         reaction_line_color[0],
                                         reaction_line_color[1],
                                         reaction_line_color[2]),
                                     line_thickness=reaction_line_width)
示例#16
0
    def Apply(self, event):
        """
        If apply button is clicked, the nodes will be arranged in a circle
        using either a default radius or a user input radius.
        """
        def translate_nodes(node_indices, r, phi):
            """
            Takes in list of node indices, desired radius, and phi
            and moves the current node
            to its new position
            """
            # Iterate through the nodes and change their position.
            node_num = 0
            for i in node_ind:
                theta = node_num * phi  # angle position for node
                newPos = self.get_new_position(i, r, theta)
                if newPos[0] < 0 or newPos[1] < 0:
                    wx.MessageBox("Please increase radius size", "Message",
                                  wx.OK | wx.ICON_INFORMATION)
                    return
                api.move_node(0, i, newPos, False)
                node_num += 1  # updating node number

        # Get button and checkbox state
        btn_state = event.GetEventObject().GetValue()
        # chk_state = self.OnDefaultCheck()
        chk_state = self.defaultCheck.GetValue()

        # If the button is pressed, arrange the nodes into a circle
        if btn_state is True:
            # Get number of nodes selected
            node_len = len(api.selected_node_indices())
            # get list of node indices
            node_ind = api.selected_node_indices()

            # If no nodes selected raise error
            select = self.CheckSelection(node_len)
            if select is True:
                return

            # If default radius is checked
            if chk_state is True:
                # Compute the expected center of the circle
                center = self.find_center(node_len, node_ind)
                # Compute the angle step between each node
                phi = 2 * math.pi / node_len
                r = center[0]  # radius
                translate_nodes(node_ind, r, phi)

            else:
                r = self.radiusValue
                center = Vec2(r, r)
                phi = 2 * math.pi / node_len  # angle step between each node
                translate_nodes(node_ind, r, phi)  # translating nodes

            # Making the reactions straight lines
            rxns = api.get_reaction_indices(0)
            for rxn in rxns:
                api.update_reaction(net_index=0,
                                    reaction_index=rxn,
                                    use_bezier=False)
            # Setting button state back to False (unclicked)
            event.GetEventObject().SetValue(False)