def createReaction(): #reactant = createNode("reactant", 0, 0) #product = createNode("product", 1, 0) reactant = iodine.TNode(0, "reactant", Vec2(0.3, 0.4), Vec2(3, 4), floating=True, nodeLocked=False) product = iodine.TNode(1, "product", Vec2(0.6, 0.8), Vec2(6, 8), floating=True, nodeLocked=False) rxn = iodine.TReaction( "rxn1", reactants={0: iodine.TSpeciesNode(1, reactant.position)}, products={1: iodine.TSpeciesNode(1, product.position)}) network = iodine.TNetwork("0", { 0: reactant, 1: product }, reactions={0: rxn}) network.addReaction(rxn)
def test_update_nodes(self): with run_app(): node = Node('Charles', pos=Vec2(50, 50), size=Vec2(40, 12), fill_color=wx.RED, border_color=wx.GREEN, border_width=4) api.add_node(self.neti, node) api.update_node(self.neti, 0, 'James') nodes = api.all_nodes() self.assertEqual(len(nodes), 1) self.assertTrue(nodes[0].id_, 'James')
def test_add_nodes(self): with run_app(): node = Node('Charles', pos=Vec2(50, 50), size=Vec2(40, 12), fill_color=wx.RED, border_color=wx.GREEN, border_width=4) api.add_node(self.neti, node) nodes = api.all_nodes() self.assertEqual(len(nodes), 1) self.assertEqual(0, nodes[0].index) self.assertTrue(node.props_equal(nodes[0]))
def OnLeftUp(self, evt: wx.MouseEvent): """ Handler for mouse left button up event. """ if self.dragging: assert self.dragged_point is not None drop = self.projected_landing(self.dragged_point) assert self.hover_idx != -1 self.dragging = False self.arrow_tip.points[self.hover_idx] = Vec2( drop.x // self.csize, drop.y // self.csize) self.update_hover_idx(Vec2(evt.GetPosition())) self.Refresh()
def __init__(self, parent, arrow_tip: ArrowTip): """ Creates the designer window for the arraw to design. Args: self: the Designer Window to initialize. parent: parent window. arrow_tip: ArrowTip object defining the arrow tip used. """ dim = Vec2(22, 16) self.csize = 20 size = dim * self.csize + Vec2.repeat(1) super().__init__(parent, size=size.as_tuple()) # add 1 to range end, so that the grid rectangle side will be included. rows = [r for r in range(0, int(size.y), self.csize)] cols = [c for c in range(0, int(size.x), self.csize)] self.begin_points = list() self.end_points = list() for r in rows: self.begin_points.append(wx.Point2D(0, r)) self.end_points.append(wx.Point2D(size.x - 1, r)) for c in cols: self.begin_points.append(wx.Point2D(c, 0)) self.end_points.append(wx.Point2D(c, size.y - 1)) self.handle_c = api.theme['handle_color'] self.hl_handle_c = api.theme['highlighted_handle_color'] self.handle_pen = wx.Pen(self.handle_c) self.hl_handle_pen = wx.Pen(self.hl_handle_c) self.handle_brush = wx.Brush(self.handle_c) self.hl_handle_brush = wx.Brush(self.hl_handle_c) phantom_c = opacity_mul(self.handle_c, 0.5) self.phantom_pen = wx.Pen(phantom_c) self.phantom_brush = wx.Brush(phantom_c) self.arrow_tip = arrow_tip self.radius = 12 self.radius_sq = self.radius**2 self.hover_idx = -1 self.dragged_point = None self.dragging = False self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.Bind(wx.EVT_MOTION, self.OnMotion) self.SetDoubleBuffered(True)
def projected_landing(self, point: Vec2) -> Vec2: """ Return the projected discrete landing point for the cursor. This is to make sure the user sees where the dragged arrow tip point will be dropped on the grid. Args: point: The cursor position relative to the window. Returns: Vec2 : projected point for landing. """ lx = point.x - point.x % self.csize ly = point.y - point.y % self.csize drop_x: float drop_y: float if point.x - lx < self.csize / 2: drop_x = lx else: drop_x = lx + self.csize if point.y - ly < self.csize / 2: drop_y = ly else: drop_y = ly + self.csize return Vec2(drop_x, drop_y)
def projected_landing(self, point: Vec2) -> Vec2: """ Definine projectedlanding point for arrow. Args: self: the Designer Window to initialize. point (vect2): point goven to find porjected landing. Returns: Vec2 : projected point for landing. """ lx = point.x - point.x % self.csize ly = point.y - point.y % self.csize drop_x: float drop_y: float if point.x - lx < self.csize / 2: drop_x = lx else: drop_x = lx + self.csize if point.y - ly < self.csize / 2: drop_y = ly else: drop_y = ly + self.csize return Vec2(drop_x, drop_y)
def OnLeftUp(self, evt): """ Action to take when selecting left upward. Args: self: the Designer Window to initialize. evt: the event being executed. """ if self.dragging: assert self.dragged_point is not None drop = self.projected_landing(self.dragged_point) assert self.hover_idx != -1 self.dragging = False self.arrow_tip.points[self.hover_idx] = Vec2( drop.x // self.csize, drop.y // self.csize) self.update_hover_idx(Vec2(evt.GetPosition())) self.Refresh()
def draw_point(self, gc: wx.GraphicsContext, point: Vec2, radius: float): """ Drawing a single point. Args: gc: Graphics context to modify. point: Point to be drawn. radius: Radius of the point. """ gc.DrawEllipse(*(point - Vec2.repeat(radius / 2)), radius, radius)
def test_add_basic(self): node = Node('Charles', self.neti, pos=Vec2(50, 50), size=Vec2(50, 30)) api.add_node( self.neti, id=node.id, position=node.position, size=node.size, fill_color=api._to_color(wx.RED), # HACK using API private methods border_color=api._to_color(wx.BLUE), border_width=2, ) nodes = api.get_nodes(self.neti) self.assertEqual(len(nodes), 1) self.assertEqual(0, nodes[0].index) expected = NodeData(id='Charles', net_index=self.neti, position=Vec2(50, 50), size=Vec2(50, 30), index=0) self.assertEqual(expected, nodes[0])
def draw_point(self, gc: wx.GraphicsContext, point: Vec2, radius: float): """ Drawing a single point. Args: self: the Designer Window to initialize. gc (wx.GraphixContext): Graphics context to modify. point (Vect2): Point to be drawn. radius (float): radius for the point. """ gc.DrawEllipse(*(point - Vec2.repeat(radius / 2)), radius, radius)
def test_separate_props(self): '''Test modifying the properties of node and alias that are separate, i.e. not shared. As in, if the position of an alias is changed, that of the node should remain the same, and vice versa. ''' alias_pos = Vec2(100, 100) alias_size = Vec2(50, 50) nodei = api.add_node(self.neti, id='Hookie') aliasi = api.add_alias(self.neti, nodei, position=alias_pos, size=alias_size) new_pos = Vec2(33, 33) new_size = Vec2(66, 66) new_lockNode = True api.update_node(self.neti, nodei, position=Vec2(33, 33), size=Vec2(66, 66), lockNode=True) node = api.get_node_by_index(self.neti, nodei) alias = api.get_node_by_index(self.neti, aliasi) # alias remains the same self.assertEqual(alias_pos, alias.position) self.assertEqual(alias_size, alias.size) self.assertEqual(False, alias.lockNode) # node is updated self.assertEqual(new_pos, node.position) self.assertEqual(new_size, node.size) self.assertEqual(new_lockNode, node.lockNode)
def test_update_failure(self): api.add_node(self.neti, id='Zulu') # empty ID with self.assertRaises(ValueError): api.update_node(self.neti, 0, id='') # nodes don't exist with self.assertRaises(NetIndexError): api.update_node(-1, 0, size=Vec2(50, 60)) with self.assertRaises(NodeIndexError): api.update_node(0, 2, size=Vec2(50, 60)) # out of bounds with self.assertRaises(ValueError): api.update_node(self.neti, 0, position=Vec2(-1, 0)) with self.assertRaises(ValueError): api.update_node(self.neti, 0, position=Vec2(0, -1)) csize = api.canvas_size() # in bounds api.update_node(self.neti, 0, position=csize - Vec2(100, 100)) # out of bounds with self.assertRaises(ValueError): api.update_node(self.neti, 0, position=csize - Vec2(1, 1))
def test_simple_handles(self): """Simple tests for Bezier handles.""" api.add_reaction(self.neti, 'AB', [0], [1]) api.set_reaction_center_handle(0, 0, Vec2(-10, 30)) self.assertEqual(api.get_reaction_center_handle(0, 0), Vec2(-10, 30)) api.set_reaction_node_handle(0, 0, 0, True, Vec2(40, 50)) self.assertEqual(api.get_reaction_node_handle(0, 0, 0, True), Vec2(40, 50)) with self.assertRaises(NodeIndexError): api.get_reaction_node_handle(0, 0, 12, True) # test for the case where node exists but not reactant/product with self.assertRaises(ValueError): api.get_reaction_node_handle(0, 0, 1, True) with self.assertRaises(ValueError): api.get_reaction_node_handle(0, 0, 0, False) with self.assertRaises(ReactionIndexError): api.get_reaction_node_handle(0, 2, 0, True)
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 OnMotion(self, evt): """ Action to take when moving around the screen. Args: self: the Designer Window to initialize. evt: the event being executed. """ pos = Vec2(evt.GetPosition()) if self.dragging: self.dragged_point = pos else: self.update_hover_idx(pos) evt.Skip() self.Refresh()
def OnMotion(self, evt: wx.MouseEvent): """ Handler for mouse motion events. Args: self: the Designer Window to initialize. evt: the event being executed. """ pos = Vec2(evt.GetPosition()) if self.dragging: self.dragged_point = pos else: self.update_hover_idx(pos) evt.Skip() self.Refresh()
def test_add_alias(self): size = Vec2(60, 60) nodei = api.add_node(self.neti, id='Hookie', size=size) api.add_alias(self.neti, nodei, size=size) nodes = api.get_nodes(self.neti) self.assertEqual(2, len(nodes)) original = NodeData(net_index=self.neti, id='Hookie', index=0, original_index=-1, size=size) alias = NodeData(net_index=self.neti, id='Hookie', index=1, original_index=0, size=size) self.assertEqual(original, nodes[0]) self.assertEqual(alias, nodes[1])
def Visualize(self, evt): """ Handler for the "Visualize" button. Visualize the SBML string to a network shown on the canvas. """ def hex_to_rgb(value): value = value.lstrip('#') return tuple(int(value[i:i+2], 16) for i in (0, 2, 4)) if len(self.sbmlStr) == 0: 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 =[] spec_dimension_list =[] spec_position_list = [] #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(self.sbmlStr) model_layout = document.getModel() mplugin = (model_layout.getPlugin("layout")) if mplugin is None: 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: 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() 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]) rPlugin = layout.getPlugin("render") if (rPlugin != None and rPlugin.getNumLocalRenderInformationObjects() > 0): 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() 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(self.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 len(comp_id_list) != 0: #if mplugin is not None: for j in range(numComps): 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 dimension = [4000,2500] position = [0,0] 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 for i in range(numComps): comp_node_list[i] = [] if len(comp_id_list) != 0: #if mplugin is not None: for i in range (numFloatingNodes): temp_id = FloatingNodes_ids[i] comp_id = model.getCompartmentIdSpeciesIsIn(temp_id) for j in range(numNodes): if temp_id == spec_id_list[j]: dimension = spec_dimension_list[j] position = spec_position_list[j] nodeIdx_temp = api.add_node(net_index, id=temp_id, floatingNode = 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) 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) for j in range(numNodes): if temp_id == spec_id_list[j]: dimension = spec_dimension_list[j] position = spec_position_list[j] nodeIdx_temp = api.add_node(net_index, id=temp_id, floatingNode = 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) for j in range(numComps): if comp_id == comp_id_list[j]: comp_node_list[j].append(nodeIdx_temp) 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), floatingNode = 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) 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), floatingNode = 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) 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 j in range(len(node_list_temp)): api.set_compartment_of_node(net_index=net_index, node_index=node_list_temp[j], 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)
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])
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)
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)