def draw(G, pos=None, **kwargs): """ Draw the graph G using hvPlot. Draw the graph with hvPlot with options for node positions, labeling, titles, and many other drawing features. Parameters ---------- G : graph A networkx graph pos : dictionary, optional A dictionary with nodes as keys and positions as values. If not specified a spring layout positioning will be computed. See :py:mod:`networkx.drawing.layout` for functions that compute node positions. arrows : bool, optional (default=True) For directed graphs, if True draw arrowheads. Note: Arrows will be the same color as edges. arrowhead_length : float, optional (default=0.025) The length of the arrows as fraction of the overall extent of the graph with_labels : bool, optional (default=True) Set to True to draw labels on the nodes. nodelist : list, optional (default G.nodes()) Draw only specified nodes edgelist : list, optional (default=G.edges()) Draw only specified edges node_size : scalar or array, optional (default=300) Size of nodes. If an array is specified it must be the same length as nodelist. node_color : color string, node attribute, or array of floats, (default='r') Can be a single color, the name of an attribute on the nodes or sequence of colors with the same length as nodelist. If the node_color references an attribute on the nodes or is a list of values they will be colormapped using the cmap and vmin, vmax parameters. node_shape : string, optional (default='o') The shape of the node. Specification is as valid bokeh marker. alpha : float, optional (default=1.0) The node and edge transparency cmap : Colormap, optional (default=None) Colormap for mapping intensities of nodes vmin,vmax : float, optional (default=None) Minimum and maximum for node colormap scaling linewidths : [None | scalar | sequence] Line width of symbol border (default =1.0) edge_width : float, optional (default=1.0) Line width of edges edge_color : color string, or array of floats (default='r') Can be a single color, the name of an attribute on the edges or sequence of colors with the same length as the edges. If the edge_color references an attribute on the edges or is a list of values they will be colormapped using the edge_cmap and edge_vmin, edge_vmax parameters. edge_cmap : Matplotlib colormap, optional (default=None) Colormap for mapping intensities of edges edge_vmin,edge_vmax : floats, optional (default=None) Minimum and maximum for edge colormap scaling style : string, optional (default='solid') Edge line style (solid|dashed|dotted,dashdot) labels : dictionary or string, optional (default=None) Node labels in a dictionary keyed by node of text labels or a string referencing a node attribute font_size : int, optional (default=12) Font size for text labels font_color : string, optional (default='black') Font color string font_family : string, optional (default='sans-serif') Font family label : string, optional Label for graph legend selection_policy : string, optional (default='nodes') Whether to select 'nodes', 'edges' or None on tap and selection events. inspection_policy : string, optional (default='nodes') Whether to select 'nodes', 'edges' or None on tap and selection events. geo : boolean, optional (default=False) Whether to return a GeoViews graph crs : cartopy.crs.CRS A cartopy coordinate reference system (enables a geographic plot) height : int, optional (default=400) The height of the plot in pixels width : int, optional (default=400) The width of the plot in pixels """ if pos is None: pos = nx.drawing.spring_layout if not isinstance(pos, dict): pos = pos(G, **kwargs.get('layout_kwargs', {})) params, label_params = {}, {} label_element = Labels if kwargs.get('geo', False) or 'crs' in kwargs: try: import geoviews except ImportError: raise ImportError('In order to use geo-related features ' 'the geoviews library must be available. ' 'It can be installed with:\n conda ' 'install -c pyviz geoviews') crs = process_crs(kwargs.get('crs')) label_element = geoviews.Labels params['cls'] = geoviews.Graph params['crs'] = crs label_params['crs'] = crs # Construct Graph object g = _from_networkx(G, pos, **params) if 'nodelist' in kwargs: g.nodes.data = g.nodes.data.iloc[list(kwargs['nodelist'])] if 'edgelist' in kwargs: edges = g.array([0, 1]) comparisons = [] for edge in kwargs['edgelist']: comparisons.append(edges == edge) if len(comparisons): selector = np.logical_and(*np.logical_or.reduce(comparisons).T) g = g.iloc[selector] else: g = g.iloc[:0] # Compute options inspection_policy = kwargs.pop('inspection_policy', 'nodes') opts = dict( axiswise=True, arrowhead_length=kwargs.get('arrowhead_length', 0.025), directed=kwargs.pop('arrows', isinstance(G, nx.DiGraph)), colorbar=kwargs.pop('colorbar', False), padding=kwargs.get('padding', 0.1), width=kwargs.pop('width', 400), height=kwargs.pop('height', 400), selection_policy=kwargs.pop('selection_policy', 'nodes'), inspection_policy=inspection_policy, node_fill_color='red') if '_axis_defaults': opts.update(xaxis=None, yaxis=None, show_frame=False) opts.update({k: kwargs.pop(k) for k in list(kwargs) if k in GraphPlot.style_opts}) if 'node_size' in opts: if isinstance(opts['node_size'], str): opts['node_size'] = dim(opts['node_size']) opts['node_size'] = np.sqrt(opts['node_size']) if 'node_color' in opts: opts['node_fill_color'] = opts.pop('node_color') if 'edge_color' in opts: opts['edge_line_color'] = opts.pop('edge_color') if 'node_shape' in kwargs: marker = kwargs.pop('node_shape') if marker in markers: marker_opts = markers[marker] marker = marker_opts['marker'] if 'angle' in marker_opts: Store.add_style_opts(Graph, ['node_angle'], 'bokeh') opts['node_angle'] = marker_opts['angle'] opts['node_marker'] = marker if 'alpha' in kwargs: alpha = kwargs.pop('alpha') opts['node_alpha'] = alpha opts['edge_alpha'] = alpha if 'linewidths' in kwargs: opts['node_line_width'] = kwargs.pop('linewidths') if 'edge_width' in kwargs: opts['edge_line_width'] = kwargs.pop('edge_width') if 'style' in kwargs: opts['edge_line_dash'] = kwargs.pop('style') node_styles = ('node_fill_color', 'node_size', 'node_alpha', 'node_line_width') for node_style in node_styles: if isinstance(opts.get(node_style), (np.ndarray, list, range)): g = g.clone((g.data, g.nodes.add_dimension(node_style, len(g.nodes.vdims), opts[node_style], True))) opts[node_style] = node_style edge_styles = ('edge_line_color', 'edge_line_alpha', 'edge_alpha', 'edge_line_width') for edge_style in edge_styles: if isinstance(opts.get(edge_style), (np.ndarray, list, range)): g = g.add_dimension(edge_style, len(g.vdims), opts[edge_style], True) opts[edge_style] = edge_style if opts.get('node_fill_color') in g.nodes.dimensions(): lims = (kwargs.get('vmin', None), kwargs.get('vmax', None)) if lims != (None, None): dimension = g.nodes.get_dimension(opts.get('node_fill_color')) dimension.range = lims if opts.get('edge_line_color') in g.dimensions(): lims = (kwargs.get('edge_vmin', None), kwargs.get('edge_vmax', None)) if lims != (None, None): dimension = g.get_dimension(opts.get('edge_line_color')) dimension.range = lims if inspection_policy == 'nodes': tooltip_dims = [(d.label, 'index_hover' if d in g.nodes.kdims else d.name) for d in g.nodes.kdims[2:] + g.nodes.vdims] else: tooltip_dims = [(d.label, d.name+'_values' if d in g.kdims else d.name) for d in g.kdims + g.vdims] tooltips = [(label, '@{%s}' % dimension_sanitizer(name)) for label, name in tooltip_dims if name not in node_styles + edge_styles] opts['tools'] = [HoverTool(tooltips=tooltips), 'tap'] g.opts(**opts) # Construct Labels if kwargs.get('with_labels', kwargs.get('labels', False)): label_opts = {k: kwargs.pop(k) for k in list(kwargs) if k in LabelsPlot.style_opts} if 'xoffset' in kwargs: label_opts['xoffset'] = kwargs.pop('xoffset') if 'yoffset' in kwargs: label_opts['yoffset'] = kwargs.pop('yoffset') if 'font_size' in kwargs: label_opts['text_font_size'] = kwargs.pop('font_size') if 'font_color' in kwargs: label_opts['text_color'] = kwargs.pop('font_color') if 'font_family' in kwargs: label_opts['text_font'] = kwargs.pop('font_family') labels = kwargs.get('labels', g.nodes.kdims[2]) if isinstance(labels, dict): values = g.nodes.array(g.nodes.kdims) data = [(x, y, labels[i]) for (x, y, i) in values if i in labels] labels = label_element(data, g.nodes.kdims[:2], 'text', **label_params) else: labels = label_element(g.nodes, g.nodes.kdims[:2], labels, **label_params) g = g * labels.opts(**label_opts) # Apply label if 'label' in kwargs: g = g.relabel(kwargs.pop('label')) return g