Exemplo n.º 1
0
class ArrowDesigner(WindowedPlugin):
    """
    The ArrowDesigner plugin that subclasses WindowedPlugin.
    """
    metadata = PluginMetadata(
        name='ArrowDesigner',
        author='Gary Geng',
        version='0.0.1',
        short_desc='Arrow tip designer for reactions.',
        long_desc='Arrow tip designer for reactions.',
        category=PluginCategory.APPEARANCE,
    )

    def __init__(self):
        super().__init__()
        self.arrow_tip = api.get_arrow_tip()

    def create_window(self, dialog):
        """
        Called when creating a window. Create the designer window as well as control buttons.
        """
        window = wx.Window(dialog, size=(500, 500))
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.designer = DesignerWindow(window, self.arrow_tip)
        save_btn = wx.Button(window, label='Save')
        save_btn.Bind(wx.EVT_BUTTON, self.OnSave)
        restore_btn = wx.Button(window, label='Restore default')
        restore_btn.Bind(wx.EVT_BUTTON, self.OnRestore)
        sizerflags = wx.SizerFlags().Align(wx.ALIGN_CENTER_HORIZONTAL).Border(
            wx.TOP, 20)
        sizer.Add(self.designer, sizerflags)
        sizer.Add(save_btn, sizerflags)
        sizer.Add(restore_btn, sizerflags)
        dialog.SetSizer(sizer)
        return window

    def OnSave(self, evt):
        """
        Handler for the "save" button. Save the new arrow tip.
        """
        api.set_arrow_tip(self.arrow_tip)
        api.refresh_canvas()

    def OnRestore(self, evt):
        """
        Update the arrow point to be set to default values.
        """
        default_tip = api.get_default_arrow_tip()
        api.set_arrow_tip(default_tip)
        self.designer.update_arrow_tip(default_tip)
Exemplo n.º 2
0
class LayoutNetworkX(WindowedPlugin):
    metadata = PluginMetadata(
        name='Auto Layout',
        author='Carmen and Herbert M Sauro',
        version='0.5.2',
        short_desc='Auto Layout using networkX.',
        long_desc='Rearrange a random network into a neat auto layout',
        category=PluginCategory.UTILITIES,
    )

    def create_window(self, dialog):
        '''
        Create a window with several inputs and buttons.
        Args:
            self
            dialog
        '''
        # TODO: k, gravity, useMagnetism, useBoundary, useGrid
        self.window = wx.Panel(dialog, pos=(5,100), size=(350, 220))
        self.sizer = wx.FlexGridSizer(cols=2, vgap=10, hgap=0)
        self.sizer.AddGrowableCol(0, 0.6)
        self.sizer.AddGrowableCol(1, 0.4)

        self.sizer.Add((0, 10))
        self.sizer.Add((0, 10))

        self.MaxIterText = wx.TextCtrl(self.window, -1, "100", size=(100, -1))
        self.MaxIterText.SetInsertionPoint(0)
        self.MaxIterText.Bind(wx.EVT_TEXT, self.OnText_MaxIter)
        self.MaxIterValue = int(self.MaxIterText.GetValue())
        self.AddField('Max Number of Iterations', self.MaxIterText)

        self.kText = wx.TextCtrl(self.window, -1, "70", size=(100, -1))
        self.kText.SetInsertionPoint(0)
        self.kText.Bind(wx.EVT_TEXT, self.OnText_k)
        self.kValue = float(self.kText.GetValue())        

        self.AddField('k (float > 0)', self.kText)

        self.scaleText = wx.TextCtrl(self.window, -1, "550", size=(100, -1))
        self.scaleText.SetInsertionPoint(0)
        self.scaleText.Bind(wx.EVT_TEXT, self.OnText_scale)
        self.scaleValue = float(self.scaleText.GetValue())

        self.AddField('Scale of Layout', self.scaleText)

        self.useCentroid = False
        self.centroidCheckBox = wx.CheckBox(self.window)
        self.centroidCheckBox.Bind(wx.EVT_CHECKBOX, self.OnCheckUseCentroid)

        self.AddField('Also Arrange Centroids', self.centroidCheckBox)

        # add spacer left of button
        self.sizer.Add((0, 0))
        apply_btn = wx.Button(self.window, -1, 'Run', (220, 130))
        apply_btn.Bind(wx.EVT_BUTTON, self.Apply)
        self.sizer.Add(apply_btn)
        self.window.SetPosition (wx.Point(10,10))
        self.window.SetSizer(self.sizer)
        return self.window

    def AddField(self, text, field):
        self.sizer.Add(wx.StaticText(self.window, label=text), wx.SizerFlags().Border(wx.LEFT, 20))
        self.sizer.Add(field)

    def OnText_MaxIter(self, evt):
        try:
          update = evt.GetString()
          if update != '':
              self.MaxIterValue = int(self.MaxIterText.GetValue())
        except ValueError:
           wx.MessageBox('Value must be a number', 'Error', wx.OK | wx.ICON_INFORMATION)

    def OnText_k(self, evt):
        try:
           update = evt.GetString()
           if update != '':
              self.kValue = float(self.kText.GetValue())
        except ValueError:
           wx.MessageBox('Value must be a number', 'Error', wx.OK | wx.ICON_INFORMATION)

    def OnText_scale(self, evt):
        try:
           update = evt.GetString()
           if update != '':
              self.scaleValue = float(self.scaleText.GetValue())
        except ValueError:
           wx.MessageBox('Value must be a number', 'Error', wx.OK | wx.ICON_INFORMATION)

    def OnCheckUseCentroid(self, evt):
        cb = evt.GetEventObject() 
        self.useCentroid = cb.GetValue()
           
    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)
Exemplo n.º 3
0
class AddReaction(WindowedPlugin):
    metadata = PluginMetadata(
        name='AddReaction',
        author='Jin Xu and Herbert Sauro',
        version='0.0.1',
        short_desc='Add Reactions.',
        long_desc=
        'Add different reactions including UniUni, BiUni, UniBi and BiBi.',
        category=PluginCategory.UTILITIES,
    )

    def __init__(self):
        """
      Initialize the StructuralAnalysis Plugin.
      Args:
         self
      """
        super().__init__()
        self.uniuniState = False
        self.biuniState = False
        self.unibiState = False
        self.bibiState = False
        self.src = []
        self.dest = []

    def create_window(self, dialog):
        """
      Create a window to do the structural analysis.
      Args:
         self
         dialog
      """
        window = wx.Panel(dialog, pos=(5, 100), size=(150, 190))

        wx.StaticText(window, -1, 'Select reaction type', (15, 10))
        wx.StaticText(window, -1, 'then select nodes:', (15, 25))

        self.UniUni_btn = wx.ToggleButton(window,
                                          -1,
                                          'UniUni', (36, 22 + 25),
                                          size=(62, 22))
        self.UniUni_btn.Bind(wx.EVT_TOGGLEBUTTON, self.UniUni)

        self.BiUni_btn = wx.ToggleButton(window,
                                         -1,
                                         'BiUni', (36, 47 + 25),
                                         size=(62, 22))
        self.BiUni_btn.Bind(wx.EVT_TOGGLEBUTTON, self.BiUni)

        self.UniBi_btn = wx.ToggleButton(window,
                                         -1,
                                         'UniBi', (36, 72 + 25),
                                         size=(62, 22))
        self.UniBi_btn.Bind(wx.EVT_TOGGLEBUTTON, self.UniBi)

        self.BiBi_btn = wx.ToggleButton(window,
                                        -1,
                                        'BiBi', (36, 97 + 25),
                                        size=(62, 22))
        self.BiBi_btn.Bind(wx.EVT_TOGGLEBUTTON, self.BiBi)

        window.SetPosition(wx.Point(10, 10))
        return window

    def on_did_create_dialog(self):
        # Set position of popup window to top-left corner of screen
        self.dialog.SetPosition((240, 250))

    def on_will_close_window(self, evt):
        # print ("***** Window Closed *****")
        evt.Skip()

    def getUniqueName(self, base: str, names: list) -> str:
        increment = 0
        # keep incrementing until you find a unique Id
        while True:
            suffix = '_{}'.format(increment)

            cur_id = base + suffix

            if cur_id in names:
                increment += 1
                continue
            else:
                # loop finished normally; done
                return cur_id

    def addReaction(self, src, dest):
        # THis method is callde for all reactions
        names = []
        # Get a unique reaction name
        for r in api.get_reactions(0):
            names.append(r.id)
        reactionId = self.getUniqueName('reaction', names)
        r_idx = api.add_reaction(0,
                                 reactionId,
                                 src,
                                 dest,
                                 fill_color=api.Color(129, 123, 255))

    def on_selection_did_change(self, evt):
        """
      Overrides base class event handler to update number of items selected.
      Args:
         self
         node_indices(List[int]): List of node indices changed.
         reaction_indices (List[int]): List of reaction indices changed.
         compartment_indices (List[int]): List of compartment indices changed.
      """
        if len(list(evt.node_indices)) == 0:
            self.src = []
            self.dest = []
            return

        if (not self.uniuniState) and (not self.biuniState) and \
              (not self.unibiState) and (not self.bibiState):
            return

        self.node_clicked = list(evt.node_indices)

        try:
            if self.uniuniState:
                if len(self.src) == 0:
                    self.src.append(self.node_clicked[0])
                    return

                if len(self.dest) == 0:
                    self.dest.append(self.node_clicked[0])
                    self.addReaction(self.src, self.dest)
                    return

            if self.biuniState:
                if len(self.src) == 0:
                    self.src.append(self.node_clicked[0])
                    return

                if len(self.src) == 1:
                    self.src.append(self.node_clicked[0])
                    return

                if (len(self.src) <= 2) and len(self.dest) == 0:
                    self.dest.append(self.node_clicked[0])
                    self.addReaction(self.src, self.dest)
                    return

            if self.unibiState:
                if len(self.src) == 0:
                    self.src.append(self.node_clicked[0])
                    return

                if len(self.dest) == 0:
                    self.dest.append(self.node_clicked[0])
                    return

                if (len(self.src) <= 1) and len(self.dest) == 1:
                    self.dest.append(self.node_clicked[0])
                    self.addReaction(self.src, self.dest)
                    return

            if self.bibiState:
                if len(self.src) == 0:
                    self.src.append(self.node_clicked[0])
                    return

                if len(self.src) == 1:
                    self.src.append(self.node_clicked[0])
                    return

                if len(self.dest) == 0:
                    self.dest.append(self.node_clicked[0])
                    return

                if (len(self.src) <= 2) and len(self.dest) == 1:
                    self.dest.append(self.node_clicked[0])
                    self.addReaction(self.src, self.dest)
                    return
        except:
            pass  #wx.MessageBox("Error: Try again", "Message", wx.OK | wx.ICON_INFORMATION)

    def UniUni(self, evt):
        """
      Handler for the "UniUni" button. add a UniUni reaction.
      """
        state = evt.GetEventObject().GetValue()
        if state == True:
            self.src = []
            self.dest = []
            # This code is to make the buttons work as a radionbutton
            self.uniuniState = True
            self.biuniState = False
            self.unibiState = False
            self.bibiState = False
            self.BiUni_btn.SetValue(False)
            self.UniBi_btn.SetValue(False)
            self.BiBi_btn.SetValue(False)
        else:
            self.uniuniState = False

    def BiUni(self, evt):
        """
      Handler for the "BiUni" button. add a BiUni reaction.
      """
        state = evt.GetEventObject().GetValue()
        if state == True:
            self.src = []
            self.dest = []

            # This code is to make the buttons work as a radionbutton
            self.uniuniState = False
            self.biuniState = True
            self.unibiState = False
            self.bibiState = False
            self.UniUni_btn.SetValue(False)
            self.UniBi_btn.SetValue(False)
            self.BiBi_btn.SetValue(False)
        else:
            self.biuniState = False

    def UniBi(self, evt):
        """
      Handler for the "UniBi" button. add a UniBi reaction.
      """
        state = evt.GetEventObject().GetValue()
        if state == True:
            self.src = []
            self.dest = []

            # This code is to make the buttons work as a radionbutton
            self.uniuniState = False
            self.biuniState = False
            self.unibiState = True
            self.bibiState = False
            self.UniUni_btn.SetValue(False)
            self.BiUni_btn.SetValue(False)
            self.BiBi_btn.SetValue(False)
        else:
            self.unibiState = False

    def BiBi(self, evt):
        """
      Handler for the "UniBi" button. add a UniBi reaction.
      """
        state = evt.GetEventObject().GetValue()
        if state == True:
            self.src = []
            self.dest = []

            # This code is to make the buttons work as a radionbutton
            self.uniuniState = False
            self.biuniState = False
            self.unibiState = False
            self.bibiState = True
            self.UniUni_btn.SetValue(False)
            self.BiUni_btn.SetValue(False)
            self.UniBi_btn.SetValue(False)
        else:
            self.bibiState = False
Exemplo n.º 4
0
class DuplicateReaction(CommandPlugin):
    metadata = PluginMetadata(
        name='DuplicateReaction',
        author='Claire Samuels',
        version='0.0.1',
        short_desc='Duplicate a reaction.',
        long_desc=
        'Creates an exact copy of the selected reactions and all connected nodes.',
        category=PluginCategory.UTILITIES,
    )

    def __init__(self):
        """
      Initialize the DuplicateReaction.

      Args:
          self

      """
        super().__init__()

    def run(self):

        net_index = 0

        selected_reacts = api.selected_reaction_indices()
        if len(selected_reacts) < 1:
            selected_reacts = api.get_reaction_indices(net_index)

        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

        orig_node_set = set()
        reaction_info = {}

        for r_index in selected_reacts:
            r = api.get_reaction_by_index(net_index, r_index)
            r_info = {"sources": r.sources, "targets": r.targets, "id": r.id}
            reaction_info[r_index] = r_info
            orig_node_set = orig_node_set.union(set(r.sources))
            orig_node_set = orig_node_set.union(set(r.targets))

        node_indices = {}
        for n_index in orig_node_set:
            new_index = copy_node(n_index, net_index)
            node_indices[n_index] = new_index

        for reaction in reaction_info:
            new_sources = []
            for src in reaction_info[reaction]["sources"]:
                new_sources.append(node_indices[src])
            new_targets = []
            for trg in reaction_info[reaction]["targets"]:
                new_targets.append(node_indices[trg])
            reac_id = reaction_info[reaction]["id"]
            n_index = api.add_reaction(net_index,
                                       id="copy" + str(reaction),
                                       reactants=new_sources,
                                       products=new_targets)
            api.update_reaction(net_index,
                                n_index,
                                id='{}_copy_{}'.format(reac_id, n_index))
Exemplo n.º 5
0
class StructuralAnalysis(WindowedPlugin):
    metadata = PluginMetadata(
        name='StructuralAnalysis',
        author='Jin Xu',
        version='0.0.1',
        short_desc='Structural Analysis.',
        long_desc=
        'StructuralAnalysis Plugin is to calculate and visualize the stoichiometry matrix and conserved moieties for the network.',
        category=PluginCategory.ANALYSIS)

    def __init__(self):
        """
        Initialize the StructuralAnalysis Plugin.
        Args:
            self
        """
        super().__init__()
        self.index_list = []

    def create_window(self, dialog):
        """
        Create a window to do the structural analysis.
        Args:
            self
            dialog
        """
        topPanel = wx.Panel(dialog, pos=(0, 0), size=(700, 500))

        # Create two panels size by side
        panel1 = wx.Panel(topPanel, -1, pos=(0, 100), size=(200, 100))
        panel2 = wx.Panel(topPanel, -1, pos=(100, 100), size=(450, 100))

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(panel1, 0, wx.EXPAND | wx.ALL, border=10)
        sizer.Add(panel2, 0, wx.EXPAND | wx.ALL, border=10)

        topPanel.SetSizer(sizer)

        # Add a notebook to the second panel
        nb = wx.Notebook(panel2)

        # Create the tabs
        self.tab1 = TabOne(nb)
        self.tab2 = TabTwo(nb)
        nb.AddPage(self.tab1, "Stoichiometry Matrix")
        nb.AddPage(self.tab2, "Conservation Matrix")

        # Make sure the second panel fills the right side.
        sizer = wx.BoxSizer()
        sizer.Add(nb, 1, wx.EXPAND)
        panel2.SetSizer(sizer)

        Compute_btn = wx.Button(panel1, -1, 'Compute Matrix', (20, 20))
        Compute_btn.Bind(wx.EVT_BUTTON, self.Compute)

        wx.StaticText(panel1, -1, 'Select a row from the table of', (20, 100))
        wx.StaticText(panel1, -1, 'Moiety Conservation Laws', (20, 120))
        wx.StaticText(panel1, -1, 'and pick a color:', (20, 140))

        Picker = wx.ColourPickerCtrl(panel1, pos=(20, 160))
        Picker.Bind(wx.EVT_COLOURPICKER_CHANGED, self.color_callback)

        wx.StaticText(panel1, -1, 'Unhighlight the nodes:', (20, 240))
        Clear_Btn = wx.Button(panel1, -1, 'Clear', (20, 260))
        Clear_Btn.Bind(wx.EVT_BUTTON, self.unhighlight)

        return topPanel

    def on_did_create_dialog(self):
        # Set position of popup window to top-left corner of screen
        self.dialog.SetPosition((240, 250))

    def Compute(self, evt):
        """
        Handler for the "Compute" button.
        Get the network on canvas.
        Calculate the Stoichiometry Matrix and Conservation Matrix for the randon network.
        """
        def nullspace(A, atol=1e-13, rtol=0):
            A = _np.atleast_2d(A)
            u, s, vh = _np.linalg.svd(A)
            tol = max(atol, rtol * s[0])
            nnz = (s >= tol).sum()
            ns = vh[nnz:].conj().T
            return ns

        #https://gist.github.com/sgsfak/77a1c08ac8a9b0af77393b24e44c9547
        def rref(B, tol=1e-8, debug=False):
            A = B.copy()
            rows, cols = A.shape
            r = 0
            pivots_pos = []
            row_exchanges = _np.arange(rows)
            for c in range(cols):
                if debug:
                    print("Now at row", r, "and col", c, "with matrix:")
                    print(A)

                ## Find the pivot row:
                pivot = _np.argmax(_np.abs(A[r:rows, c])) + r
                m = _np.abs(A[pivot, c])
                if debug: print("Found pivot", m, "in row", pivot)
                if m <= tol:
                    ## Skip column c, making sure the approximately zero terms are
                    ## actually zero.
                    A[r:rows, c] = _np.zeros(rows - r)
                    if debug:
                        print("All elements at and below (", r, ",", c,
                              ") are zero.. moving on..")
                else:
                    ## keep track of bound variables
                    pivots_pos.append((r, c))

                    if pivot != r:
                        ## Swap current row and pivot row
                        A[[pivot, r], c:cols] = A[[r, pivot], c:cols]
                        row_exchanges[[pivot, r]] = row_exchanges[[r, pivot]]

                        if debug:
                            print("Swap row", r, "with row", pivot, "Now:")
                            print(A)

                    ## Normalize pivot row
                    A[r, c:cols] = A[r, c:cols] / A[r, c]

                    ## Eliminate the current column
                    v = A[r, c:cols]
                    ## Above (before row r):
                    if r > 0:
                        ridx_above = _np.arange(r)
                        A[ridx_above,
                          c:cols] = A[ridx_above, c:cols] - _np.outer(
                              v, A[ridx_above, c]).T
                        if debug:
                            print("Elimination above performed:")
                            print(A)
                    ## Below (after row r):
                    if r < rows - 1:
                        ridx_below = _np.arange(r + 1, rows)
                        A[ridx_below,
                          c:cols] = A[ridx_below, c:cols] - _np.outer(
                              v, A[ridx_below, c]).T
                        if debug:
                            print("Elimination below performed:")
                            print(A)
                    r += 1
                ## Check if done
                if r == rows:
                    break
            return (A, pivots_pos, row_exchanges)

        netIn = 0
        numNodes = api.node_count(netIn)

        if numNodes == 0:
            wx.MessageBox("Please import a network on canvas", "Message",
                          wx.OK | wx.ICON_INFORMATION)
        else:
            allNodes = api.get_nodes(netIn)
            #id = allNodes[0].id[0:-2]
            node = allNodes[0]
            try:
                primitive, transform = node.shape.items[0]
                self.default_color = primitive.fill_color
            except:
                self.default_color = api.Color(255, 204,
                                               153)  #random network node color

            largest_node_index = 0
            for i in range(numNodes):
                if allNodes[i].index > largest_node_index:
                    largest_node_index = allNodes[i].index
            row = largest_node_index + 1
            numReactions = api.reaction_count(netIn)
            #print("numReactions:", numReactions)
            col = numReactions
            self.st = _np.zeros((row, col))
            allReactions = api.get_reactions(netIn)
            for i in range(numReactions):
                for j in range(len(allReactions[i].sources)):
                    #print(allReactions[i].sources[j])
                    for m in range(row):
                        if allReactions[i].sources[j] == m:
                            self.st.itemset((m, i), -1)
                for j in range(len(allReactions[i].targets)):
                    #print(allReactions[i].targets[j])
                    for m in range(row):
                        if allReactions[i].targets[j] == m:
                            self.st.itemset((m, i), 1)

            stt = _np.transpose(self.st)
            m = _np.transpose(nullspace(stt))
            moi_mat = rref(m)[0]

            # set all the values of non-existing nodes to zero
            for i in range(moi_mat.shape[0]):
                for j in range(moi_mat.shape[1]):
                    if _np.array_equal(self.st[j, :],
                                       _np.zeros(self.st.shape[1])):
                        moi_mat.itemset((i, j), 0.)

            for i in range(self.st.shape[1]):
                self.tab1.grid_st.SetColLabelValue(i, "J" + str(i))
            for i in range(self.st.shape[0]):
                #self.tab1.grid_st.SetRowLabelValue(i, id + "_" + str(i))
                id = allNodes[i].id
                self.tab1.grid_st.SetRowLabelValue(i, id)

            for row in range(self.st.shape[0]):
                for col in range(self.st.shape[1]):
                    self.tab1.grid_st.SetCellValue(
                        row, col, "%d" % self.st.item(row, col))

            for i in range(moi_mat.shape[1]):
                #self.tab2.grid_moi.SetColLabelValue(i, id + "_" + str(i))
                id = allNodes[i].id
                self.tab2.grid_moi.SetColLabelValue(i, id)

            CSUM_id = 0

            for i in range(moi_mat.shape[0]):
                a = moi_mat[i, :]
                a = [0. if abs(a_) < 0.005 else a_
                     for a_ in a]  # some elements are very small
                if _np.array_equal(
                        a, _np.zeros(moi_mat.shape[1])
                ):  # delete the row if all the elements are zero
                    CSUM_id = CSUM_id
                else:
                    self.tab2.grid_moi.SetRowLabelValue(
                        CSUM_id, "CSUM" + str(CSUM_id))

                    for j in range(moi_mat.shape[1]):
                        #self.tab2.grid_moi.SetCellValue(CSUM_id, j, format (moi_mat[i][j], ".2f"))
                        self.tab2.grid_moi.SetCellValue(
                            CSUM_id, j, format(a[j], ".2f"))
                    CSUM_id += 1

    def printSelectedCells(self, top_left, bottom_right):
        """
        Based on code from http://ginstrom.com/scribbles/2008/09/07/getting-the-selected-cells-from-a-wxpython-grid/
        """
        cells = []

        rows_start = top_left[0]
        rows_end = bottom_right[0]
        cols_start = top_left[1]
        cols_end = bottom_right[1]
        rows = range(rows_start, rows_end + 1)
        cols = range(cols_start, cols_end + 1)
        cells.extend([(row, col) for row in rows for col in cols])

        self.index_list = []
        for cell in cells:
            row, col = cell
            value = self.tab2.grid_moi.GetCellValue(row, col)
            if value != "0.00" and value != "+0.00" and value != "-0.00" and value != "":
                self.index_list.append(int(col))
            #print("selected nodes:", self.index_list)

    def color_callback(self, evt):
        """
        Get whatever cells are currently selected
        """

        cells = self.tab2.grid_moi.GetSelectedCells()
        if not cells:
            if self.tab2.grid_moi.GetSelectionBlockTopLeft():
                top_left = self.tab2.grid_moi.GetSelectionBlockTopLeft()[0]
                bottom_right = self.tab2.grid_moi.GetSelectionBlockBottomRight(
                )[0]
                self.printSelectedCells(top_left, bottom_right)
            #else:
            #    print (self.currentlySelectedCell)
        else:
            print("no cells are selected")
        """
        Callback for the color picker control; sets the color of every node/reaction selected.
        """

        wxcolor = evt.GetColour()
        color = Color.from_rgb(wxcolor.GetRGB())

        # start group action context for undo purposes
        with api.group_action():
            # color selected nodes
            #for index in api.selected_node_indices():

            if len(self.index_list) == 0:
                wx.MessageBox("Please select a row and pick a color again",
                              "Message", wx.OK | wx.ICON_INFORMATION)
            try:
                for index in self.index_list:
                    #api.update_node(api.cur_net_index(), index, fill_color=color, forder_color=color)
                    api.update_node(api.cur_net_index(),
                                    index,
                                    fill_color=color)
            except:
                wx.MessageBox("Please select a row and pick a color again",
                              "Message", wx.OK | wx.ICON_INFORMATION)

    def unhighlight(self, evt):
        """
        Callback for the color picker control; sets the color of every node/reaction selected.
        """

        # start group action context for undo purposes
        with api.group_action():
            # color selected nodes
            #for index in api.selected_node_indices():
            try:
                for index in self.index_list:
                    api.update_node(api.cur_net_index(),
                                    index,
                                    fill_color=self.default_color)
            except:
                wx.MessageBox("There is no highlighted nodes", "Message",
                              wx.OK | wx.ICON_INFORMATION)
Exemplo n.º 6
0
class RandomNetwork(WindowedPlugin):
    metadata = PluginMetadata(
        name='RandomNetwork',
        author='Jin Xu, Herbert M Sauro',
        version='0.0.1',
        short_desc='Random network.',
        long_desc=
        'Display a random network with certain number of species and reactions as input.',
        category=PluginCategory.UTILITIES)

    def __init__(self):
        """
        Initialize the RandomNetwork.

        Args:
            self

        """
        super().__init__()

    def create_window(self, dialog):
        """
        Create a window with several inputs and buttons.
        Args:
            self
            dialog
        """

        window = wx.Panel(dialog, pos=(5, 100), size=(300, 320))

        numSpecs = wx.StaticText(window, -1, 'Number of Species:', (20, 20))
        self.numSpecsText = wx.TextCtrl(window,
                                        -1,
                                        str(DefaultValues.maxSpecies),
                                        (160, 20),
                                        size=(100, -1))
        self.numSpecsText.SetInsertionPoint(0)
        self.numSpecsText.Bind(wx.EVT_TEXT, self.OnText_numSpecs)
        self.numSpecsValue = int(self.numSpecsText.GetValue())

        numRxns = wx.StaticText(window, -1, 'Number of Reactions:', (20, 50))
        self.numRxnsText = wx.TextCtrl(window,
                                       -1,
                                       str(DefaultValues.maxReactions),
                                       (160, 50),
                                       size=(100, -1))
        self.numRxnsText.SetInsertionPoint(0)
        self.numRxnsText.Bind(wx.EVT_TEXT, self.OnText_numRxns)
        self.numRxnsValue = int(self.numRxnsText.GetValue())

        probUniUni = wx.StaticText(window, -1, 'Probability of UniUni:',
                                   (20, 90))
        self.probUniUniText = wx.TextCtrl(window,
                                          -1,
                                          str(DefaultValues.probUniUniValue),
                                          (160, 90),
                                          size=(100, -1))
        self.probUniUniText.SetInsertionPoint(0)
        self.probUniUniText.Bind(wx.EVT_TEXT, self.OnText_UniUni)
        self.probUniUniValue = float(self.probUniUniText.GetValue())

        probBiUni = wx.StaticText(window, -1, 'Probability of BiUni:',
                                  (20, 120))
        self.probBiUniText = wx.TextCtrl(window,
                                         -1,
                                         str(DefaultValues.probBiUniValue),
                                         (160, 120),
                                         size=(100, -1))
        self.probBiUniText.SetInsertionPoint(0)
        self.probBiUniText.Bind(wx.EVT_TEXT, self.OnText_BiUni)
        self.probBiUniValue = float(self.probBiUniText.GetValue())

        probUniBi = wx.StaticText(window, -1, 'Probability of UniBi:',
                                  (20, 150))
        self.probUniBiText = wx.TextCtrl(window,
                                         -1,
                                         str(DefaultValues.probUniBiValue),
                                         (160, 150),
                                         size=(100, -1))
        self.probUniBiText.SetInsertionPoint(0)
        self.probUniBiText.Bind(wx.EVT_TEXT, self.OnText_UniBi)
        self.probUniBiValue = float(self.probUniBiText.GetValue())

        probBiBi = wx.StaticText(window, -1, 'Probability of BiBi:', (20, 180))
        self.probBiBiText = wx.TextCtrl(window,
                                        -1,
                                        str(DefaultValues.probBiBiValue),
                                        (160, 180),
                                        size=(100, -1))
        self.probBiBiText.SetInsertionPoint(0)
        self.probBiBiText.Bind(wx.EVT_TEXT, self.OnText_BiBi)
        self.probBiBiValue = float(self.probBiBiText.GetValue())

        randomSeed = wx.StaticText(window, -1, 'Random seed:', (20, 210))
        randomSeed = wx.StaticText(window, -1, '0 means no seed setup',
                                   (20, 230))
        self.randomSeedText = wx.TextCtrl(window,
                                          -1,
                                          str(DefaultValues.randomSeed),
                                          (160, 210),
                                          size=(100, -1))
        self.randomSeedText.SetInsertionPoint(0)
        self.randomSeedText.Bind(wx.EVT_TEXT, self.OnText_randomSeed)
        self.randomSeedValue = float(self.randomSeedText.GetValue())

        apply_btn = wx.Button(window, -1, 'Apply', (160, 250))
        apply_btn.Bind(wx.EVT_BUTTON, self.Apply)

        return window

    def OnText_numSpecs(self, evt):
        update = evt.GetString()
        if update != '':
            try:
                self.numSpecsValue = int(self.numSpecsText.GetValue())
            except:
                wx.MessageBox(
                    "Please enter an integer for the number of species.",
                    "Message", wx.OK | wx.ICON_INFORMATION)

    def OnText_numRxns(self, evt):
        update = evt.GetString()
        if update != '':
            try:
                self.numRxnsValue = int(self.numRxnsText.GetValue())
            except:
                wx.MessageBox(
                    "Please enter an integer for the number of reactions.",
                    "Message", wx.OK | wx.ICON_INFORMATION)

    def OnText_UniUni(self, evt):
        update = evt.GetString()
        if update != '':
            try:
                self.probUniUniValue = float(self.probUniUniText.GetValue())
            except:
                wx.MessageBox(
                    "Please enter a floating point number for the probability of UniUni.",
                    "Message", wx.OK | wx.ICON_INFORMATION)

    def OnText_BiUni(self, evt):
        update = evt.GetString()
        if update != '':
            #DefaultValues.probBiUniValue = float(self.probBiUniText.GetValue())
            try:
                self.probBiUniValue = float(self.probBiUniText.GetValue())
            except:
                wx.MessageBox(
                    "Please enter a floating point number for the probability of BiUni.",
                    "Message", wx.OK | wx.ICON_INFORMATION)

    def OnText_UniBi(self, evt):
        update = evt.GetString()
        if update != '':
            try:
                self.probUniBiValue = float(self.probUniBiText.GetValue())
            except:
                wx.MessageBox(
                    "Please enter a floating point number for the probability of UniBi.",
                    "Message", wx.OK | wx.ICON_INFORMATION)

    def OnText_BiBi(self, evt):
        update = evt.GetString()
        if update != '':
            try:
                self.probBiBiValue = float(self.probBiBiText.GetValue())
            except:
                wx.MessageBox(
                    "Please enter a floating point number for the probability of BiBi.",
                    "Message", wx.OK | wx.ICON_INFORMATION)

    def OnText_randomSeed(self, evt):
        update = evt.GetString()
        if update != '':
            try:
                self.randomSeedValue = float(self.randomSeedText.GetValue())
            except:
                wx.MessageBox(
                    "Please enter a valid random seed other than zero.",
                    "Message", wx.OK | wx.ICON_INFORMATION)

    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])
Exemplo n.º 7
0
class IMPORTSBML(WindowedPlugin):
    metadata = PluginMetadata(
        name='ImportSBML',
        author='Jin Xu',
        version='0.0.3',
        short_desc='Import SBML.',
        long_desc=
        'Import an SBML String from a file and visualize it as a network on canvas.',
        category=PluginCategory.ANALYSIS)

    def create_window(self, dialog):
        """
        Create a window to import SBML.
        Args:
            self
            dialog
        """
        self.window = wx.Panel(dialog, pos=(5, 100), size=(300, 320))
        self.sbmlStr = ''
        show_btn = wx.Button(self.window, -1, 'Show', (5, 5))
        show_btn.Bind(wx.EVT_BUTTON, self.Show)

        copy_btn = wx.Button(self.window, -1, 'Copy', (100, 5))
        copy_btn.Bind(wx.EVT_BUTTON, self.Copy)

        visualize_btn = wx.Button(self.window, -1, 'Visualize', (195, 5))
        visualize_btn.Bind(wx.EVT_BUTTON, self.Visualize)

        wx.StaticText(self.window, -1, 'SBML string:', (5, 30))
        self.SBMLText = wx.TextCtrl(self.window,
                                    -1,
                                    "", (10, 50),
                                    size=(260, 220),
                                    style=wx.TE_MULTILINE | wx.HSCROLL)
        self.SBMLText.SetInsertionPoint(0)

        return self.window

    def Show(self, evt):
        """
        Handler for the "Import" button.
        Open the SBML file and show it in the TextCtrl box.
        """
        self.dirname = ""  #set directory name to blank
        dlg = wx.FileDialog(
            self.window,
            "Choose a file to open",
            self.dirname,
            wildcard="SBML files (*.xml)|*.xml",
            style=wx.FD_OPEN
            | wx.FD_FILE_MUST_EXIST)  #open the dialog boxto open file
        if dlg.ShowModal() == wx.ID_OK:  #if positive button selected....
            self.filename = dlg.GetFilename()  #get the filename of the file
            self.dirname = dlg.GetDirectory(
            )  #get the directory of where file is located
            f = open(
                os.path.join(self.dirname, self.filename),
                'r')  #traverse the file directory and find filename in the OS
            self.sbmlStr = f.read()
            self.SBMLText.SetValue(
                f.read())  #open the file from location as read
            self.SBMLText.WriteText(self.sbmlStr)
            f.close
        dlg.Destroy()

    def Copy(self, evt):
        """
        Handler for the "Copy" button.
        Copy the SBML string to a clipboard.
        """
        self.dataObj = wx.TextDataObject()
        self.dataObj.SetText(self.SBMLText.GetValue())
        if wx.TheClipboard.Open():
            wx.TheClipboard.SetData(self.dataObj)
            wx.TheClipboard.Close()
        else:
            wx.MessageBox("Unable to open the clipboard", "Error")

    def Visualize(self, evt):
        """
        Handler for the "Visualize" button.
        Visualize the SBML string to a network shown on the canvas.
        """
        self.DisplayModel(self.sbmlStr, True, False)

    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)
Exemplo n.º 8
0
class CaptureSBML(WindowedPlugin):
      metadata = PluginMetadata(
        name='CaptureSBML',
        author='Claire Samuels',
        version='0.0.2',
        short_desc='Visualize and capture SBML or Antimony.',
        long_desc='Import a directory of SBML and Antimony files, visualize reactions, capture and save images.',
        category=PluginCategory.ANALYSIS
    )
      def create_window(self, dialog):
        """
        Create a window to export the SBML.
        Args:
            self
            dialog
        """
        # requires importSBML version 0.0.3
        v = IMPORTSBML.metadata.version.split(".")
        importSBMLvers = 0
        for i in range(3):
          importSBMLvers += pow(10,i)*int(v[len(v)-1-i])
        if importSBMLvers < 3:
          self.window = wx.Panel(dialog, pos=(5,100), size=(300, 320))
          txt = wx.StaticText(self.window, -1, "CaptureSBML requires ImportSBML version 0.0.3 or later!", (10,10))
          txt.Wrap(250)
          return self.window

        # import button
        self.window = wx.Panel(dialog, pos=(5,100), size=(300, 320))
        import_btn = wx.Button(self.window, -1, 'Import', (5, 5))
        import_btn.Bind(wx.EVT_BUTTON, self.Import)

        # Directory text:
        self.display_dir = wx.StaticText(self.window, -1, '', (85,10), (180,25),
                                         style= wx.ST_NO_AUTORESIZE | wx.ST_ELLIPSIZE_START)

        # files to import
        wx.StaticText(self.window, -1, 'Files to Display:', (5,30))
        self.selectedFiles = wx.TextCtrl(self.window, -1, "", (10,50), (240, 150),
                                         style=wx.TE_MULTILINE | wx.TE_READONLY)

        # directory to save images to
        output_dir_label = wx.StaticText(self.window, -1, "Output Directory:", (5,215))
        self.output_dir = wx.TextCtrl(self.window, -1, "", (100,210), (180,25))

        # go button
        go_btn = wx.Button(self.window, -1, 'Go', (200,250))
        go_btn.Bind(wx.EVT_BUTTON, self.Go)

        return self.window

      def Import(self, evt):
        '''
        Handler for "Import" button
        Choose a directory to iterate through'''
        self.dirname = ""
        dlg = wx.DirDialog(self.window, "Choose a directory", self.dirname,
                            wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
        self.file_list = []
        if dlg.ShowModal() == wx.ID_OK:
            self.dirname = dlg.GetPath()
            for file in os.listdir(self.dirname):
              # only want .xml files and .ant
              filename = os.fsdecode(file)
              if filename.endswith(".xml") | filename.endswith(".ant"):
                self.file_list.append(filename)
        self.display_dir.SetLabel(str(self.dirname))
        self.selectedFiles.SetLabel(str(self.file_list))

        self.output_dir.Clear()
        self.output_dir.write('{}\\reaction_visualizations'.format(self.dirname))
        dlg.Destroy()

      def Go(self, evt):
        '''
        Handler for "Go" button.
        Reads each file in selected directory. If readable SBML, displays on canvas'''
        reader = SBMLReader()

        self.output_dir_path = self.output_dir.Value
        if not os.path.isdir(self.output_dir_path):
          os.mkdir(self.output_dir_path)
        else:
          dir_cnt = 1
          while os.path.isdir('{} ({})'.format(self.output_dir_path, dir_cnt)):
            dir_cnt += 1
          self.output_dir_path = '{} ({})'.format(self.output_dir_path, dir_cnt)
          os.mkdir(self.output_dir_path)

        self.blank_canvas = []

        for filename in self.file_list:

          f = open(os.path.join(self.dirname, filename), 'r')
          sbmlStr = f.read()

          # convert .ant files to .xml
          if filename.endswith(".ant"):
            try:
              sbmlStr = tellurium.tellurium.antimonyToSBML(sbmlStr)
            except:
              pass

          doc = reader.readSBMLFromString(sbmlStr)
          if doc.getNumErrors() > 0:
            self.blank_canvas.append(filename)
          else:
            try:
              IMPORTSBML.DisplayModel(self, sbmlStr, False, True)
            except ValueError:
              pass
            self.Capture(filename)
        if len(self.blank_canvas) > 0:
          flist = ""
          for blkf in self.blank_canvas:
            flist += blkf + ", "
          flist = flist[:-2]
          wx.MessageBox("Done. Images saved to\n{}\nWarning: No node or reaction information found for {}.\nNo visualizations saved for these files.".format(self.output_dir_path, flist),
                         "Message", wx.OK | wx.ICON_INFORMATION)
        else:
          wx.MessageBox("Done. Images saved to\n{}".format(self.output_dir_path), "Message",
                         wx.OK | wx.ICON_INFORMATION)

      def Capture(self, filename):
        '''
        Saves a png of the current canvas to the chosen output directory
        Args:
          self
          filename: name of sbml file currently displayed'''

        # ensure that the canvas isn't blank
        if api.node_count(0) == 0 and api.reaction_count(0) == 0 and api.compartments_count(0) <= 1:
          self.blank_canvas.append(filename)
        else:
          pathname = os.path.join(self.output_dir_path, 'img_{}.png'.format(filename))

          canv = api.get_canvas()
          img = canv.DrawActiveRectToImage()

          img.SaveFile(pathname)
Exemplo n.º 9
0
class AlignCircle(WindowedPlugin):
    metadata = PluginMetadata(name='AlignCircle',
                              author='Evan Yip (2021)',
                              version='0.0.1',
                              short_desc='Align Circle',
                              long_desc='Aligns the nodes into a circle',
                              category=PluginCategory.UTILITIES)

    def __init__(self):
        """
        Initialize the AlignCircle

        Args:
            self
        """
        # allows the align circle class to inherit
        # the methods of the Windowed Plugin Class
        super().__init__()

    def create_window(self, dialog):
        """
        Create a window to do the structural analysis.
        Args:
            self
            dialog
        """
        # Making the window
        window = wx.Panel(dialog, pos=(5, 100), size=(300, 155))
        wx.StaticText(window, -1, 'Select nodes to arrange in circle',
                      (15, 10))

        # Use default radius
        wx.StaticText(window, -1, 'Use default radius:', (15, 30))
        self.defaultCheck = wx.CheckBox(window, -1, pos=(150, 30))
        self.defaultCheck.SetValue(True)

        # Making radius setable
        wx.StaticText(window, -1, 'Input desired radius:', (15, 55))
        self.radiusText = wx.TextCtrl(window,
                                      -1,
                                      '0', (150, 55),
                                      size=(120, 22))
        self.radiusText.SetInsertionPoint(0)
        self.radiusText.Bind(wx.EVT_TEXT, self.OnText_radius)  # binding test
        self.radiusValue = float(self.radiusText.GetValue())

        # Making the toggle button
        apply_btn = wx.ToggleButton(window,
                                    -1,
                                    'Apply', (100, 85),
                                    size=(80, 22))
        apply_btn.SetValue(False)
        # Binding the method to the button
        apply_btn.Bind(wx.EVT_TOGGLEBUTTON, self.Apply)
        return window

    def find_center(self, num_nodes, nodes):
        """
        Takes in the number of nodes and list of node indices and
        computes the optimal centerpoint for the circle
        Parameters: num_nodes(int) - number of nodes,
            node_indices(list) - list of nodes indices
        Returns: center(tuple)
        """
        # Max dimension of the node size
        max_dim = 0  # will consider this the diameter of a circle node
        for i in nodes:
            # Get node
            node = api.get_node_by_index(0, i)
            for dim in node.size:
                if dim > max_dim:
                    max_dim = dim

        # Approximate circumference estimate
        spacing = max_dim / 4
        circum_estimate = num_nodes * (max_dim + spacing)

        # Computing radius
        r = circum_estimate / (2 * np.pi) + max_dim

        center = (r, r)
        return center

    def cart(self, r, theta):
        """
        Converts from polar coordinates to cartesian coordinates
        Parameters: r(double), theta(double in radians)
        Returns: (x,y) cartesian coordinate tuple
        """
        x = r * math.cos(theta)
        y = r * math.sin(theta)
        return x, y

    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)

    def OnText_radius(self, event):
        """
        Catches exception if self.radiusText can not be converted
        to a floating point number. Opens a window.
        """
        update = event.GetString()
        if update != '':
            try:
                self.radiusValue = float(self.radiusText.GetValue())
            except:
                wx.MessageBox(
                    "Please enter a floating point number"
                    "for the desired radius", "Message",
                    wx.OK | wx.ICON_INFORMATION)

    def CheckSelection(self, nodes):
        """
        Verifies that there are selected nodes. Raises window if
        no nodes are selected, but apply button is pressed
        """
        if nodes == 0:
            wx.MessageBox("Please select desired nodes to arrange"
                          "in circle", "Message", wx.OK | wx.ICON_INFORMATION)
            return True

    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)
Exemplo n.º 10
0
class ExportSBML(WindowedPlugin):
    metadata = PluginMetadata(
        name='ExportSBML',
        author='Jin Xu',
        version='0.0.2',
        short_desc='Export SBML.',
        long_desc=
        'Export the SBML String from the network on canvas and save it to a file.',
        category=PluginCategory.ANALYSIS)

    def create_window(self, dialog):
        """
        Create a window to export the SBML.
        Args:
            self
            dialog
        """
        self.window = wx.Panel(dialog, pos=(5, 100), size=(300, 320))

        show_btn = wx.Button(self.window, -1, 'Show', (5, 5))
        show_btn.Bind(wx.EVT_BUTTON, self.Show)

        copy_btn = wx.Button(self.window, -1, 'Copy', (100, 5))
        copy_btn.Bind(wx.EVT_BUTTON, self.Copy)

        save_btn = wx.Button(self.window, -1, 'Save', (195, 5))
        save_btn.Bind(wx.EVT_BUTTON, self.Save)

        wx.StaticText(self.window, -1, 'SBML string:', (5, 30))
        self.SBMLText = wx.TextCtrl(self.window,
                                    -1,
                                    "", (10, 50),
                                    size=(260, 220),
                                    style=wx.TE_MULTILINE | wx.HSCROLL)
        self.SBMLText.SetInsertionPoint(0)

        return self.window

    def Copy(self, evt):
        """
        Handler for the "Copy" button.
        Copy the SBML string to a clipboard.
        """
        self.dataObj = wx.TextDataObject()
        self.dataObj.SetText(self.SBMLText.GetValue())
        if wx.TheClipboard.Open():
            wx.TheClipboard.SetData(self.dataObj)
            wx.TheClipboard.Close()
        else:
            wx.MessageBox("Unable to open the clipboard", "Error")

    def Show(self, evt):
        """
        Handler for the "Export" button.
        Get the network on canvas and change it to an SBML string.
        """

        isReversible = True
        netIn = 0
        numNodes = api.node_count(netIn)
        numReactions = api.reaction_count(netIn)

        if numNodes == 0 or numReactions == 0:
            wx.MessageBox(
                "Please import a network with at least one reaction on canvas",
                "Message", wx.OK | wx.ICON_INFORMATION)
        else:
            allNodes = api.get_nodes(netIn)
            allReactions = api.get_reactions(netIn)
            allcompartments = api.get_compartments(netIn)
            numCompartments = len(allcompartments)
            #######################################

            # Creates an SBMLNamespaces object with the given SBML level, version
            # package name, package version.
            #
            # (NOTE) By default, the name of package (i.e. "layout") will be used
            # if the argument for the prefix is missing or empty. Thus the argument
            # for the prefix can be added as follows:
            #
            #    SBMLNamespaces sbmlns(3,1,"layout",1,"LAYOUT")
            #
            sbmlns = SBMLNamespaces(3, 1, "layout", 1)
            # create the document
            document = SBMLDocument(sbmlns)
            # set the "required" attribute of layout package  to "true"
            document.setPkgRequired("layout", False)

            # create the Model
            model = document.createModel()
            model.setId("Model_layout")
            document.setModel(model)

            # create the Compartment and species

            comp_id_list = []
            for i in range(numCompartments):
                comp_id_list.append(allcompartments[i].id)

            if numCompartments != 0:
                if "_compartment_default_" not in comp_id_list:
                    compartment = model.createCompartment()
                    comp_id = "_compartment_default_"
                    compartment.setId(comp_id)
                    compartment.setConstant(True)

                for i in range(numCompartments):
                    compartment = model.createCompartment()
                    comp_id = allcompartments[i].id
                    compartment.setId(comp_id)
                    compartment.setConstant(True)
                for i in range(numNodes):
                    original_index = allNodes[i].original_index
                    if original_index == -1:
                        spec_id = allNodes[i].id
                        species = model.createSpecies()
                        species.setId(spec_id)
                        comp_idx = allNodes[i].comp_idx
                        if comp_idx != -1:
                            comp_id = allcompartments[comp_idx].id
                            species.setCompartment(comp_id)
                        else:
                            species.setCompartment("_compartment_default_")
                        species.setInitialConcentration(1.0)
                        species.setHasOnlySubstanceUnits(False)
                        species.setBoundaryCondition(False)
                        species.setConstant(False)
                        if allNodes[i].floating_node == False:
                            species.setBoundaryCondition(True)
                            species.setConstant(True)
            else:  #set default compartment
                compartment = model.createCompartment()
                comp_id = "_compartment_default_"
                compartment.setId(comp_id)
                compartment.setConstant(True)
                for i in range(numNodes):
                    original_index = allNodes[i].original_index
                    if original_index == -1:
                        spec_id = allNodes[i].id
                        species = model.createSpecies()
                        species.setId(spec_id)
                        species.setCompartment(comp_id)
                        species.setInitialConcentration(1.0)
                        species.setHasOnlySubstanceUnits(False)
                        species.setBoundaryCondition(False)
                        species.setConstant(False)
                        if allNodes[i].floating_node == False:
                            species.setBoundaryCondition(True)
                            species.setConstant(True)
            # create reactions:
            for i in range(numReactions):
                reaction_id = allReactions[i].id
                rct = []  # id list of the rcts
                prd = []
                rct_num = len(allReactions[i].sources)
                prd_num = len(allReactions[i].targets)
                for j in range(rct_num):
                    rct.append(
                        get_node_by_index(netIn,
                                          allReactions[i].sources[j]).id)
                for j in range(prd_num):
                    prd.append(
                        get_node_by_index(netIn,
                                          allReactions[i].targets[j]).id)

                kinetic_law = ''
                parameter_list = []
                kinetic_law = kinetic_law + 'E' + str(i) + '*(k' + str(i)
                parameter_list.append('E' + str(i))
                parameter_list.append('k' + str(i))
                for j in range(rct_num):
                    kinetic_law = kinetic_law + '*' + rct[j]

                reaction = model.createReaction()
                reaction.setId(allReactions[i].id)
                reaction.setReversible(False)
                reaction.setFast(False)
                if isReversible:
                    reaction.setReversible(True)
                    kinetic_law = kinetic_law + ' - k' + str(i) + 'r'
                    parameter_list.append('k' + str(i) + 'r')
                    for j in range(prd_num):
                        kinetic_law = kinetic_law + '*' + prd[j]
                kinetic_law = kinetic_law + ')'
                for j in range(len(parameter_list)):
                    parameters = model.createParameter()
                    parameters.setId(parameter_list[j])
                    parameters.setValue(0.1)
                    parameters.setConstant(True)
                kinetics = reaction.createKineticLaw()
                kinetics.setFormula(kinetic_law)

                for j in range(rct_num):
                    reference = reaction.createReactant()
                    reference.setSpecies(rct[j])
                    ref_id = "SpecRef_" + reaction_id + "_rct" + str(j)
                    reference.setId(ref_id)
                    reference.setStoichiometry(1.)
                    reference.setConstant(False)

                for j in range(prd_num):
                    reference = reaction.createProduct()
                    reference.setSpecies(prd[j])
                    ref_id = "SpecRef_" + reaction_id + "_prd" + str(j)
                    reference.setId(ref_id)
                    reference.setStoichiometry(1.)
                    reference.setConstant(False)

            # create the Layout

            #
            # set the LayoutPkgNamespaces for Level 3 Version1 Layout Version 1
            #
            layoutns = LayoutPkgNamespaces(3, 1, 1)

            renderns = RenderPkgNamespaces(3, 1, 1)

            #
            # Get a LayoutModelPlugin object plugged in the model object.
            #
            # The type of the returned value of SBase::getPlugin() function is SBasePlugin, and
            # thus the value needs to be casted for the corresponding derived class.
            #

            mplugin = model.getPlugin("layout")

            # rPlugin = model.getPlugin("render")
            # if rPlugin is None:
            #   print("there is no render outside layout.")

            # lolPlugin = mplugin.getListOfLayouts().getPlugin("render")
            # if lolPlugin is None:
            #   print("there is no render info inside layout.")

            if mplugin is None:
                # print(
                #     "[Fatal Error] Layout Extension Level " + layoutns.getLevel() + " Version " + layoutns.getVersion() + " package version " + layoutns.getPackageVersion() + " is not registered.")
                # sys.exit(1)
                wx.MessageBox("There is no layout information.", "Message",
                              wx.OK | wx.ICON_INFORMATION)

            #
            # Creates a Layout object via LayoutModelPlugin object.
            #
            layout = mplugin.createLayout()
            layout.setId("Layout_1")
            layout.setDimensions(Dimensions(layoutns, 800.0, 800.0))
            # random network (40+800x, 40+800y)

            #create the CompartmentGlyph and SpeciesGlyphs
            if numCompartments != 0:
                # if "_compartment_default_" not in comp_id_list:
                #     comp_id= "_compartment_default_"
                #     compartmentGlyph = layout.createCompartmentGlyph()
                #     compG_id = "CompG_" + comp_id
                #     compartmentGlyph.setId(compG_id)
                #     compartmentGlyph.setCompartmentId(comp_id)
                #     bb_id  = "bb_" + comp_id
                #     pos_x  = 10
                #     pos_y  = 10
                #     width  = 3900
                #     height = 2400
                #     compartmentGlyph.setBoundingBox(BoundingBox(layoutns, bb_id, pos_x, pos_y, width, height))

                for i in range(numCompartments):
                    comp_id = allcompartments[i].id
                    if comp_id != "_compartment_default_":
                        compartmentGlyph = layout.createCompartmentGlyph()
                        compG_id = "CompG_" + comp_id
                        compartmentGlyph.setId(compG_id)
                        compartmentGlyph.setCompartmentId(comp_id)
                        bb_id = "bb_" + comp_id
                        pos_x = allcompartments[i].position.x
                        pos_y = allcompartments[i].position.y
                        width = allcompartments[i].size.x
                        height = allcompartments[i].size.y
                        compartmentGlyph.setBoundingBox(
                            BoundingBox(layoutns, bb_id, pos_x, pos_y, width,
                                        height))
                for i in range(numNodes):
                    spec_id = allNodes[i].id
                    spec_index = allNodes[i].index
                    spec_shapeIdx = allNodes[i].shape_index
                    speciesGlyph = layout.createSpeciesGlyph()
                    specG_id = "SpecG_" + spec_id + '_idx_' + str(spec_index)
                    speciesGlyph.setId(specG_id)
                    speciesGlyph.setSpeciesId(spec_id)
                    bb_id = "bb_" + spec_id + '_idx_' + str(spec_index)
                    pos_x = allNodes[i].position.x
                    pos_y = allNodes[i].position.y
                    width = allNodes[i].size.x
                    height = allNodes[i].size.y
                    speciesGlyph.setBoundingBox(
                        BoundingBox(layoutns, bb_id, pos_x, pos_y, width,
                                    height))

                    textGlyph = layout.createTextGlyph()
                    textG_id = "TextG_" + spec_id + '_idx_' + str(spec_index)
                    textGlyph.setId(textG_id)
                    bb_id = "bb_spec_text_" + spec_id + '_idx_' + str(
                        spec_index)
                    if spec_shapeIdx == 6:  #rough by eyes
                        pos_x_text = pos_x + 50
                        pos_y_text = pos_y + 30
                    else:
                        pos_x_text = pos_x
                        pos_y_text = pos_y
                    textGlyph.setBoundingBox(
                        BoundingBox(layoutns, bb_id, pos_x_text, pos_y_text,
                                    width, height))
                    textGlyph.setOriginOfTextId(specG_id)
                    textGlyph.setGraphicalObjectId(specG_id)
            else:  #there is no compartment
                comp_id = "_compartment_default_"
                compartmentGlyph = layout.createCompartmentGlyph()
                compG_id = "CompG_" + comp_id
                compartmentGlyph.setId(compG_id)
                compartmentGlyph.setCompartmentId(comp_id)
                bb_id = "bb_" + comp_id
                pos_x = 10
                pos_y = 10
                width = 3900
                height = 2400
                compartmentGlyph.setBoundingBox(
                    BoundingBox(layoutns, bb_id, pos_x, pos_y, width, height))

                for i in range(numNodes):
                    spec_id = allNodes[i].id
                    spec_index = allNodes[i].index
                    spec_shapeIdx = allNodes[i].shape_index
                    speciesGlyph = layout.createSpeciesGlyph()
                    specG_id = "SpecG_" + spec_id + '_idx_' + str(spec_index)
                    speciesGlyph.setId(specG_id)
                    speciesGlyph.setSpeciesId(spec_id)
                    bb_id = "bb_" + spec_id + '_idx_' + str(spec_index)
                    pos_x = allNodes[i].position.x
                    pos_y = allNodes[i].position.y
                    width = allNodes[i].size.x
                    height = allNodes[i].size.y
                    speciesGlyph.setBoundingBox(
                        BoundingBox(layoutns, bb_id, pos_x, pos_y, width,
                                    height))

                    textGlyph = layout.createTextGlyph()
                    textG_id = "TextG_" + spec_id + '_idx_' + str(spec_index)
                    textGlyph.setId(textG_id)
                    if spec_shapeIdx == 6:  #rough by eyes
                        pos_x_text = pos_x + 50
                        pos_y_text = pos_y + 30
                    else:
                        pos_x_text = pos_x
                        pos_y_text = pos_y
                    bb_id = "bb_spec_text_" + spec_id + '_idx_' + str(
                        spec_index)
                    textGlyph.setBoundingBox(
                        BoundingBox(layoutns, bb_id, pos_x_text, pos_y_text,
                                    width, height))
                    textGlyph.setOriginOfTextId(specG_id)
                    textGlyph.setGraphicalObjectId(specG_id)

            # create the ReactionGlyphs and SpeciesReferenceGlyphs
            for i in range(numReactions):
                reaction_id = allReactions[i].id
                reactionGlyph = layout.createReactionGlyph()
                reactionG_id = "RectionG_" + reaction_id
                reactionGlyph.setId(reactionG_id)
                reactionGlyph.setReactionId(reaction_id)

                reactionCurve = reactionGlyph.getCurve()
                ls = reactionCurve.createLineSegment()
                centroid = api.compute_centroid(0, allReactions[i].sources,
                                                allReactions[i].targets)
                ls.setStart(Point(layoutns, centroid.x, centroid.y))
                ls.setEnd(Point(layoutns, centroid.x, centroid.y))

                rct = []  # id list of the rcts
                prd = []
                rct_index = []
                prd_index = []
                rct_num = len(allReactions[i].sources)
                prd_num = len(allReactions[i].targets)

                for j in range(rct_num):
                    rct.append(
                        get_node_by_index(netIn,
                                          allReactions[i].sources[j]).id)
                    rct_index.append(
                        get_node_by_index(netIn,
                                          allReactions[i].sources[j]).index)
                for j in range(prd_num):
                    prd.append(
                        get_node_by_index(netIn,
                                          allReactions[i].targets[j]).id)
                    prd_index.append(
                        get_node_by_index(netIn,
                                          allReactions[i].targets[j]).index)
                for j in range(rct_num):
                    ref_id = "SpecRef_" + reaction_id + "_rct" + str(j)

                    speciesReferenceGlyph = reactionGlyph.createSpeciesReferenceGlyph(
                    )
                    specsRefG_id = "SpecRefG_" + reaction_id + "_rct" + str(j)
                    specG_id = "SpecG_" + rct[j] + '_idx_' + str(rct_index[j])
                    speciesReferenceGlyph.setId(specsRefG_id)
                    speciesReferenceGlyph.setSpeciesGlyphId(specG_id)
                    speciesReferenceGlyph.setSpeciesReferenceId(ref_id)
                    speciesReferenceGlyph.setRole(SPECIES_ROLE_SUBSTRATE)

                    speciesReferenceCurve = speciesReferenceGlyph.getCurve()
                    cb = speciesReferenceCurve.createCubicBezier()
                    #cb = speciesReferenceCurve.createLineSegment()

                    cb.setStart(Point(layoutns, centroid.x, centroid.y))

                    handles = api.default_handle_positions(
                        netIn, allReactions[i].index)
                    pos_x = handles[1 + j].x
                    pos_y = handles[1 + j].y
                    cb.setBasePoint1(Point(layoutns, pos_x, pos_y))
                    cb.setBasePoint2(Point(layoutns, pos_x, pos_y))

                    pos_x = get_node_by_index(
                        netIn, allReactions[i].sources[j]).position.x
                    pos_y = get_node_by_index(
                        netIn, allReactions[i].sources[j]).position.y
                    width = get_node_by_index(
                        netIn, allReactions[i].sources[j]).size.x
                    height = get_node_by_index(
                        netIn, allReactions[i].sources[j]).size.y
                    cb.setEnd(
                        Point(layoutns, pos_x + 0.5 * width,
                              pos_y - 0.5 * height))

                for j in range(prd_num):
                    ref_id = "SpecRef_" + reaction_id + "_prd" + str(j)
                    speciesReferenceGlyph = reactionGlyph.createSpeciesReferenceGlyph(
                    )
                    specsRefG_id = "SpecRefG_" + reaction_id + "_prd" + str(j)
                    specG_id = "SpecG_" + prd[j] + '_idx_' + str(prd_index[j])
                    speciesReferenceGlyph.setId(specsRefG_id)
                    speciesReferenceGlyph.setSpeciesGlyphId(specG_id)
                    speciesReferenceGlyph.setSpeciesReferenceId(ref_id)
                    speciesReferenceGlyph.setRole(SPECIES_ROLE_PRODUCT)

                    speciesReferenceCurve = speciesReferenceGlyph.getCurve()
                    cb = speciesReferenceCurve.createCubicBezier()
                    #cb = speciesReferenceCurve.createLineSegment()
                    cb.setStart(Point(layoutns, centroid.x, centroid.y))

                    handles = api.default_handle_positions(
                        netIn, allReactions[i].index)
                    pos_x = handles[1 + j].x
                    pos_y = handles[1 + j].y
                    cb.setBasePoint1(Point(layoutns, pos_x, pos_y))
                    cb.setBasePoint2(Point(layoutns, pos_x, pos_y))

                    pos_x = get_node_by_index(
                        netIn, allReactions[i].targets[j]).position.x
                    pos_y = get_node_by_index(
                        netIn, allReactions[i].targets[j]).position.y
                    width = get_node_by_index(
                        netIn, allReactions[i].targets[j]).size.x
                    height = get_node_by_index(
                        netIn, allReactions[i].targets[j]).size.y
                    cb.setEnd(
                        Point(layoutns, pos_x + 0.5 * width,
                              pos_y - 0.5 * height))

            sbmlStr_layout = writeSBMLToString(
                document)  #sbmlStr is w/o layout info
            #self.SBMLText.SetValue(sbmlStr_layout)

            doc = readSBMLFromString(sbmlStr_layout)
            model_layout = doc.getModel()
            mplugin = model_layout.getPlugin("layout")

            # add render information to the first layout
            layout = mplugin.getLayout(0)

            rPlugin = layout.getPlugin("render")

            uri = RenderExtension.getXmlnsL2() if doc.getLevel(
            ) == 2 else RenderExtension.getXmlnsL3V1V1()

            # enable render package
            doc.enablePackage(uri, "render", True)
            doc.setPackageRequired("render", False)

            rPlugin = layout.getPlugin("render")

            rInfo = rPlugin.createLocalRenderInformation()
            rInfo.setId("info")
            rInfo.setName("Render Information")
            rInfo.setProgramName("RenderInformation")
            rInfo.setProgramVersion("1.0")

            # add some colors
            color = rInfo.createColorDefinition()
            color.setId("black")
            color.setColorValue("#000000")

            if numCompartments != 0:
                for i in range(len(allcompartments)):
                    temp_id = allcompartments[i].id
                    if temp_id != '_compartment_default':
                        fill_color = allcompartments[i].fill_color
                        border_color = allcompartments[i].border_color
                        comp_border_width = allcompartments[i].border_width
                        fill_color_str = '#%02x%02x%02x' % (
                            fill_color.r, fill_color.g, fill_color.b)
                        border_color_str = '#%02x%02x%02x' % (
                            border_color.r, border_color.g, border_color.b)

                        # color = rInfo.createColorDefinition()
                        # color.setId("comp_fill_color" + str(i))
                        # color.setColorValue(fill_color_str)

                        # color = rInfo.createColorDefinition()
                        # color.setId("comp_border_color" + str(i))
                        # color.setColorValue(border_color_str)

                        # # add a list of styles
                        # style = rInfo.createStyle("compStyle" + str(i))
                        # style.getGroup().setFillColor("comp_fill_color" + str(i))
                        # style.getGroup().setStroke("comp_border_color" + str (i))
                        # style.getGroup().setStrokeWidth(comp_border_width)
                        # style.addType("COMPARTMENTGLYPH")
                        # rectangle = style.getGroup().createRectangle()
                        # rectangle.setCoordinatesAndSize(RelAbsVector(0,0),RelAbsVector(0,0),RelAbsVector(0,0),RelAbsVector(0,100),RelAbsVector(0,100))

                color = rInfo.createColorDefinition()
                color.setId("comp_fill_color")
                color.setColorValue(fill_color_str)

                color = rInfo.createColorDefinition()
                color.setId("comp_border_color")
                color.setColorValue(border_color_str)

                # add a list of styles
                style = rInfo.createStyle("compStyle")
                style.getGroup().setFillColor("comp_fill_color")
                style.getGroup().setStroke("comp_border_color")
                style.getGroup().setStrokeWidth(comp_border_width)
                style.addType("COMPARTMENTGLYPH")
                rectangle = style.getGroup().createRectangle()
                rectangle.setCoordinatesAndSize(RelAbsVector(0, 0),
                                                RelAbsVector(0, 0),
                                                RelAbsVector(0, 0),
                                                RelAbsVector(0, 100),
                                                RelAbsVector(0, 100))

            else:
                comp_border_width = 2.
                #fill_color_str    = '#9ea9ff'
                #border_color_str  = '#001dff'
                #set default compartment with white color
                fill_color_str = '#ffffff'
                border_color_str = '#ffffff'

                color = rInfo.createColorDefinition()
                color.setId("comp_fill_color")
                color.setColorValue(fill_color_str)

                color = rInfo.createColorDefinition()
                color.setId("comp_border_color")
                color.setColorValue(border_color_str)

                # add a list of styles
                style = rInfo.createStyle("compStyle")
                style.getGroup().setFillColor("comp_fill_color")
                style.getGroup().setStroke("comp_border_color")
                style.getGroup().setStrokeWidth(comp_border_width)
                style.addType("COMPARTMENTGLYPH")
                rectangle = style.getGroup().createRectangle()
                rectangle.setCoordinatesAndSize(RelAbsVector(0, 0),
                                                RelAbsVector(0, 0),
                                                RelAbsVector(0, 0),
                                                RelAbsVector(0, 100),
                                                RelAbsVector(0, 100))

            for i in range(len(allNodes)):
                node = allNodes[i]
                #print(node.shape)
                try:
                    primitive, transform = node.shape.items[0]
                    spec_fill_color = primitive.fill_color
                    spec_border_color = primitive.border_color
                    spec_fill_color_str = '#%02x%02x%02x' % (spec_fill_color.r,
                                                             spec_fill_color.g,
                                                             spec_fill_color.b)
                    spec_border_color_str = '#%02x%02x%02x' % (
                        spec_border_color.r, spec_border_color.g,
                        spec_border_color.b)
                    spec_border_width = primitive.border_width
                except:  #text-only
                    #spec_fill_color_str = '#ffcc99'
                    #spec_border_color_str = '#ff6c09'
                    #set default species/node with white color
                    spec_fill_color_str = '#ffffff'
                    spec_border_color_str = '#ffffff'
                    #transparent color does not work
                    #spec_fill_color_str = '#000000'
                    #spec_border_color_str = '#000000'
                    spec_border_width = 2.

                color = rInfo.createColorDefinition()
                color.setId("spec_fill_color" + str(i))
                color.setColorValue(spec_fill_color_str)

                color = rInfo.createColorDefinition()
                color.setId("spec_border_color" + str(i))
                color.setColorValue(spec_border_color_str)

                style = rInfo.createStyle("specStyle" + str(i))
                style.getGroup().setFillColor("spec_fill_color" + str(i))
                style.getGroup().setStroke("spec_border_color" + str(i))
                style.getGroup().setStrokeWidth(spec_border_width)
                style.addType("SPECIESGLYPH")
                if node.shape_index == 1 or node.shape_index == 6:  #ellipse/text-outside
                    ellipse = style.getGroup().createEllipse()
                    ellipse.setCenter2D(RelAbsVector(0, 50),
                                        RelAbsVector(0, 50))
                    ellipse.setRadii(RelAbsVector(0, 50), RelAbsVector(0, 50))

                elif node.shape_index == 2:  #hexagon(6)
                    polygon = style.getGroup().createPolygon()
                    renderPoint1 = polygon.createPoint()
                    renderPoint1.setCoordinates(RelAbsVector(0, 100),
                                                RelAbsVector(0, 50))
                    renderPoint2 = polygon.createPoint()
                    renderPoint2.setCoordinates(RelAbsVector(0, 75),
                                                RelAbsVector(0, 7))
                    renderPoint3 = polygon.createPoint()
                    renderPoint3.setCoordinates(RelAbsVector(0, 25),
                                                RelAbsVector(0, 7))
                    renderPoint4 = polygon.createPoint()
                    renderPoint4.setCoordinates(RelAbsVector(0, 0),
                                                RelAbsVector(0, 50))
                    renderPoint5 = polygon.createPoint()
                    renderPoint5.setCoordinates(RelAbsVector(0, 25),
                                                RelAbsVector(0, 86))
                    renderPoint6 = polygon.createPoint()
                    renderPoint6.setCoordinates(RelAbsVector(0, 75),
                                                RelAbsVector(0, 86))
                elif node.shape_index == 3:  #line(2)
                    polygon = style.getGroup().createPolygon()
                    renderPoint1 = polygon.createPoint()
                    renderPoint1.setCoordinates(RelAbsVector(0, 0),
                                                RelAbsVector(0, 50))
                    renderPoint2 = polygon.createPoint()
                    renderPoint2.setCoordinates(RelAbsVector(0, 100),
                                                RelAbsVector(0, 50))
                elif node.shape_index == 4:  #triangle(3)
                    polygon = style.getGroup().createPolygon()
                    renderPoint1 = polygon.createPoint()
                    renderPoint1.setCoordinates(RelAbsVector(0, 100),
                                                RelAbsVector(0, 50))
                    renderPoint2 = polygon.createPoint()
                    renderPoint2.setCoordinates(RelAbsVector(0, 25),
                                                RelAbsVector(0, 7))
                    renderPoint3 = polygon.createPoint()
                    renderPoint3.setCoordinates(RelAbsVector(0, 25),
                                                RelAbsVector(0, 86))
                else:  #rectangle shape_index = 0/text-only 5/demo-combo 7/others as default (rectangle)
                    rectangle = style.getGroup().createRectangle()
                    rectangle.setCoordinatesAndSize(RelAbsVector(0, 0),
                                                    RelAbsVector(0, 0),
                                                    RelAbsVector(0, 0),
                                                    RelAbsVector(0, 100),
                                                    RelAbsVector(0, 100))

                style = rInfo.createStyle("textStyle")
                style.getGroup().setStroke("black")
                style.getGroup().setStrokeWidth(1.)
                style.addType("TEXTGLYPH")

            if numReactions != 0:
                for i in range(len(allReactions)):
                    reaction_fill_color = allReactions[i].fill_color
                    reaction_fill_color_str = '#%02x%02x%02x' % (
                        reaction_fill_color.r, reaction_fill_color.g,
                        reaction_fill_color.b)
                    reaction_line_thickness = allReactions[i].line_thickness

                    color = rInfo.createColorDefinition()
                    color.setId("reaction_fill_color" + str(i))
                    color.setColorValue(reaction_fill_color_str)

                    style = rInfo.createStyle("reactionStyle" + str(i))
                    style.getGroup().setStroke("reaction_fill_color" + str(i))
                    style.getGroup().setStrokeWidth(reaction_line_thickness)
                    style.addType("REACTIONGLYPH SPECIESREFERENCEGLYPH")

            sbmlStr_layout_render = writeSBMLToString(doc)
            self.SBMLText.SetValue(sbmlStr_layout_render)

    def Save(self, evt):
        """
        Handler for the "Save" button.
        Save the SBML string to a file.
        """
        self.dirname = ""  #set directory name to blank
        dlg = wx.FileDialog(self.window,
                            "Save As",
                            self.dirname,
                            wildcard="SBML files (*.xml)|*.xml",
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        if dlg.ShowModal() == wx.ID_OK:
            # Grab the content to be saved
            itcontains = self.SBMLText.GetValue()
            # Open the file for write, write, close
            self.filename = dlg.GetFilename()
            self.dirname = dlg.GetDirectory()
            filehandle = open(os.path.join(self.dirname, self.filename), 'w')
            filehandle.write(itcontains)
            filehandle.close()
        # Get rid of the dialog to keep things tidy
        dlg.Destroy()
Exemplo n.º 11
0
class ExportAntimony(WindowedPlugin):
    metadata = PluginMetadata(
        name='ExportAntimony',
        author='Jin Xu',
        version='0.0.2',
        short_desc='Export Antimony.',
        long_desc='Export the Antimony String from the network on canvas.',
        category=PluginCategory.ANALYSIS)

    def create_window(self, dialog):
        """
        Create a window to do the antimony export.
        Args:
            self
            dialog
        """
        self.window = wx.Panel(dialog, pos=(5, 100), size=(300, 320))

        show_btn = wx.Button(self.window, -1, 'Show', (5, 5))
        show_btn.Bind(wx.EVT_BUTTON, self.Show)

        copy_btn = wx.Button(self.window, -1, 'Copy', (100, 5))
        copy_btn.Bind(wx.EVT_BUTTON, self.Copy)

        save_btn = wx.Button(self.window, -1, 'Save', (195, 5))
        save_btn.Bind(wx.EVT_BUTTON, self.Save)

        wx.StaticText(self.window, -1, 'Antimony string:', (5, 30))
        self.antimonyText = wx.TextCtrl(self.window,
                                        -1,
                                        "", (10, 50),
                                        size=(260, 220),
                                        style=wx.TE_MULTILINE | wx.HSCROLL)
        self.antimonyText.SetInsertionPoint(0)

        return self.window

    def Show(self, evt):
        """
        Handler for the "Export" button.
        Get the network on canvas and change it to an Antimony string.
        """
        isReversible = True
        netIn = 0
        numNodes = api.node_count(netIn)

        if numNodes == 0:
            wx.MessageBox("Please import a network on canvas", "Message",
                          wx.OK | wx.ICON_INFORMATION)
        else:
            allNodes = api.get_nodes(netIn)
            numReactions = api.reaction_count(netIn)
            antStr = ''
            allReactions = api.get_reactions(netIn)
            for i in range(numReactions):
                antStr = antStr + 'J' + str(i) + ': '
                rct_num = len(allReactions[i].sources)
                prd_num = len(allReactions[i].targets)
                for j in range(rct_num - 1):
                    antStr = antStr + allNodes[allReactions[i].sources[j]].id
                    antStr = antStr + ' + '
                antStr = antStr + allNodes[allReactions[i].sources[rct_num -
                                                                   1]].id
                antStr = antStr + ' -> '
                for j in range(prd_num - 1):
                    antStr = antStr + allNodes[allReactions[i].targets[j]].id
                    antStr = antStr + ' + '
                antStr = antStr + allNodes[allReactions[i].targets[prd_num -
                                                                   1]].id
                antStr = antStr + '; E' + str(i) + '*(k' + str(i)
                for j in range(rct_num):
                    antStr = antStr + '*' + allNodes[
                        allReactions[i].sources[j]].id
                if isReversible:
                    antStr = antStr + ' - k' + str(i) + 'r'
                    for j in range(prd_num):
                        antStr = antStr + '*' + allNodes[
                            allReactions[i].targets[j]].id
                antStr = antStr + ')'
                antStr = antStr + ';\n'
            self.antimonyText.SetValue(antStr)

    def Copy(self, evt):
        """
        Handler for the "Copy" button.
        Copy the Antimony string to a clipboard.
        """
        self.dataObj = wx.TextDataObject()
        self.dataObj.SetText(self.antimonyText.GetValue())
        if wx.TheClipboard.Open():
            wx.TheClipboard.SetData(self.dataObj)
            wx.TheClipboard.Close()
        else:
            wx.MessageBox("Unable to open the clipboard", "Error")

    def Save(self, evt):
        """
        Handler for the "Save" button.
        Save the Antimony string to a file.
        """

        self.dirname = ""  #set directory name to blank

        dlg = wx.FileDialog(self.window,
                            "Save As",
                            self.dirname,
                            wildcard="Antimony files (*.ant)|*.ant",
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        if dlg.ShowModal() == wx.ID_OK:
            # Grab the content to be saved
            itcontains = self.antimonyText.GetValue()
            # Open the file for write, write, close
            self.filename = dlg.GetFilename()
            self.dirname = dlg.GetDirectory()
            filehandle = open(os.path.join(self.dirname, self.filename), 'w')
            filehandle.write(itcontains)
            filehandle.close()
        # Get rid of the dialog to keep things tidy
        dlg.Destroy()