def getNodeSizes(net,size_by="strength",minsize=2.0,maxsize=6.0): """Returns a dictionary {node:size} for visualizations. The sizes are set using either node strength""" nodeSizes={} if size_by=="strength": if hasattr(net,'matrixtype'): if net.matrixtype==0: net=transforms.dist_to_weights(net) strengths = netext.strengths(net) maxs = max(strengths.values()) mins = min(strengths.values()) if maxs==mins: A=0 else: A=(maxsize-minsize)/(maxs-mins) B=maxsize-A*maxs for node in net: nodeSizes[node]=A*strengths[node]+B elif size_by=="fixed": for node in net: nodeSizes[node]=maxsize else: numeric_props=netext.getNumericProperties(net) if size_by in numeric_props: values=[] for node in net: values.append(net.nodeProperty[size_by][node]) minval=min(values) maxval=max(values) if maxval==minval: A=0 else: A=(maxsize-minsize)/(maxval-minval) B=maxsize-A*maxval for node in net: nodeSizes[node]=A*net.nodeProperty[size_by][node]+B return nodeSizes
def getNodeSizes(net, size_by="strength", minsize=2.0, maxsize=6.0): """Returns a dictionary {node:size} for visualizations. The sizes are set using either node strength""" nodeSizes = {} if size_by == "strength": if hasattr(net, 'matrixtype'): if net.matrixtype == 0: net = transforms.dist_to_weights(net) strengths = netext.strengths(net) maxs = max(strengths.values()) mins = min(strengths.values()) if maxs == mins: A = 0 else: A = (maxsize - minsize) / (maxs - mins) B = maxsize - A * maxs for node in net: nodeSizes[node] = A * strengths[node] + B elif size_by == "fixed": for node in net: nodeSizes[node] = maxsize else: numeric_props = netext.getNumericProperties(net) if size_by in numeric_props: values = [] for node in net: values.append(net.nodeProperty[size_by][node]) minval = min(values) maxval = max(values) if maxval == minval: A = 0 else: A = (maxsize - minsize) / (maxval - minval) B = maxsize - A * maxval for node in net: nodeSizes[node] = A * net.nodeProperty[size_by][node] + B return nodeSizes
def strength_distribution(network,style='logbin',Nbins=25): '''Returns the binned strength probability distribution of a network. Optional inputs: style = 'logbin' or 'linbin', Nbins = # of bins Output: list [s,P(s)]''' sv=netext.strengths(network) strength_vector=sv.values() minw=min(strength_vector) maxw=max(strength_vector) if style=='logbin': factor=(float(maxw)/minw)**(1.0/Nbins) bins=generateLogbins(minw,maxw,factor,False) else: bins=generateLinbins(minw,maxw,Nbins) bc=binCenters(bins) Pbin=probabilityLogbinner(bins,strength_vector) return [bc,Pbin]
def strength_distribution(network, style='logbin', Nbins=25): '''Returns the binned strength probability distribution of a network. Optional inputs: style = 'logbin' or 'linbin', Nbins = # of bins Output: list [s,P(s)]''' sv = netext.strengths(network) strength_vector = sv.values() minw = min(strength_vector) maxw = max(strength_vector) if style == 'logbin': factor = (float(maxw) / minw)**(1.0 / Nbins) bins = generateLogbins(minw, maxw, factor, False) else: bins = generateLinbins(minw, maxw, Nbins) bc = binCenters(bins) Pbin = probabilityLogbinner(bins, strength_vector) return [bc, Pbin]
def visualizeNet(net, coords=None, axes=None, frame=False, animated=False, scaling=True, margin=0.025, nodeShapes=None, defaultNodeShape='o', nodeSizes=None, defaultNodeSize=None, nodeColors=None, defaultNodeColor=None, nodeEdgeColors=None, defaultNodeEdgeColor='black', nodeLabels=None, nodeLabelSize=None, labelAllNodes=False, labelPositions=None, defaultLabelPosition='out', edgeColors=None, defaultEdgeColor=None, edgeWidths=None, defaultEdgeWidth=None, nodeEdgeWidths=None, defaultNodeEdgeWidth=0.2, edgeLabels=None, edgeLabelSize=None, labelAllEdges=False, nodePlotOrders=None, defaultNodePlotOrder=1, edgePlotOrders=None, defaultEdgePlotOrder=0): """Visualize a network. Note that all sizes (node size, link width, etc.) are given in points: one point equals 1/72th of an inch. Basic parameters ---------------- net : pynet.SymmNet The network to visualize coords : dictionary of tuples {node_ID: (x,y)} Coordinates of all nodes. If None, the coordinates will be calculated. The x and y coordinates are assumed to have the same scale, so for example an edge between nodes 0 and 1 with `coords[0]=(0,0)` and `coords[1]=(2,2)` will be at an angle of 45 degrees. axes : pylab.axes object If given, the network will be drawn in this axis. Otherwise a new figure is created for the plot and the figure handle is then returned. frame : bool If False, the frame will be not be shown in the plot. You can still use axis labels. scaling : bool If True, the coordinate axes will be scaled for best fit. If false, the coordinate axes will not be altered. margin : float (>= 0) The relative size of empty margin around the network. Margin of 0.0 means that some nodes touch the edge of the plot, margin of 0.2 adds 20 % on all sides etc. This parameter has an effect only if scaling is True. Defining node and edge colors ----------------------------- Colors for nodes and edges are defined similarly. The following explains the procedure for nodes; to control edge coloring simply replace the word 'node' (or 'Node') with the word 'edge' (or 'Edge') in the parameter names. The color of a node is defined with the dictionary `nodeColors`: key is the node index and the value is any valid coloring scheme (see below under 'Coloring schemes'). If a node index is not in `nodeColors`, it is colored according to `defaultNodeColor`. This variable can have the same values as the values in `nodeColors`. Coloring schemes ---------------- A constant color can be defined in any way allowed by pylab. For example 'k', 'black' and (0,0,0) all give black color. Alternatively the color can be based on the node strength, degree or any node property. In this case the coloring definition is a dictionary. The following examples illustrate the idea: color_scheme = {'by':'weight', 'scale':'log', 'cmap':'winter'} color_scheme = {'by':'degree', 'scale':'lin', 'min':1, 'max':10} color_scheme = {'by':'property:myProperty', 'scale':'log'} The possible keys and their default values are KEY DEFAULT VALUE OTHER POSSIBLE VALUES 'by' 'strength'/'weight' 'degree', 'property:<property_name>' 'scale' 'log' 'lin' 'cmap' 'jet' Any colormap 'min' (Min value in data) Any integer x, 1 <= x <= 'max' 'max' (Max value in data) Any integer x, 'min' <= x Any keys that are omitted are filled in with the default value. Note the syntax for using node properties, where the word 'property' is followed by a semicolon and the property name. Node size --------- The node size is controlled with a syntax similar to that used with colors. Node size is defined by dictionary `nodeSizes`, and if a node is not in it, the default value given by `defaultNodeSize` is used. The value can be a single integer, which gives the node size in pixels. Alternatively the node size can be controlled by node strength, degree or any property: node_size_scheme = {'by':'strength', 'scale':'log', 'min':2, 'max':10} node_size_scheme = {'by':'degree', 'scale':'lin'} node_size_scheme = {'by':'property:myProperty', 'scale':'log'} The possible keys and their default values are KEY DEFAULT VALUE OTHER POSSIBLE VALUES 'by' 'strength' 'degree', 'property:<property_name>' 'scale' 'log' 'lin' 'min' (Min value in data) int; 1 <= x <= 'max' 'max' (Max value in data) int; 'min' <= x 'min_size' 1 int; 1 <= x <= 'max_size' 'max_size' 6 int; 'min_size' <= x Again, keys that are omitted are filled with default values. Edge width ---------- Edge width is defined by dictionary `edgeWidths`, and if an edge is not in it, the default value given by `defaultEdgeWidth` is used. The value can be a single integer, which gives the edge width in pixels. Alternatively the edge width can be controlled by edge weight: edge_width_scheme = {'by':'weight', 'scale':'log', 'min':1, 'max':5} The possible keys and their default values are KEY DEFAULT VALUE OTHER POSSIBLE VALUES 'by' 'weight' 'scale' 'log' 'lin' 'min' (Min value in data) int; 1 <= x <= 'max' 'max' (Max value in data) int; 'min' <= x 'min_size' 0.2 float; 1 <= x <= 'max_width' 'max_size' 2.0 float; 'min_width' <= x Note that the 'by'-key can always be omitted since it has only one possible value. Node labels ----------- Node labels can be given in `nodeLabels` dictionary, where the key is node index and the value is the corresponding labels. If `labelAllNodes` is True, also nodes not in `nodeLabels` will receive a label, which is the node index. The values in `nodeLabels` are converted to string with str(). There are two possibilities for the positioning of node labels: 'in' and 'out' (default). 'in' means that the label is printed at the exact position of the node; if the node is hollow, this effectively prints the node labes inside the nodes (make sure the node size and font sizes are compatible). 'out' prints the label next to the node. Edge labels ----------- Also edges can have labels, given in `edgeLabels` dictionary, where the key is a tuple (i,j) of end node indices. The edge labels are always printed on the right side of each edge (with direction defined from i to j). If `labelAllEdges` is True, also the edges not listed in `edgeLabels` will be given a label. In this case the label is '(i,j)', where i and j are the indices of the end nodes. Return ------ fig : pylab.Figure (None if `axes` is given.) Figure object with one axes containing the plotted network figure. Examples -------- >>> # Construct an example network. >>> from netpython import pynet, visuals >>> net = pynet.SymmNet() >>> net[0][1] = 1.0 >>> net[1][2] = 3.5 >>> net[0][2] = 5.0 >>> # Simplest case: get coordinates, plot into a >>> # new figure and save it to disk >>> fig = visuals.visualizeNet(net) >>> fig.savefig('myNet.eps') >>> # Draw the figure in the upper left subfigure, with predefined >>> # coordinates. Note that drawNet does not return anything. >>> import pylab >>> coords = {0:(0,0), 1:(4,0), 2:(2,3)} >>> fig = pylab.figure() >>> ax = fig.add_subplot(2,2,1) >>> visuals.visualizeNet(net, coords=coords, axes=ax) """ # # DEFAULT VALUES. These will be used whenever the user has not # defined a given value for defaultNodeColor etc. # internal_defaultNodeColor = {'by':'strength', 'scale':'log', 'cmap':'jet'} internal_defaultEdgeColor = {'by':'weight', 'scale':'log', 'cmap':'jet'} internal_defaultNodeSize = {'by':'strength', 'scale':'log', 'min_size':2, 'max_size':6} internal_defaultEdgeWidth = {'by':'weight', 'scale':'log', 'min_size':0.2, 'max_size':2.0} node_label_font_color = 'k' node_label_font_size = (8 if nodeLabelSize==None else nodeLabelSize) edge_label_font_color = None #'k' edge_label_font_size = (5 if edgeLabelSize==None else edgeLabelSize) # # PROCESS INPUT PARAMETERS # if coords is None: coords = calculateCoordinates(net) fig = None if axes is None: fig = figure() axes = fig.add_subplot(111) nodeShapes = (nodeShapes or {}) nodeColors = (nodeColors or {}) defaultNodeColor = (defaultNodeColor or {}) if isinstance(defaultNodeColor, dict): for k,v in internal_defaultNodeColor.iteritems(): if k not in defaultNodeColor: defaultNodeColor[k] = v nodeEdgeColors = (nodeEdgeColors or {}) edgeColors = (edgeColors or {}) defaultEdgeColor = (defaultEdgeColor or {}) if isinstance(defaultEdgeColor, dict): for k,v in internal_defaultEdgeColor.iteritems(): if k not in defaultEdgeColor: defaultEdgeColor[k] = v nodeSizes = (nodeSizes or {}) if defaultNodeSize is None: defaultNodeSize = {} if isinstance(defaultNodeSize, dict): for k,v in internal_defaultNodeSize.iteritems(): if k not in defaultNodeSize: defaultNodeSize[k] = v edgeWidths = (edgeWidths or {}) if defaultEdgeWidth is None: defaultEdgeWidth = {} if isinstance(defaultEdgeWidth, dict): for k,v in internal_defaultEdgeWidth.iteritems(): if k not in defaultEdgeWidth: defaultEdgeWidth[k] = v nodeEdgeWidths = (nodeEdgeWidths or {}) nodeLabels = (nodeLabels or {}) labelPositions = (labelPositions or {}) edgeLabels = (edgeLabels or {}) nodePlotOrders = (nodePlotOrders or {}) edgePlotOrders = (edgePlotOrders or {}) if margin < 0: margin = 0.0 # Initialize dictionary where the returned plotted artist objects will be collected. obj = dict() # # AUXILIARY FUNCTIONS # def scaled(scaling_type, value, value_limits, final_limits): def lin_scaling(value, value_limits, final_limits): value_span = value_limits[1] - value_limits[0] final_span = final_limits[1] - final_limits[0] if final_span == 0: return final_limits[0] if value_span == 0: p = 0.5 else: p = float(value - value_limits[0])/value_span return final_limits[0]+p*final_span if value <= value_limits[0]: return final_limits[0] if value >= value_limits[1]: return final_limits[1] if scaling_type == 'log' or scaling_type == 'logarithmic': return lin_scaling(np.log(value), np.log(value_limits), final_limits) else: return lin_scaling(value, value_limits, final_limits) def determine_size(scheme, i, net, values, limits, defaults): if not isinstance(scheme, dict): return scheme else: # Determine what defines the size. Calculate the limits # for this property if not yet done. size_by = scheme.get('by', defaults['by']) if size_by not in limits: property_name = "".join(size_by.split(':')[1:]) np_ = sorted(net.nodeProperty[property_name].values()) limits[size_by] = (np_[0], np_[-1]) if size_by not in values: property_name = "".join(size_by.split(':')[1:]) values[size_by] = net.nodeProperty[property_name][i] scale = scheme.get('scale', defaults['scale']) val_min = scheme.get('min', limits[size_by][0]) val_max = scheme.get('max', limits[size_by][1]) size_min = scheme.get('min_size', defaults['min_size']) size_max = scheme.get('max_size', defaults['max_size']) #print size_by, scale, val_min, val_max, size_min, size_max return scaled(scale, values[size_by], [val_min, val_max], [size_min, size_max]) def determine_color(scheme, i, net, values, limits, defaults): if not isinstance(scheme, dict): return scheme else: color_by = scheme.get('by', defaults['by']) if color_by not in limits: property_name = "".join(color_by.split(':')[1:]) np_ = sorted(net.nodeProperty[property_name].values()) limits[color_by] = (np_[0], np_[-1]) if color_by not in values: property_name = "".join(color_by.split(':')[1:]) values[color_by] = net.nodeProperty[property_name][i] scale = scheme.get('scale', defaults['scale']) cmap = scheme.get('cmap', defaults['cmap']) val_min = scheme.get('min', limits[color_by][0]) val_max = scheme.get('max', limits[color_by][1]) cval = scaled(scale, values[color_by], [val_min, val_max], [0.0,1.0]) cm = setColorMap(cmap) return cm(float(cval)) def luminance(c): """Return luminance of color `c`.""" c_vec = matplotlib.colors.colorConverter.to_rgb(c) return 0.2126*c_vec[0]+0.7152*c_vec[1]+0.0722*c_vec[2] def edge_label_pos(axes, xcoords, ycoords, edge_width, label_size, offset=1.5): """Return the baseline position and label rotation (in angles) for an edge label. The label will be on the right side of the edge, in proper orientation for reading, and located `offset` points from the edge. """ theta = get_edge_angle(xcoords, ycoords) if theta > -np.pi/2 and theta < np.pi/2: # Edge goes from left to right. label_rotation = theta else: # Edge goes from right to left. label_rotation = theta - np.pi offset_points = offset+0.5*edge_width+0.5*label_size label_position = (0.5*sum(xcoords), 0.5*sum(ycoords)) offset_dir = theta - np.pi/2 label_offset = (offset_points*np.cos(offset_dir), offset_points*np.sin(offset_dir)) return label_position, label_offset, 180*label_rotation/np.pi # # INITIALIZE SOME DATA STRUCTURES # # Find out the minimum and maximum value for strength and degree. strengths = netext.strengths(net) smin, smax = min(strengths.values()), max(strengths.values()) degrees = netext.deg(net) dmin, dmax = min(degrees.values()), max(degrees.values()) limits = {"strength":(smin, smax), "degree":(dmin,dmax)} # # INITIALIZE AXES SIZE # node_diameters = {}; for nodeIndex in net: values = {"strength": strengths[nodeIndex], "degree": degrees[nodeIndex]} node_diameters[nodeIndex] = (determine_size(nodeSizes.get(nodeIndex, defaultNodeSize), nodeIndex, net, values, limits, defaultNodeSize) + determine_size(nodeEdgeWidths.get(nodeIndex, defaultNodeEdgeWidth), nodeIndex, net, values, limits, defaultNodeEdgeWidth)) if scaling: # Make axis equal making sure the nodes on the edges are not # clipped. We cannot use `axis('equal')` because nothing has been # drawn yet, but we still need to do this so the arrows will be # draw properly in the plotting phase. This is a bit tricky # because the axes might not be square. max_node_diameter = max(node_diameters.values()) y_coords = sorted(map(operator.itemgetter(1), coords.values())) x_coords = sorted(map(operator.itemgetter(0), coords.values())) ax_pos = axes.get_position() x_span = x_coords[-1] - x_coords[0] y_span = y_coords[-1] - y_coords[0] ax_width_inches = ax_pos.width*axes.get_figure().get_figwidth() ax_height_inches = ax_pos.height*axes.get_figure().get_figheight() if (x_span*ax_height_inches > y_span*ax_width_inches): # The x-span dictates the coordinates. Calculate the margin # necessary to fit in the nodes on the edges. rad_frac = 0.5*max_node_diameter/(72*ax_width_inches) x_margin = x_span*rad_frac/(1-2*rad_frac) x_min, x_max = x_coords[0]-x_margin, x_coords[-1]+x_margin y_mid = 0.5*(y_coords[-1] + y_coords[0]) y_axis_span = (x_max-x_min)*ax_height_inches/ax_width_inches y_min, y_max = y_mid - 0.5*y_axis_span, y_mid + 0.5*y_axis_span, else: # The y-span dictates the coordinates. Calculate the margin # necessary to fit in the nodes on the edges. rad_frac = 0.5*max_node_diameter/(72*ax_height_inches) y_margin = y_span*rad_frac/(1-2*rad_frac) y_min, y_max = y_coords[0]-y_margin, y_coords[-1]+y_margin x_mid = 0.5*(x_coords[-1] + x_coords[0]) x_axis_span = (y_max-y_min)*ax_width_inches/ax_height_inches x_min, x_max = x_mid - 0.5*x_axis_span, x_mid + 0.5*x_axis_span, y_span, x_span = y_max - y_min, x_max - x_min axes.set_ylim(ymin=y_min-margin*y_span, ymax=y_max+margin*y_span) axes.set_xlim(xmin=x_min-margin*x_span, xmax=x_max+margin*x_span) prev_autoscale = axes.get_autoscale_on() axes.set_autoscale_on(False) point_trans = lambda x_: points_to_data(ax,x_) # Transform points to data coordinates. # # DRAW EDGES # edges = list(net.edges) if edges: # Sort by edge weight. edges.sort(key=operator.itemgetter(2)) limits['weight'] = (edges[0][2], edges[-1][2]) # DEBUGGING: Print statistics of edge weights. #import data_utils #weights_ = map(operator.itemgetter(2), edges) #print "Edges:", limits['weight'], " 10/25/50/75/90:", #mp_ = len(edges)/2 #print "%d, %d, %d, %d, %d" % (int(data_utils.percentile(weights_, 0.1)), # int(data_utils.percentile(weights_, 0.25)), # int(data_utils.percentile(weights_, 0.5)), # int(data_utils.percentile(weights_, 0.75)), # int(data_utils.percentile(weights_, 0.9))) net_edges = NetEdges(axes, net.isSymmetric()) for i,j,w in edges: values = {"weight": w, "strength": strengths[j], "degree": degrees[j]} # Determine edge width. if (i,j) in edgeWidths: width = determine_size(edgeWidths[(i,j)], (i,j), net, values, limits, defaultEdgeWidth) elif (j,i) in edgeWidths: width = determine_size(edgeWidths[(j,i)], (j,i), net, values, limits, defaultEdgeWidth) else: width = determine_size(defaultEdgeWidth, (i,j), net, values, limits, defaultEdgeWidth) # Determine edge color. if (i,j) in edgeColors: color = determine_color(edgeColors[(i,j)], (i,j), net, values, limits, defaultEdgeColor) elif (j,i) in edgeColors: color = determine_color(edgeColors[(j,i)], (j,i), net, values, limits, defaultEdgeColor) else: color = determine_color(defaultEdgeColor, (j,i), net, values, limits, defaultEdgeColor) if (i,j) in edgePlotOrders: zorder = edgePlotOrders[(i,j)] elif (j,i) in edgePlotOrders: zorder = edgePlotOrders[(j,i)] else: zorder = defaultEdgePlotOrder # FOR DEBUGGING: #print "Edge (%d,%d / %.2f) : %.1f %s %f" % (i,j,w,width,str(color),zorder) xcoords, ycoords = (coords[i][0], coords[j][0]), (coords[i][1], coords[j][1]) #obj[(i,j)] = draw_edge(axes, xcoords, ycoords, width, color, # net.isSymmetric(), zorder, node_diameters[j]) net_edges.add(xcoords, ycoords, width, color, zorder, node_diameters[j]) # Add edge label. if (labelAllEdges or (i,j) in edgeLabels or (net.isSymmetric() and (j,i) in edgeLabels)): if (i,j) in edgeLabels: label = str(edgeLabels[(i,j)]) elif (net.isSymmetric() and (j,i) in edgeLabels): label = str(edgeLabels[(j,i)]) else: label = "(%d,%d)" % (i,j) lpos, loffset, lrot = edge_label_pos(axes, xcoords, ycoords, width, edge_label_font_size) axes.annotate(label, lpos, xytext=loffset, textcoords='offset points', color=edge_label_font_color, size=edge_label_font_size, horizontalalignment='center', verticalalignment='center', rotation=lrot, zorder=zorder+0.5) # # DRAW NODES # max_node_diameter = 0; net_nodes = NetNodes(axes) node_internal_color = {} for nodeIndex in net: values = {"strength": strengths[nodeIndex], "degree": degrees[nodeIndex]} # Determine node shape. shape = nodeShapes.get(nodeIndex, defaultNodeShape) # Determine node size (and update max size). size = determine_size(nodeSizes.get(nodeIndex, defaultNodeSize), nodeIndex, net, values, limits, defaultNodeSize) # Determine node edge width. edgewidth = determine_size(nodeEdgeWidths.get(nodeIndex, defaultNodeEdgeWidth), nodeIndex, net, values, limits, defaultNodeEdgeWidth) max_node_diameter = max(max_node_diameter, size+edgewidth) # Determine node color color = determine_color(nodeColors.get(nodeIndex, defaultNodeColor), nodeIndex, net, values, limits, defaultNodeColor) node_internal_color[nodeIndex] = color # Determine node edge color edgecolor = determine_color(nodeEdgeColors.get(nodeIndex, defaultNodeEdgeColor), nodeIndex, net, values, limits, defaultNodeEdgeColor) # Determine z-order. zorder = nodePlotOrders.get(nodeIndex, defaultNodePlotOrder) # FOR DEBUGGING: #print "Node %d : %f %s %f %s" % (nodeIndex, size, str(color), edgewidth, str(edgecolor)) #obj[nodeIndex] = draw_node(axes, coords[nodeIndex][0], coords[nodeIndex][1], # shape, color, size, edgecolor, edgewidth, zorder) net_nodes.add(coords[nodeIndex][0], coords[nodeIndex][1], color, size, edgecolor, edgewidth, zorder) # Add node label. if nodeIndex in nodeLabels or labelAllNodes: if nodeIndex in nodeLabels: label = str(nodeLabels[nodeIndex]) else: label = str(nodeIndex) label_pos = labelPositions.get(nodeIndex, defaultLabelPosition) if label_pos == 'out': nodeLabel_offset = int(np.ceil(float(size)/2))+1 axes.annotate(label, (coords[nodeIndex][0],coords[nodeIndex][1]), textcoords='offset points', xytext=(nodeLabel_offset, nodeLabel_offset), color=node_label_font_color, size=node_label_font_size, zorder=zorder+0.5) elif label_pos == 'in': axes.annotate(label, (coords[nodeIndex][0],coords[nodeIndex][1]), color=("black" if luminance(node_internal_color[nodeIndex]) > 0.5 else "white"), size=max(5, min(size-1, 0.7*size)), horizontalalignment='center', verticalalignment='center', zorder=zorder+0.5) # Remove frame. if not frame: # Using 'axes.set_axis_off()' would also turn of the axis # labels, which is too much. The following lines are required # to turn off the frame and tick labels while keeping axis # labels. axes.set_frame_on(False) axes.set_xticklabels([]) axes.xaxis.set_ticks_position('none') axes.set_yticklabels([]) axes.yaxis.set_ticks_position('none') # Return autoscaling to the original value. axes.set_autoscale_on(prev_autoscale) # Return figure (or objects drawn). return (obj if animated else axes.get_figure())
def getNodeColors(net,colorwith="strength",useColorMap="orange",parentnet=[]): """Returns a dictionary {node:color}. The colors are set based on either node strengh (colorwith="strength", default) or any nodeProperty. For cases where e.g. nodes which have been thresholded out (k=0), the input parameter parentnet can be used - parentnet should contain the original network *before* thresholding, i.e. containing all original nodes and their attributes. IF parentnet is given, i) if strength is used, its nodes which are NOT in net colored gray, ii) if properties are used, its nodes are colored similarly to those nodes in net. Also the dictionary which is returned contains then all nodes in parentnet""" myNodeColors=setColorMap(useColorMap) nodeColors={} if colorwith=="strength": if hasattr(net,'matrixtype'): if net.matrixtype==0: net=transforms.dist_to_weights(net) strengths = netext.strengths(net) max_value = max(strengths.values()) min_value = min(strengths.values()) if len(parentnet)>0: # if we want the dict to include nodes not in net for node in parentnet: if node in net: # if the node is in net, use its strength for color nodeColors[node]=setColor(strengths[node],(min_value,max_value),myNodeColors) else: # otherwise color it gray nodeColors[node]=(0.5,0.5,0.5) else: for node in net: # if parentnet not given, just color nodes by strength nodeColors[node]=setColor(strengths[node],(min_value,max_value),myNodeColors) else: numeric_props=netext.getNumericProperties(net) # first check if colorwith is a numeric property if colorwith in numeric_props: values=[] if len(parentnet)>0: # again if we want to include nodes not in net for node in parentnet: # first get min and max value of property values.append(parentnet.nodeProperty[colorwith][node]) min_value=min(values) max_value=max(values) for node in parentnet: # then set colors according to property nodeColors[node]=setColor(parentnet.nodeProperty[colorwith][node],(min_value,max_value),myNodeColors) else: # otherwise do the above for nodes in net for node in net: values.append(net.nodeProperty[colorwith][node]) min_value=min(values) max_value=max(values) for node in net: nodeColors[node]=setColor(net.nodeProperty[colorwith][node],(min_value,max_value),myNodeColors) else: # colorwith is not a numeric property, so look up unique values # and give them integer numbers values={} # empty dict for values if len(parentnet)>0:# if there are nodes not in net props=list(set(parentnet.nodeProperty[colorwith].values())) else: props=list(set(net.nodeProperty[colorwith].values())) #Check if properties can be converted to colors: if isListOfColors(props): propToColor={} cc=matplotlib.colors.ColorConverter() for p in props: propToColor[p]=cc.to_rgb(p) if len(parentnet)>0: for node in parentnet: nodeColors[node]=propToColor[parentnet.nodeProperty[colorwith][node]] else: for node in net: nodeColors[node]=propToColor[parentnet.nodeProperty[colorwith][node]] else: for i,prop in enumerate(props): values[prop]=i+1 # now all property strings have a numerical value min_value=1 max_value=max(values.values()) if len(parentnet)>0: for node in parentnet: nodeColors[node]=setColor(values[parentnet.nodeProperty[colorwith][node]],(min_value,max_value),myNodeColors) else: for node in net: nodeColors[node]=setColor(values[net.nodeProperty[colorwith][node]],(min_value,max_value),myNodeColors) if len(nodeColors)==0: # finally if for whatever reason no nodes were colored, just set them gray if len(parentnet)>0: for node in parentnet: nodeColors[node]=(0.5,0.5,0.5) else: for node in net: nodeColors[node]=(0.5, 0.5, 0.5) return nodeColors
def visualizeNet(net, coords=None, axes=None, frame=False, animated=False, scaling=True, margin=0.025, nodeShapes=None, defaultNodeShape='o', nodeSizes=None, defaultNodeSize=None, nodeColors=None, defaultNodeColor=None, nodeEdgeColors=None, defaultNodeEdgeColor='black', nodeLabels=None, nodeLabelSize=None, labelAllNodes=False, labelPositions=None, defaultLabelPosition='out', edgeColors=None, defaultEdgeColor=None, edgeWidths=None, defaultEdgeWidth=None, nodeEdgeWidths=None, defaultNodeEdgeWidth=0.2, edgeLabels=None, edgeLabelSize=None, labelAllEdges=False, nodePlotOrders=None, defaultNodePlotOrder=1, edgePlotOrders=None, defaultEdgePlotOrder=0): """Visualize a network. Note that all sizes (node size, link width, etc.) are given in points: one point equals 1/72th of an inch. Basic parameters ---------------- net : pynet.SymmNet The network to visualize coords : dictionary of tuples {node_ID: (x,y)} Coordinates of all nodes. If None, the coordinates will be calculated. The x and y coordinates are assumed to have the same scale, so for example an edge between nodes 0 and 1 with `coords[0]=(0,0)` and `coords[1]=(2,2)` will be at an angle of 45 degrees. axes : pylab.axes object If given, the network will be drawn in this axis. Otherwise a new figure is created for the plot and the figure handle is then returned. frame : bool If False, the frame will be not be shown in the plot. You can still use axis labels. scaling : bool If True, the coordinate axes will be scaled for best fit. If false, the coordinate axes will not be altered. margin : float (>= 0) The relative size of empty margin around the network. Margin of 0.0 means that some nodes touch the edge of the plot, margin of 0.2 adds 20 % on all sides etc. This parameter has an effect only if scaling is True. Defining node and edge colors ----------------------------- Colors for nodes and edges are defined similarly. The following explains the procedure for nodes; to control edge coloring simply replace the word 'node' (or 'Node') with the word 'edge' (or 'Edge') in the parameter names. The color of a node is defined with the dictionary `nodeColors`: key is the node index and the value is any valid coloring scheme (see below under 'Coloring schemes'). If a node index is not in `nodeColors`, it is colored according to `defaultNodeColor`. This variable can have the same values as the values in `nodeColors`. Coloring schemes ---------------- A constant color can be defined in any way allowed by pylab. For example 'k', 'black' and (0,0,0) all give black color. Alternatively the color can be based on the node strength, degree or any node property. In this case the coloring definition is a dictionary. The following examples illustrate the idea: color_scheme = {'by':'weight', 'scale':'log', 'cmap':'winter'} color_scheme = {'by':'degree', 'scale':'lin', 'min':1, 'max':10} color_scheme = {'by':'property:myProperty', 'scale':'log'} The possible keys and their default values are KEY DEFAULT VALUE OTHER POSSIBLE VALUES 'by' 'strength'/'weight' 'degree', 'property:<property_name>' 'scale' 'log' 'lin' 'cmap' 'jet' Any colormap 'min' (Min value in data) Any integer x, 1 <= x <= 'max' 'max' (Max value in data) Any integer x, 'min' <= x Any keys that are omitted are filled in with the default value. Note the syntax for using node properties, where the word 'property' is followed by a semicolon and the property name. Node size --------- The node size is controlled with a syntax similar to that used with colors. Node size is defined by dictionary `nodeSizes`, and if a node is not in it, the default value given by `defaultNodeSize` is used. The value can be a single integer, which gives the node size in pixels. Alternatively the node size can be controlled by node strength, degree or any property: node_size_scheme = {'by':'strength', 'scale':'log', 'min':2, 'max':10} node_size_scheme = {'by':'degree', 'scale':'lin'} node_size_scheme = {'by':'property:myProperty', 'scale':'log'} The possible keys and their default values are KEY DEFAULT VALUE OTHER POSSIBLE VALUES 'by' 'strength' 'degree', 'property:<property_name>' 'scale' 'log' 'lin' 'min' (Min value in data) int; 1 <= x <= 'max' 'max' (Max value in data) int; 'min' <= x 'min_size' 1 int; 1 <= x <= 'max_size' 'max_size' 6 int; 'min_size' <= x Again, keys that are omitted are filled with default values. Edge width ---------- Edge width is defined by dictionary `edgeWidths`, and if an edge is not in it, the default value given by `defaultEdgeWidth` is used. The value can be a single integer, which gives the edge width in pixels. Alternatively the edge width can be controlled by edge weight: edge_width_scheme = {'by':'weight', 'scale':'log', 'min':1, 'max':5} The possible keys and their default values are KEY DEFAULT VALUE OTHER POSSIBLE VALUES 'by' 'weight' 'scale' 'log' 'lin' 'min' (Min value in data) int; 1 <= x <= 'max' 'max' (Max value in data) int; 'min' <= x 'min_size' 0.2 float; 1 <= x <= 'max_width' 'max_size' 2.0 float; 'min_width' <= x Note that the 'by'-key can always be omitted since it has only one possible value. Node labels ----------- Node labels can be given in `nodeLabels` dictionary, where the key is node index and the value is the corresponding labels. If `labelAllNodes` is True, also nodes not in `nodeLabels` will receive a label, which is the node index. The values in `nodeLabels` are converted to string with str(). There are two possibilities for the positioning of node labels: 'in' and 'out' (default). 'in' means that the label is printed at the exact position of the node; if the node is hollow, this effectively prints the node labes inside the nodes (make sure the node size and font sizes are compatible). 'out' prints the label next to the node. Edge labels ----------- Also edges can have labels, given in `edgeLabels` dictionary, where the key is a tuple (i,j) of end node indices. The edge labels are always printed on the right side of each edge (with direction defined from i to j). If `labelAllEdges` is True, also the edges not listed in `edgeLabels` will be given a label. In this case the label is '(i,j)', where i and j are the indices of the end nodes. Return ------ fig : pylab.Figure (None if `axes` is given.) Figure object with one axes containing the plotted network figure. Examples -------- >>> # Construct an example network. >>> from netpython import pynet, visuals >>> net = pynet.SymmNet() >>> net[0][1] = 1.0 >>> net[1][2] = 3.5 >>> net[0][2] = 5.0 >>> # Simplest case: get coordinates, plot into a >>> # new figure and save it to disk >>> fig = visuals.visualizeNet(net) >>> fig.savefig('myNet.eps') >>> # Draw the figure in the upper left subfigure, with predefined >>> # coordinates. Note that drawNet does not return anything. >>> import pylab >>> coords = {0:(0,0), 1:(4,0), 2:(2,3)} >>> fig = pylab.figure() >>> ax = fig.add_subplot(2,2,1) >>> visuals.visualizeNet(net, coords=coords, axes=ax) """ # # DEFAULT VALUES. These will be used whenever the user has not # defined a given value for defaultNodeColor etc. # internal_defaultNodeColor = { 'by': 'strength', 'scale': 'log', 'cmap': 'jet' } internal_defaultEdgeColor = {'by': 'weight', 'scale': 'log', 'cmap': 'jet'} internal_defaultNodeSize = { 'by': 'strength', 'scale': 'log', 'min_size': 2, 'max_size': 6 } internal_defaultEdgeWidth = { 'by': 'weight', 'scale': 'log', 'min_size': 0.2, 'max_size': 2.0 } node_label_font_color = 'k' node_label_font_size = (8 if nodeLabelSize == None else nodeLabelSize) edge_label_font_color = None #'k' edge_label_font_size = (5 if edgeLabelSize == None else edgeLabelSize) # # PROCESS INPUT PARAMETERS # if coords is None: coords = calculateCoordinates(net) fig = None if axes is None: fig = figure() axes = fig.add_subplot(111) nodeShapes = (nodeShapes or {}) nodeColors = (nodeColors or {}) defaultNodeColor = (defaultNodeColor or {}) if isinstance(defaultNodeColor, dict): for k, v in internal_defaultNodeColor.iteritems(): if k not in defaultNodeColor: defaultNodeColor[k] = v nodeEdgeColors = (nodeEdgeColors or {}) edgeColors = (edgeColors or {}) defaultEdgeColor = (defaultEdgeColor or {}) if isinstance(defaultEdgeColor, dict): for k, v in internal_defaultEdgeColor.iteritems(): if k not in defaultEdgeColor: defaultEdgeColor[k] = v nodeSizes = (nodeSizes or {}) if defaultNodeSize is None: defaultNodeSize = {} if isinstance(defaultNodeSize, dict): for k, v in internal_defaultNodeSize.iteritems(): if k not in defaultNodeSize: defaultNodeSize[k] = v edgeWidths = (edgeWidths or {}) if defaultEdgeWidth is None: defaultEdgeWidth = {} if isinstance(defaultEdgeWidth, dict): for k, v in internal_defaultEdgeWidth.iteritems(): if k not in defaultEdgeWidth: defaultEdgeWidth[k] = v nodeEdgeWidths = (nodeEdgeWidths or {}) nodeLabels = (nodeLabels or {}) labelPositions = (labelPositions or {}) edgeLabels = (edgeLabels or {}) nodePlotOrders = (nodePlotOrders or {}) edgePlotOrders = (edgePlotOrders or {}) if margin < 0: margin = 0.0 # Initialize dictionary where the returned plotted artist objects will be collected. obj = dict() # # AUXILIARY FUNCTIONS # def scaled(scaling_type, value, value_limits, final_limits): def lin_scaling(value, value_limits, final_limits): value_span = value_limits[1] - value_limits[0] final_span = final_limits[1] - final_limits[0] if final_span == 0: return final_limits[0] if value_span == 0: p = 0.5 else: p = float(value - value_limits[0]) / value_span return final_limits[0] + p * final_span if value <= value_limits[0]: return final_limits[0] if value >= value_limits[1]: return final_limits[1] if scaling_type == 'log' or scaling_type == 'logarithmic': return lin_scaling(np.log(value), np.log(value_limits), final_limits) else: return lin_scaling(value, value_limits, final_limits) def determine_size(scheme, i, net, values, limits, defaults): if not isinstance(scheme, dict): return scheme else: # Determine what defines the size. Calculate the limits # for this property if not yet done. size_by = scheme.get('by', defaults['by']) if size_by not in limits: property_name = "".join(size_by.split(':')[1:]) np_ = sorted(net.nodeProperty[property_name].values()) limits[size_by] = (np_[0], np_[-1]) if size_by not in values: property_name = "".join(size_by.split(':')[1:]) values[size_by] = net.nodeProperty[property_name][i] scale = scheme.get('scale', defaults['scale']) val_min = scheme.get('min', limits[size_by][0]) val_max = scheme.get('max', limits[size_by][1]) size_min = scheme.get('min_size', defaults['min_size']) size_max = scheme.get('max_size', defaults['max_size']) #print size_by, scale, val_min, val_max, size_min, size_max return scaled(scale, values[size_by], [val_min, val_max], [size_min, size_max]) def determine_color(scheme, i, net, values, limits, defaults): if not isinstance(scheme, dict): return scheme else: color_by = scheme.get('by', defaults['by']) if color_by not in limits: property_name = "".join(color_by.split(':')[1:]) np_ = sorted(net.nodeProperty[property_name].values()) limits[color_by] = (np_[0], np_[-1]) if color_by not in values: property_name = "".join(color_by.split(':')[1:]) values[color_by] = net.nodeProperty[property_name][i] scale = scheme.get('scale', defaults['scale']) cmap = scheme.get('cmap', defaults['cmap']) val_min = scheme.get('min', limits[color_by][0]) val_max = scheme.get('max', limits[color_by][1]) cval = scaled(scale, values[color_by], [val_min, val_max], [0.0, 1.0]) cm = setColorMap(cmap) return cm(float(cval)) def luminance(c): """Return luminance of color `c`.""" c_vec = matplotlib.colors.colorConverter.to_rgb(c) return 0.2126 * c_vec[0] + 0.7152 * c_vec[1] + 0.0722 * c_vec[2] def edge_label_pos(axes, xcoords, ycoords, edge_width, label_size, offset=1.5): """Return the baseline position and label rotation (in angles) for an edge label. The label will be on the right side of the edge, in proper orientation for reading, and located `offset` points from the edge. """ theta = get_edge_angle(xcoords, ycoords) if theta > -np.pi / 2 and theta < np.pi / 2: # Edge goes from left to right. label_rotation = theta else: # Edge goes from right to left. label_rotation = theta - np.pi offset_points = offset + 0.5 * edge_width + 0.5 * label_size label_position = (0.5 * sum(xcoords), 0.5 * sum(ycoords)) offset_dir = theta - np.pi / 2 label_offset = (offset_points * np.cos(offset_dir), offset_points * np.sin(offset_dir)) return label_position, label_offset, 180 * label_rotation / np.pi # # INITIALIZE SOME DATA STRUCTURES # # Find out the minimum and maximum value for strength and degree. strengths = netext.strengths(net) smin, smax = min(strengths.values()), max(strengths.values()) degrees = netext.deg(net) dmin, dmax = min(degrees.values()), max(degrees.values()) limits = {"strength": (smin, smax), "degree": (dmin, dmax)} # # INITIALIZE AXES SIZE # node_diameters = {} for nodeIndex in net: values = { "strength": strengths[nodeIndex], "degree": degrees[nodeIndex] } node_diameters[nodeIndex] = ( determine_size(nodeSizes.get(nodeIndex, defaultNodeSize), nodeIndex, net, values, limits, defaultNodeSize) + determine_size(nodeEdgeWidths.get( nodeIndex, defaultNodeEdgeWidth), nodeIndex, net, values, limits, defaultNodeEdgeWidth)) if scaling: # Make axis equal making sure the nodes on the edges are not # clipped. We cannot use `axis('equal')` because nothing has been # drawn yet, but we still need to do this so the arrows will be # draw properly in the plotting phase. This is a bit tricky # because the axes might not be square. max_node_diameter = max(node_diameters.values()) y_coords = sorted(map(operator.itemgetter(1), coords.values())) x_coords = sorted(map(operator.itemgetter(0), coords.values())) ax_pos = axes.get_position() x_span = x_coords[-1] - x_coords[0] y_span = y_coords[-1] - y_coords[0] ax_width_inches = ax_pos.width * axes.get_figure().get_figwidth() ax_height_inches = ax_pos.height * axes.get_figure().get_figheight() if (x_span * ax_height_inches > y_span * ax_width_inches): # The x-span dictates the coordinates. Calculate the margin # necessary to fit in the nodes on the edges. rad_frac = 0.5 * max_node_diameter / (72 * ax_width_inches) x_margin = x_span * rad_frac / (1 - 2 * rad_frac) x_min, x_max = x_coords[0] - x_margin, x_coords[-1] + x_margin y_mid = 0.5 * (y_coords[-1] + y_coords[0]) y_axis_span = (x_max - x_min) * ax_height_inches / ax_width_inches y_min, y_max = y_mid - 0.5 * y_axis_span, y_mid + 0.5 * y_axis_span, else: # The y-span dictates the coordinates. Calculate the margin # necessary to fit in the nodes on the edges. rad_frac = 0.5 * max_node_diameter / (72 * ax_height_inches) y_margin = y_span * rad_frac / (1 - 2 * rad_frac) y_min, y_max = y_coords[0] - y_margin, y_coords[-1] + y_margin x_mid = 0.5 * (x_coords[-1] + x_coords[0]) x_axis_span = (y_max - y_min) * ax_width_inches / ax_height_inches x_min, x_max = x_mid - 0.5 * x_axis_span, x_mid + 0.5 * x_axis_span, y_span, x_span = y_max - y_min, x_max - x_min axes.set_ylim(ymin=y_min - margin * y_span, ymax=y_max + margin * y_span) axes.set_xlim(xmin=x_min - margin * x_span, xmax=x_max + margin * x_span) prev_autoscale = axes.get_autoscale_on() axes.set_autoscale_on(False) point_trans = lambda x_: points_to_data( ax, x_) # Transform points to data coordinates. # # DRAW EDGES # edges = list(net.edges) if edges: # Sort by edge weight. edges.sort(key=operator.itemgetter(2)) limits['weight'] = (edges[0][2], edges[-1][2]) # DEBUGGING: Print statistics of edge weights. #import data_utils #weights_ = map(operator.itemgetter(2), edges) #print "Edges:", limits['weight'], " 10/25/50/75/90:", #mp_ = len(edges)/2 #print "%d, %d, %d, %d, %d" % (int(data_utils.percentile(weights_, 0.1)), # int(data_utils.percentile(weights_, 0.25)), # int(data_utils.percentile(weights_, 0.5)), # int(data_utils.percentile(weights_, 0.75)), # int(data_utils.percentile(weights_, 0.9))) net_edges = NetEdges(axes, net.isSymmetric()) for i, j, w in edges: values = { "weight": w, "strength": strengths[j], "degree": degrees[j] } # Determine edge width. if (i, j) in edgeWidths: width = determine_size(edgeWidths[(i, j)], (i, j), net, values, limits, defaultEdgeWidth) elif (j, i) in edgeWidths: width = determine_size(edgeWidths[(j, i)], (j, i), net, values, limits, defaultEdgeWidth) else: width = determine_size(defaultEdgeWidth, (i, j), net, values, limits, defaultEdgeWidth) # Determine edge color. if (i, j) in edgeColors: color = determine_color(edgeColors[(i, j)], (i, j), net, values, limits, defaultEdgeColor) elif (j, i) in edgeColors: color = determine_color(edgeColors[(j, i)], (j, i), net, values, limits, defaultEdgeColor) else: color = determine_color(defaultEdgeColor, (j, i), net, values, limits, defaultEdgeColor) if (i, j) in edgePlotOrders: zorder = edgePlotOrders[(i, j)] elif (j, i) in edgePlotOrders: zorder = edgePlotOrders[(j, i)] else: zorder = defaultEdgePlotOrder # FOR DEBUGGING: #print "Edge (%d,%d / %.2f) : %.1f %s %f" % (i,j,w,width,str(color),zorder) xcoords, ycoords = (coords[i][0], coords[j][0]), (coords[i][1], coords[j][1]) #obj[(i,j)] = draw_edge(axes, xcoords, ycoords, width, color, # net.isSymmetric(), zorder, node_diameters[j]) net_edges.add(xcoords, ycoords, width, color, zorder, node_diameters[j]) # Add edge label. if (labelAllEdges or (i, j) in edgeLabels or (net.isSymmetric() and (j, i) in edgeLabels)): if (i, j) in edgeLabels: label = str(edgeLabels[(i, j)]) elif (net.isSymmetric() and (j, i) in edgeLabels): label = str(edgeLabels[(j, i)]) else: label = "(%d,%d)" % (i, j) lpos, loffset, lrot = edge_label_pos(axes, xcoords, ycoords, width, edge_label_font_size) axes.annotate(label, lpos, xytext=loffset, textcoords='offset points', color=edge_label_font_color, size=edge_label_font_size, horizontalalignment='center', verticalalignment='center', rotation=lrot, zorder=zorder + 0.5) # # DRAW NODES # max_node_diameter = 0 net_nodes = NetNodes(axes) node_internal_color = {} for nodeIndex in net: values = { "strength": strengths[nodeIndex], "degree": degrees[nodeIndex] } # Determine node shape. shape = nodeShapes.get(nodeIndex, defaultNodeShape) # Determine node size (and update max size). size = determine_size(nodeSizes.get(nodeIndex, defaultNodeSize), nodeIndex, net, values, limits, defaultNodeSize) # Determine node edge width. edgewidth = determine_size( nodeEdgeWidths.get(nodeIndex, defaultNodeEdgeWidth), nodeIndex, net, values, limits, defaultNodeEdgeWidth) max_node_diameter = max(max_node_diameter, size + edgewidth) # Determine node color color = determine_color(nodeColors.get(nodeIndex, defaultNodeColor), nodeIndex, net, values, limits, defaultNodeColor) node_internal_color[nodeIndex] = color # Determine node edge color edgecolor = determine_color( nodeEdgeColors.get(nodeIndex, defaultNodeEdgeColor), nodeIndex, net, values, limits, defaultNodeEdgeColor) # Determine z-order. zorder = nodePlotOrders.get(nodeIndex, defaultNodePlotOrder) # FOR DEBUGGING: #print "Node %d : %f %s %f %s" % (nodeIndex, size, str(color), edgewidth, str(edgecolor)) #obj[nodeIndex] = draw_node(axes, coords[nodeIndex][0], coords[nodeIndex][1], # shape, color, size, edgecolor, edgewidth, zorder) net_nodes.add(coords[nodeIndex][0], coords[nodeIndex][1], color, size, edgecolor, edgewidth, zorder) # Add node label. if nodeIndex in nodeLabels or labelAllNodes: if nodeIndex in nodeLabels: label = str(nodeLabels[nodeIndex]) else: label = str(nodeIndex) label_pos = labelPositions.get(nodeIndex, defaultLabelPosition) if label_pos == 'out': nodeLabel_offset = int(np.ceil(float(size) / 2)) + 1 axes.annotate(label, (coords[nodeIndex][0], coords[nodeIndex][1]), textcoords='offset points', xytext=(nodeLabel_offset, nodeLabel_offset), color=node_label_font_color, size=node_label_font_size, zorder=zorder + 0.5) elif label_pos == 'in': axes.annotate( label, (coords[nodeIndex][0], coords[nodeIndex][1]), color=("black" if luminance(node_internal_color[nodeIndex]) > 0.5 else "white"), size=max(5, min(size - 1, 0.7 * size)), horizontalalignment='center', verticalalignment='center', zorder=zorder + 0.5) # Remove frame. if not frame: # Using 'axes.set_axis_off()' would also turn of the axis # labels, which is too much. The following lines are required # to turn off the frame and tick labels while keeping axis # labels. axes.set_frame_on(False) axes.set_xticklabels([]) axes.xaxis.set_ticks_position('none') axes.set_yticklabels([]) axes.yaxis.set_ticks_position('none') # Return autoscaling to the original value. axes.set_autoscale_on(prev_autoscale) # Return figure (or objects drawn). return (obj if animated else axes.get_figure())
def getNodeColors(net, colorwith="strength", useColorMap="orange", parentnet=[]): """Returns a dictionary {node:color}. The colors are set based on either node strengh (colorwith="strength", default) or any nodeProperty. For cases where e.g. nodes which have been thresholded out (k=0), the input parameter parentnet can be used - parentnet should contain the original network *before* thresholding, i.e. containing all original nodes and their attributes. IF parentnet is given, i) if strength is used, its nodes which are NOT in net colored gray, ii) if properties are used, its nodes are colored similarly to those nodes in net. Also the dictionary which is returned contains then all nodes in parentnet""" myNodeColors = setColorMap(useColorMap) nodeColors = {} if colorwith == "strength": if hasattr(net, 'matrixtype'): if net.matrixtype == 0: net = transforms.dist_to_weights(net) strengths = netext.strengths(net) max_value = max(strengths.values()) min_value = min(strengths.values()) if len(parentnet ) > 0: # if we want the dict to include nodes not in net for node in parentnet: if node in net: # if the node is in net, use its strength for color nodeColors[node] = setColor(strengths[node], (min_value, max_value), myNodeColors) else: # otherwise color it gray nodeColors[node] = (0.5, 0.5, 0.5) else: for node in net: # if parentnet not given, just color nodes by strength nodeColors[node] = setColor(strengths[node], (min_value, max_value), myNodeColors) else: numeric_props = netext.getNumericProperties(net) # first check if colorwith is a numeric property if colorwith in numeric_props: values = [] if len(parentnet ) > 0: # again if we want to include nodes not in net for node in parentnet: # first get min and max value of property values.append(parentnet.nodeProperty[colorwith][node]) min_value = min(values) max_value = max(values) for node in parentnet: # then set colors according to property nodeColors[node] = setColor( parentnet.nodeProperty[colorwith][node], (min_value, max_value), myNodeColors) else: # otherwise do the above for nodes in net for node in net: values.append(net.nodeProperty[colorwith][node]) min_value = min(values) max_value = max(values) for node in net: nodeColors[node] = setColor( net.nodeProperty[colorwith][node], (min_value, max_value), myNodeColors) else: # colorwith is not a numeric property, so look up unique values # and give them integer numbers values = {} # empty dict for values if len(parentnet) > 0: # if there are nodes not in net props = list(set(parentnet.nodeProperty[colorwith].values())) else: props = list(set(net.nodeProperty[colorwith].values())) #Check if properties can be converted to colors: if isListOfColors(props): propToColor = {} cc = matplotlib.colors.ColorConverter() for p in props: propToColor[p] = cc.to_rgb(p) if len(parentnet) > 0: for node in parentnet: nodeColors[node] = propToColor[ parentnet.nodeProperty[colorwith][node]] else: for node in net: nodeColors[node] = propToColor[ parentnet.nodeProperty[colorwith][node]] else: for i, prop in enumerate(props): values[prop] = i + 1 # now all property strings have a numerical value min_value = 1 max_value = max(values.values()) if len(parentnet) > 0: for node in parentnet: nodeColors[node] = setColor( values[parentnet.nodeProperty[colorwith][node]], (min_value, max_value), myNodeColors) else: for node in net: nodeColors[node] = setColor( values[net.nodeProperty[colorwith][node]], (min_value, max_value), myNodeColors) if len( nodeColors ) == 0: # finally if for whatever reason no nodes were colored, just set them gray if len(parentnet) > 0: for node in parentnet: nodeColors[node] = (0.5, 0.5, 0.5) else: for node in net: nodeColors[node] = (0.5, 0.5, 0.5) return nodeColors