def get_data(self, element, ranges, style): if self.static_source: data = {} else: if self.geographic and element.crs != DEFAULT_PROJ: element = project_shape(element) xs, ys = geom_to_array(element.geom()).T if self.invert_axes: xs, ys = ys, xs data = dict(xs=[xs], ys=[ys]) mapping = dict(self._mapping) dim = element.vdims[0].name if element.vdims else None if element.level is not None: cmap = style.get('palette', style.get('cmap', None)) if cmap and dim: cdim = element.vdims[0] dim_name = util.dimension_sanitizer(cdim.name) cmapper = self._get_colormapper(cdim, element, ranges, style) data[dim_name] = [element.level] mapping['fill_color'] = {'field': dim_name, 'transform': cmapper} if 'hover' in self.tools+self.default_tools: if dim: dim_name = util.dimension_sanitizer(dim) data[dim_name] = [element.level] for k, v in self.overlay_dims.items(): dim = util.dimension_sanitizer(k.name) data[dim] = [v for _ in range(len(xs))] return data, mapping, style
def get_data(self, element, ranges=None, empty=False): geoms = element.geom() if self.geographic and element.crs != DEFAULT_PROJ: try: geoms = DEFAULT_PROJ.project_geometry(geoms, element.crs) except: empty = True xs, ys = ([], []) if empty else geom_to_array(geoms) data = dict(xs=xs, ys=ys) style = self.style[self.cyclic_index] cmap = style.get('palette', style.get('cmap', None)) mapping = dict(self._mapping) dim = element.vdims[0].name if element.vdims else None if cmap and dim and element.level is not None: cdim = element.vdims[0] dim_name = util.dimension_sanitizer(cdim.name) cmapper = self._get_colormapper(cdim, element, ranges, style) data[dim_name] = [] if empty else [ element.level for _ in range(len(xs)) ] mapping['fill_color'] = {'field': dim_name, 'transform': cmapper} if 'hover' in self.tools + self.default_tools: if dim: dim_name = util.dimension_sanitizer(dim) data[dim_name] = [element.level for _ in range(len(xs))] for k, v in self.overlay_dims.items(): dim = util.dimension_sanitizer(k.name) data[dim] = [v for _ in range(len(xs))] return data, mapping
def get_data(self, element, ranges, style): if not self.geographic: return super(GeometryPlot, self).get_data(element, ranges, style) if self.static_source: data = {} else: geoms = element.geom() if element.crs: geoms = DEFAULT_PROJ.project_geometry(geoms, element.crs) xs, ys = geom_to_array(geoms) data = dict(xs=ys, ys=xs) if self.invert_axes else dict(xs=xs, ys=ys) mapping = dict(self._mapping) if element.vdims and getattr(element, 'level', None) is not None: cdim = element.vdims[0] dim_name = util.dimension_sanitizer(cdim.name) data[dim_name] = [element.level for _ in range(len(xs))] cmapper = self._get_colormapper(cdim, element, ranges, style) color_prop = 'fill_color' if isinstance(element, Polygons) else 'line_color' mapping[color_prop] = {'field': dim_name, 'transform': cmapper} if any(isinstance(t, HoverTool) for t in self.state.tools): dim_name = util.dimension_sanitizer(element.vdims[0].name) for k, v in self.overlay_dims.items(): dim = util.dimension_sanitizer(k.name) data[dim] = [v for _ in range(len(xs))] data[dim_name] = [element.level for _ in range(len(xs))] self._get_hover_data(data, element) return data, mapping, style
def _postprocess_hover(self, renderer, source): super(GeoPlot, self)._postprocess_hover(renderer, source) hover = self.handles.get('hover') try: from bokeh.models import CustomJSHover except: CustomJSHover = None if (not self.geographic or None in (hover, CustomJSHover) or isinstance(hover.tooltips, basestring) or self.projection is not GOOGLE_MERCATOR or hover.tooltips is None): return element = self.current_frame xdim, ydim = [dimension_sanitizer(kd.name) for kd in element.kdims] formatters, tooltips = {}, [] xhover = CustomJSHover(code=self._hover_code % 0) yhover = CustomJSHover(code=self._hover_code % 1) for name, formatter in hover.tooltips: customjs = None if formatter in ('@{%s}' % xdim, '$x'): dim = xdim customjs = xhover elif formatter in ('@{%s}' % ydim, '$y'): dim = ydim customjs = yhover if customjs: key = formatter if formatter in ('$x', '$y') else dim formatters[key] = customjs formatter += '{custom}' tooltips.append((name, formatter)) hover.tooltips = tooltips hover.formatters = formatters
def _postprocess_hover(self, renderer, source): super(GeoPlot, self)._postprocess_hover(renderer, source) hover = self.handles.get('hover') try: from bokeh.models import CustomJSHover except: CustomJSHover = None if (not self.geographic or None in (hover, CustomJSHover) or isinstance(hover.tooltips, basestring)): return element = self.current_frame xdim, ydim = [dimension_sanitizer(kd.name) for kd in element.kdims] code = """ var projections = require("core/util/projections"); var x = special_vars.data_x var y = special_vars.data_y var coords = projections.wgs84_mercator.inverse([x, y]) return "" + (coords[%d]).toFixed(4) """ formatters = { xdim: CustomJSHover(formatter=code % 0), ydim: CustomJSHover(formatter=code % 1), } tooltips = [] for name, formatter in hover.tooltips: if formatter in ('@{%s}' % xdim, '@{%s}' % ydim): formatter += '{custom}' tooltips.append((name, formatter)) hover.tooltips = tooltips hover.formatters = formatters
def visits_plot_per_metric(df, x, y, hover_columns=None, filt=0): """ * x: name of the column for x-axis * y: name of the column for y-axis * hover_columns: list of column names for hover information """ from bokeh.models import HoverTool from holoviews.core.util import dimension_sanitizer if hover_columns: _tt = [(n, "@{%s}" % dimension_sanitizer(n)) for n in hover_columns] hover = HoverTool(tooltips=_tt) else: hover = "hover" # 'x' must be renamed for Hv/Pn link axes with equal name/label; # in here, it will cause plots on different filter to have their # x-axis values merged (producing big blank areas in each plot) x_renamed = "visits ({filt})".format(filt=filt) df = df.sort_values(x) df[x_renamed] = df[x].astype(str) curve = hv.Curve(df, x_renamed, y) points = hv.Scatter(df, [x_renamed, y], hover_columns).opts(size=8, line_color="white", tools=[hover, "tap"], toolbar="above") return (curve * points).redim(y=hv.Dimension(y, range=(-1, 1)))
def __init__(self, source, target, **params): if 'vertex_columns' not in params: dimensions = [ dimension_sanitizer(d.name) for d in target.dimensions()[:2] ] params['vertex_columns'] = dimensions super(VertexTableLink, self).__init__(source, target, **params)
def _update_hover(self, element): tooltips, hover_opts = self._hover_opts(element) hover = self.handles['hover'] tooltips = [(ttp.pprint_label, '@{%s}' % dimension_sanitizer(ttp.name)) if isinstance(ttp, Dimension) else ttp for ttp in tooltips] tooltips = [(l, t + '{custom}' if t in hover.formatters else t) for l, t in tooltips] self.handles['hover'].tooltips = tooltips
def _update_hover(self, element): tooltips, hover_opts = self._hover_opts(element) hover = self.handles['hover'] if 'hv_created' in hover.tags: tooltips = [ (ttp.pprint_label, '@{%s}' % dimension_sanitizer(ttp.name)) if isinstance(ttp, Dimension) else ttp for ttp in tooltips ] if self.geographic and tooltips[2:] == hover.tooltips[2:]: return tooltips = [(l, t + '{custom}' if t in hover.formatters else t) for l, t in tooltips] hover.tooltips = tooltips else: super(GeoPlot, self)._update_hover(element)
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