def _nodes(node_positions, info_df=None): """Returns a Nodes object from a networkx graph or a list of node positions.""" if isinstance(node_positions, dict): indices = sorted(np.array(list(node_positions.keys()))) node_positions = np.array(list(node_positions.values()))[indices] info = _node_info(node_positions, info_df) kdims = ["x", "y", "index"] vdims = list(info.columns.drop(kdims)) return hv.Nodes(info, kdims=kdims, vdims=vdims)
def get_graph_from_data(node_and_edges_data): node_data = node_and_edges_data['node_data'] source_edges = node_and_edges_data['source_edges'] target_edges = node_and_edges_data['target_edges'] node_data['minus_mean_deviation'] = -node_data['mean_deviation'] nodes = hv.Nodes(data=node_data) tooltips = [('Samples', '@samples'), ('Mean Deviation', '@mean_deviation'), ('Index', '@index'), ('Partition', '@partition')] hover = HoverTool(tooltips = tooltips) # add labels to nodes labels = hv.Labels(nodes, ['x', 'y'], 'index') graph = hv.Graph(((source_edges, target_edges), nodes)).opts( node_color='mean_deviation', cmap='viridis', node_size = 'node_sizes', tools=[hover], hooks=[hook_graph], height = 600, responsive = True, xaxis = None, yaxis=None) # add text to the right of the graph indicating the quartiles xpos = np.max(node_data['x']) ypos = list(set(node_data['y'])) ypos.sort() quartile_texts = ['All', 'Lower Quartile', '2nd Quartile', '3rd Quartile', 'Higher Quartile '] labels_quartiles = hv.Labels({'x' : xpos, 'y' : ypos, 'text' : quartile_texts }, ['x','y'], 'text') labels_quartiles.opts(xoffset = 1, align='start') # TODO: append the quartile texts to the plot final_graph = graph * labels #final_graph.opts( # opts.Labels(text_color='y', cmap='BrBG', color_levels=5)) return final_graph
def _make_progress(self): import holoviews as hv import holoviews.plotting.bokeh # noqa if self._graph: root = get_root(self._graph) depth = get_depth(root, self._graph) breadths = get_breadths(root, self._graph) max_breadth = max(len(v) for v in breadths.values()) else: root = None max_breadth, depth = 0, 0 breadths = {} height = 80 + (max_breadth - 1) * 20 edges = [] for src, tgts in self._graph.items(): for t in tgts: edges.append((src, t)) nodes = [] for depth, subnodes in breadths.items(): breadth = len(subnodes) step = 1. / breadth for i, n in enumerate(subnodes[::-1]): if n == self._stage: state = 'active' elif n == self._error: state = 'error' elif n == self._next_stage: state = 'next' else: state = 'inactive' nodes.append((depth, step / 2. + i * step, n, state)) cmap = { 'inactive': 'white', 'active': '#5cb85c', 'error': 'red', 'next': 'yellow' } def tap_renderer(plot, element): from bokeh.models import TapTool gr = plot.handles['glyph_renderer'] tap = plot.state.select_one(TapTool) tap.renderers = [gr] nodes = hv.Nodes(nodes, ['x', 'y', 'Stage'], 'State').opts(alpha=0, default_tools=['tap'], hooks=[tap_renderer], hover_alpha=0, selection_alpha=0, nonselection_alpha=0, axiswise=True, size=10, backend='bokeh') self._progress_sel.source = nodes graph = hv.Graph((edges, nodes)).opts(edge_hover_line_color='black', node_color='State', cmap=cmap, tools=[], default_tools=['hover'], selection_policy=None, node_hover_fill_color='gray', axiswise=True, backend='bokeh') labels = hv.Labels(nodes, ['x', 'y'], 'Stage').opts(yoffset=-.30, default_tools=[], axiswise=True, backend='bokeh') plot = (graph * labels * nodes) if self._linear else (graph * nodes) plot.opts(xaxis=None, yaxis=None, min_width=400, responsive=True, show_frame=False, height=height, xlim=(-0.25, depth + 0.25), ylim=(0, 1), default_tools=['hover'], toolbar=None, backend='bokeh') return plot
def tag_relation_net(tag_df, name=None, kind='coocc', layout=nx.spring_layout, layout_kws=None, padding=None, **node_adj_kws): """ Explore tag relationships by create a Holoviews Graph Element. Nodes are tags (colored by classification), and edges occur only when those tags happen together. Parameters ---------- tag_df : pandas.DataFrame standard Nestor tag occurrence matrix. Multi-column with top-level containing tag classifications (named-entity NE) and 2nd level containing tags. Each row corresponds to a single event (MWO), with binary indicators (1-occurs, 0-does not). name : str what to name this tag relation element. Creates a Holoviews group "name". kind : str coocc : co-occurrence graph, where tags are connected if they occur in the same MWO, above the value calculated for pct_thres. Connects all types together. sankey : Directed "flow" graph, currently implemented with a (P) -> (I) -> (S) structure. Will require ``dag=True``. Alters default to ``similarity=count`` layout : object (function), optional must take a graph object as input and output 2D coordinates for node locations (e.g. all networkx.layout functions). Defaults to ``networkx.spring_layout`` layout_kws : dict, optional options to pass to networkx layout functions padding : dict, optional contains "x" and "y" specifications for boundaries. Defaults: ``{'x':(-0.05, 1.05), 'y':(-0.05, 1.05)}`` Only valid if ``kind`` is 'coocc'. node_adj_kws : keyword arguments for ``nestor.tagtrees.tag_df_network``. Valid options are similarity : 'cosine' (default) or 'count' dag : bool, default='False', (True if ``kind='sankey'``) pct_thres : : int or None If int, between [0,100]. The lower percentile at which to threshold edges/adjacency. Returns ------- graph: holoviews.Holomap or holoviews.Graph element, pending sankey or cooccurrence input. """ try: import nestor.tagtrees except ImportError: print( 'The tag-relation network requires the use of our trees module! Import failed!' ) raise if name is None: name = 'Tag Net' adj_params = { 'similarity': 'cosine', } graph_types = { 'coocc': hv.Graph, 'sankey': hv.Sankey, } if kind is 'sankey': if node_adj_kws.get('dag', True) is False: import warnings warnings.warn( 'Sankey cannot be plotted with a co-occurrence net! Changing to DAG...' ) adj_params['similarity'] = 'count' adj_params.update(node_adj_kws) adj_params['dag'] = True else: assert kind is 'coocc', 'You have passed an invalid graph type!' adj_params.update(node_adj_kws) G, node_info, edge_info = nestor.tagtrees.tag_df_network( tag_df[['I', 'P', 'S']], **adj_params) pos = pd.DataFrame(layout(G)).T.rename(columns={0: 'x', 1: 'y'}) node_info = node_info.join(pos).reset_index().rename( columns={'index': 'tag'}) nodes = hv.Nodes(node_info, kdims=['x', 'y', 'tag'], vdims=['NE', 'count']) # nodes = nodes.sort('NE').options(color_index='NE', cmap=opts, size='size') graph = graph_types[kind]((edge_info, nodes), group=name, vdims='weight') ops = { 'color_index': 'NE', 'cmap': color_opts, 'edge_color_index': 'weight', 'edge_cmap': 'blues', # 'node_size' : 'count', # wait for HoloViews `op()` functionality! } graph = graph.options(**ops) if kind is 'sankey': return graph else: text = hv.Labels(node_info, ['x', 'y'], 'tag', group=name).options(text_font_size='8pt', xoffset=0.015, yoffset=-0.015, text_align='left') if padding is None: padding = dict(x=(-1.05, 1.05), y=(-1.05, 1.05)) return (graph * text).redim.range(**padding)
# Read in edge data edges_df = pd.read_pickle(INPUT_EDGES_DF) # Convert corporation ID to node index edges_df['source'] = edges_df['source'].map(unique_to_idx) edges_df['target'] = edges_df['target'].map(unique_to_idx) # Color each edge according to its nodes edges_df['color'] = edges_df.apply(get_edge_color, axis=1) #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# # Convert edge and node DataFrames into Holoviews graph, define tooltips #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# # Convert node DataFrame to HoloViews object hv_nodes = hv.Nodes(nodes_df) # Create HoloViews Graph object from nodes and edges, with x and y limits # bounded by `GRAPH_EXTENTS` hv_graph = hv.Graph((edges_df, hv_nodes), ) # Define custom hover tooltip hover = HoverTool(tooltips=[ ('Officer Name', '@FullName'), ('ID', '@IdNumber'), ('Company 1', '@Company1'), ('Company 2', '@Company2'), ('Company 3', '@Company3'), ]) #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
edf = pd.DataFrame(el) # make sure there aren't any edges that go to a nonexistant node edf = edf[((edf['start'].isin(ndf['user index'])) & (edf['stop'].isin(ndf['user index'])))] # create graph and save #----------------------------------------------------------------------------# # initialize default args for Holoviews kwargs = dict(width=600, height=600, xaxis=None, yaxis=None) opts.defaults(opts.Nodes(**kwargs), opts.Graph(**kwargs)) # construct Holoviews graph with Bokeh backend hv_nodes = hv.Nodes(ndf).sort() hv_graph = hv.Graph((edf, hv_nodes)) hv_graph.opts(node_color='log degree', node_size=10, edge_line_width=1, node_line_color='gray', edge_hover_line_color='#DF0000') # bundle edges for aestheticss bundled = bundle_graph(hv_graph) # save html of interactive visualizations renderer.save(bundled, 'ff_reaction_graph_bundled') renderer.save(hv_graph, 'ff_reaction_graph') #----------------------------------------------------------------------------#
# convert `source` and `target` columns to str datatype edges_df['source'] = edges_df['source'].astype(str) edges_df['target'] = edges_df['target'].astype(str) # use natural logarithm of edge weight, for visualization purposes edges_df['weight'] = np.log(edges_df['weight'].astype(float)) # scale edge weight for visualization purposes edges_df['weight'] /= EDGE_SCALING # 4. generate visualization using HoloViews package ############################################################################# # convert node DataFrame to HoloViews object hv_nodes = hv.Nodes(nodes_df).sort() # create HoloViews Graph object from nodes and edges, with x and y limits # bounded by `GRAPH_EXTENTS` hv_graph = hv.Graph((edges_df, hv_nodes), extents=GRAPH_EXTENTS) # define custom hover tooltip hover = HoverTool(tooltips=[ ("member id", "@member_id"), ("name", "@name"), ("posts", "@posts"), ("messages", "@messages"), ]) # specify parameters for visualization hv_graph.opts(node_radius='size',
graph.opts(cmap='Category20', edge_cmap='Category20', node_size=10, edge_line_width=1, node_color=dim('Id').str(), edge_color=dim('Source').str()) hv.save(graph, 'coloured_chord.html') # Facebook data as graph with predifined coordinate system kwargs = dict(width=300, height=300, xaxis=None, yaxis=None) opts.defaults(opts.Nodes(**kwargs), opts.Graph(**kwargs)) colors = ['#000000'] + hv.Cycle('Category20').values edges_df = pd.read_csv('data/fb_edges.csv') fb_nodes = hv.Nodes(pd.read_csv('data/fb_nodes.csv')).sort() fb_graph = hv.Graph((edges_df, fb_nodes), label='Facebook Circles') fb_graph.opts(cmap=colors, node_size=10, edge_line_width=1, node_line_color='gray', node_color='circle') hv.save(fb_graph, 'fb_graph.html') # Bundled graph of facebook data from holoviews.operation.datashader import datashade, bundle_graph bundled = bundle_graph(fb_graph) hv.save(bundled, 'fb_bundled.html')
def plot_subgraph(csv_path, rel_name): global edges_plot global nodes_plot global node_type_size_dict global labels with open(csv_path, 'r') as w: data = pd.read_csv(w) if not (os.path.exists(f'./{rel_name}')): os.mkdir(f'./{rel_name}') if not (os.path.exists(f'./{rel_name}/subgraphs')): os.mkdir(f'./{rel_name}/subgraphs') #this is since I have CSV that does not explicitly specify node types data["left"] = data.Edge.apply(lambda a: a.split("-->")[0]) data["right"] = data.Edge.apply(lambda a: a.split("-->")[1]) #get all unique nodes nodes = pd.concat([data.left,data.right],ignore_index=True).drop_duplicates().reset_index(drop=True).to_frame("name").reset_index() data["left_index"] = nodes.set_index("name").loc[data.left,"index"].values data["right_index"] = nodes.set_index("name").loc[data.right,"index"].values #also temporary type should be in the csv nodes["type"] = nodes.name.apply(lambda a: "Chem/Gene" if a in data.left.values else "Disease") # ### Create NetworkX Graph # Make a directed graph from a list of edges. # Also let's compute node layout as well... layout is just position of every node on the canvas graph = nx.DiGraph() graph.add_edges_from(data.loc[:,["left_index","right_index"]].values) layout = nx.layout.fruchterman_reingold_layout(graph.to_undirected(),.5) layout = pd.DataFrame(layout,index=["x","y"]).T.sort_index() nodes = pd.concat([nodes,layout],axis=1) # ## Let's Plot Some Graphs paths = make_paths(nodes,data) hv.extension("bokeh") nodes_plot = hv.Nodes(nodes,kdims=["x","y","index"],vdims=["name","type"]).opts(show_legend=True) edges_plot = hv.Graph((data,nodes_plot,paths),kdims=["left_index","right_index"],vdims=["Original_Weight","Boltzmann_Citation_Weight","Publication_Year_Weight","Publication_Year_and_Citation_Weight", "H_Index_Weight"]) # edges_plot = bundle_graph(edges_plot) labels = hv.Labels(nodes,kdims=["x","y"],vdims=["name"]).opts(text_align="left", text_font_size="8pt",xoffset=.05,text_alpha = .5, text_color="white") weight_field = "Boltzmann_Citation_Weight" weights = ["Original_Weight","Boltzmann_Citation_Weight","Publication_Year_Weight","Publication_Year_and_Citation_Weight", "H_Index_Weight"] # need to change this node_type_size_dict = {"Chem/Gene":15,"Disease":30} out = hv.HoloMap({w: make_plot(w) for w in weights},kdims = "weight_type") print('Saving Subgraphs to file...') hv.save(out,f"./{rel_name}/subgraphs/{rel_name}_subgraph.html") hv.save(out,f"./{rel_name}/subgraphs/{rel_name}_img1.gif") # ![Subgraph](imgs/img1.gif) # We can also see all of them side by side out2 = out.opts(width=600,height=600).layout("weight_type").cols(2) hv.save(out2,f"./{rel_name}/subgraphs/{rel_name}_img2.png") hv.save(out2,f"./{rel_name}/subgraphs/{rel_name}_subgraph_side_by_side.html")
fuzzy_df.shape label_df = pd.read_csv("PRJNA301554.hydroponic.sample_annotations.txt", index_col=0, sep='\t') labels = label_df.astype('object').reset_index() fuzzy_edges = pd.DataFrame(fuzzy_df.stack()).reset_index() fuzzy_edges.columns = ['source', 'target', 'weight'] fuzzy_edges.head(2) cutoff = fuzzy_edges['weight'].quantile(.95) filtered = fuzzy_edges[fuzzy_edges['weight'] > cutoff] print(f'Cutoff: {cutoff:.3}') print(f'Remaining shape: {filtered.shape}') atlas_layout = forceatlas2_layout(labels, fuzzy_edges, iterations=100) hv_opts = {} hv_opts['padding'] = 0.1 hv_opts['width'] = 600 hv_opts['height'] = 400 hv_opts['cmap'] = 'Set1' hv_opts['xaxis'] = None hv_opts['yaxis'] = None hv_opts['size'] = 5 vdims = ['Sample', 'Treatment', 'Genotype', 'Subspecies', 'Time'] hv_nodes = hv.Nodes(atlas_layout, kdims=['x', 'y', 'index'], vdims=vdims) hv_nodes.opts(**hv_opts)