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) 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)
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)) export_btn = wx.Button(self.window, -1, 'Export', (5, 5)) export_btn.Bind(wx.EVT_BUTTON, self.Export) save_btn = wx.Button(self.window, -1, 'Save', (100, 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) self.antimonyText.SetInsertionPoint(0) return self.window def Export(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) id = allNodes[0].id[0:-2] 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 + id + '_' + str( allReactions[i].sources[j]) antStr = antStr + ' + ' antStr = antStr + id + '_' + str( allReactions[i].sources[rct_num - 1]) antStr = antStr + ' -> ' for j in range(prd_num - 1): antStr = antStr + id + '_' + str( allReactions[i].targets[j]) antStr = antStr + ' + ' antStr = antStr + id + '_' + str( allReactions[i].targets[prd_num - 1]) antStr = antStr + '; E' + str(i) + '*(k' + str(i) for j in range(rct_num): antStr = antStr + '*' + id + '_' + str( allReactions[i].sources[j]) if isReversible: antStr = antStr + ' - k' + str(i) + 'r' for j in range(prd_num): antStr = antStr + '*' + id + '_' + str( allReactions[i].targets[j]) antStr = antStr + ')' antStr = antStr + ';\n' self.antimonyText.SetValue(antStr) 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()
class IMPORTSBML(WindowedPlugin): metadata = PluginMetadata( name='ImportSBML', author='Jin Xu', version='0.0.2', 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 = '' import_btn = wx.Button(self.window, -1, 'Import', (5, 5)) import_btn.Bind(wx.EVT_BUTTON, self.Import) visualize_btn = wx.Button(self.window, -1, 'Visualize', (100, 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) self.SBMLText.SetInsertionPoint(0) return self.window def Import(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 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)
Version 0.01: Author: Gary Geng (2020) """ # pylint: disable=maybe-no-member from rkviewer.utils import opacity_mul from rkviewer.canvas.state import ArrowTip import wx from typing import List, Tuple from rkplugin import api from rkplugin.plugins import PluginMetadata, WindowedPlugin from rkplugin.api import Vec2 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.') class DesignerWindow(wx.Window): """ Defining the designer window. """ def __init__(self, parent, arrow_tip: ArrowTip): """ Creates the designer window for the arraw to design. Args: self: the Designer Window to initialize.
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)
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)
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
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") nb.AddPage(self.tab2, "Moiety Conservation Laws") # 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 Conservation Laws', (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. """ #self.index_list=[] 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 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] self.default_color = allNodes[0].fill_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)) 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)) CSUM_id = 0 for i in range(moi_mat.shape[0]): a = moi_mat[i, :] a = [0 if 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")) # 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) #print(value) 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, border_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, border_color=self.default_color) except: wx.MessageBox("There is no highlighted nodes", "Message", wx.OK | wx.ICON_INFORMATION)
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])
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)) export_btn = wx.Button(self.window, -1, 'Export', (5, 5)) export_btn.Bind(wx.EVT_BUTTON, self.Export) save_btn = wx.Button(self.window, -1, 'Save', (100, 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) self.SBMLText.SetInsertionPoint(0) return self.window def Export(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 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 if numCompartments != 0: for i in range(numCompartments): compartment = model.createCompartment() comp_id = allcompartments[i].id compartment.setId(comp_id) compartment.setConstant(True) for j in range(len(allcompartments[i].nodes)): spec_id = allNodes[allcompartments[i].nodes[j]].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[allcompartments[i]. nodes[j]].floatingNode == False: species.setBoundaryCondition(True) else: #set default compartment compartment = model.createCompartment() comp_id = "c_0" compartment.setId(comp_id) compartment.setConstant(True) for i in range(numNodes): 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].floatingNode == 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(allNodes[allReactions[i].sources[j]].id) for j in range(prd_num): prd.append(allNodes[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: for i in range(numCompartments): comp_id = allcompartments[i].id 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 j in range(len(allcompartments[i].nodes)): spec_id = allNodes[allcompartments[i].nodes[j]].id speciesGlyph = layout.createSpeciesGlyph() specG_id = "SpecG_" + spec_id speciesGlyph.setId(specG_id) speciesGlyph.setSpeciesId(spec_id) bb_id = "bb_" + spec_id pos_x = allNodes[ allcompartments[i].nodes[j]].position.x pos_y = allNodes[ allcompartments[i].nodes[j]].position.y width = allNodes[allcompartments[i].nodes[j]].size.x height = allNodes[allcompartments[i].nodes[j]].size.y speciesGlyph.setBoundingBox( BoundingBox(layoutns, bb_id, pos_x, pos_y, width, height)) textGlyph = layout.createTextGlyph() textG_id = "TextG_" + spec_id textGlyph.setId(textG_id) bb_id = "bb_spec_text_" + spec_id textGlyph.setBoundingBox( BoundingBox(layoutns, bb_id, pos_x, pos_y, width, height)) textGlyph.setOriginOfTextId(specG_id) textGlyph.setGraphicalObjectId(specG_id) else: #there is no compartment for i in range(numNodes): spec_id = allNodes[i].id speciesGlyph = layout.createSpeciesGlyph() specG_id = "SpecG_" + spec_id speciesGlyph.setId(specG_id) speciesGlyph.setSpeciesId(spec_id) bb_id = "bb_" + spec_id 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 textGlyph.setId(textG_id) bb_id = "bb_spec_text_" + spec_id textGlyph.setBoundingBox( BoundingBox(layoutns, bb_id, pos_x, pos_y, 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_num = len(allReactions[i].sources) prd_num = len(allReactions[i].targets) for j in range(rct_num): rct.append(allNodes[allReactions[i].sources[j]].id) for j in range(prd_num): prd.append(allNodes[allReactions[i].targets[j]].id) 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] speciesReferenceGlyph.setId(specsRefG_id) speciesReferenceGlyph.setSpeciesGlyphId(specG_id) speciesReferenceGlyph.setSpeciesReferenceId(ref_id) speciesReferenceGlyph.setRole(SPECIES_ROLE_UNDEFINED) 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 = allNodes[allReactions[i].sources[j]].position.x pos_y = allNodes[allReactions[i].sources[j]].position.y width = allNodes[allReactions[i].sources[j]].size.x height = allNodes[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] speciesReferenceGlyph.setId(specsRefG_id) speciesReferenceGlyph.setSpeciesGlyphId(specG_id) speciesReferenceGlyph.setSpeciesReferenceId(ref_id) speciesReferenceGlyph.setRole(SPECIES_ROLE_UNDEFINED) 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 = allNodes[allReactions[i].targets[j]].position.x pos_y = allNodes[allReactions[i].targets[j]].position.y width = allNodes[allReactions[i].targets[j]].size.x height = allNodes[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 if numCompartments != 0: fill_color = allcompartments[0].fill_color border_color = allcompartments[0].border_color comp_border_width = allcompartments[0].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) else: comp_border_width = 2. fill_color_str = '#9ea9ff' border_color_str = '#001dff' #nodeData does not have fill_color,border_color,border_width node = allNodes[0] # spec_fill_color = node.fill_color # spec_border_color = node.border_color # spec_border_width = node.border_width # 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_fill_color_str = '#ffcc99' spec_border_color_str = '#ff6c09' spec_border_width = 2. if numReactions != 0: reaction_fill_color = allReactions[0].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 #add some colors color = rInfo.createColorDefinition() color.setId("black") color.setColorValue("#000000") 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) color = rInfo.createColorDefinition() color.setId("spec_fill_color") color.setColorValue(spec_fill_color_str) color = rInfo.createColorDefinition() color.setId("spec_border_color") color.setColorValue(spec_border_color_str) if numReactions != 0: color = rInfo.createColorDefinition() color.setId("reaction_fill_color") color.setColorValue(reaction_fill_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)) style = rInfo.createStyle("specStyle") style.getGroup().setFillColor("spec_fill_color") style.getGroup().setStroke("spec_border_color") style.getGroup().setStrokeWidth(spec_border_width) style.addType("SPECIESGLYPH") 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: style = rInfo.createStyle("reactionStyle") style.getGroup().setStroke("reaction_fill_color") 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()
The color of all selected nodes and reactions are set to the picked color. Version 0.01: Author: Gary Geng (2020) """ # pylint: disable=maybe-no-member import wx from typing import List from rkplugin.plugins import CommandPlugin, PluginMetadata, WindowedPlugin from rkplugin import api metadata = PluginMetadata( name='ColorSelected', author='Gary Geng', version='0.0.1', short_desc='Pick a color, and set everything selected to that color.', long_desc= 'The color of all selected nodes and reactions are set to the picked color.' ) class ColorSelected(WindowedPlugin): def __init__(self): """ Initialize the ColorSelected with no values for a Windowed Plugin. Args: self """ super().__init__(metadata)
The fill and border color of all nodes are set to a random color. Version 0.01: Author: Gary Geng (2020) """ # pylint: disable=maybe-no-member import wx import random from rkplugin.plugins import CommandPlugin, PluginMetadata from rkplugin import api metadata = PluginMetadata( name='Disco', author='Gary Geng', version='0.0.1', short_desc='Set all nodes to a random color.', long_desc= 'The fill and border color of all nodes are set to a random color.') class Disco(CommandPlugin): def __init__(self): """ Initialize the ColorSelected with no values for a Command Plugin. Args: self """ super().__init__(metadata)