def draw_embedding(G, layout, emb, embedded_graph=None, interaction_edges=None, chain_color=None, unused_color=(0.9, 0.9, 0.9, 1.0), cmap=None, show_labels=False, overlapped_embedding=False, **kwargs): """Draws an embedding onto the graph G, according to layout. If interaction_edges is not None, then only display the couplers in that list. If embedded_graph is not None, the only display the couplers between chains with intended couplings according to embedded_graph. Parameters ---------- G : NetworkX graph The graph to be drawn layout : dict A dict of coordinates associated with each node in G. Should be of the form {node: coordinate, ...}. Coordinates will be treated as vectors, and should all have the same length. emb : dict A dict of chains associated with each node in G. Should be of the form {node: chain, ...}. Chains should be iterables of qubit labels (qubits are nodes in G). embedded_graph : NetworkX graph (optional, default None) A graph which contains all keys of emb as nodes. If specified, edges of G will be considered interactions if and only if they exist between two chains of emb if their keys are connected by an edge in embedded_graph interaction_edges : list (optional, default None) A list of edges which will be used as interactions. show_labels: boolean (optional, default False) If show_labels is True, then each chain in emb is labelled with its key. chain_color : dict (optional, default None) A dict of colors associated with each key in emb. Should be of the form {node: rgba_color, ...}. Colors should be length-4 tuples of floats between 0 and 1 inclusive. If chain_color is None, each chain will be assigned a different color. cmap : str or matplotlib colormap (optional, default None) A matplotlib colormap for coloring of chains. Only used if chain_color is None. unused_color : tuple or color string (optional, default (0.9,0.9,0.9,1.0)) The color to use for nodes and edges of G which are not involved in chains, and edges which are neither chain edges nor interactions. If unused_color is None, these nodes and edges will not be shown at all. overlapped_embedding: boolean (optional, default False) If overlapped_embedding is True, then chains in emb may overlap (contain the same vertices in G), and the drawing will display these overlaps as concentric circles. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, with the exception of the `pos` parameter which is not used by this function. If `linear_biases` or `quadratic_biases` are provided, any provided `node_color` or `edge_color` arguments are ignored. """ try: import matplotlib.pyplot as plt import matplotlib as mpl except ImportError: raise ImportError("Matplotlib and numpy required for draw_chimera()") if nx.utils.is_string_like(unused_color): from matplotlib.colors import colorConverter alpha = kwargs.get('alpha', 1.0) unused_color = colorConverter.to_rgba(unused_color, alpha) if chain_color is None: import matplotlib.cm n = max(1., len(emb) - 1.) if cmap: color = matplotlib.cm.get_cmap(cmap) else: color = distinguishable_color_map(int(n + 1)) var_i = {v: i for i, v in enumerate(emb)} chain_color = {v: color(i / n) for i, v in enumerate(emb)} if overlapped_embedding: bags = compute_bags(G, emb) base_node_size = kwargs.get('node_size', 100) node_size_dict = {v: base_node_size for v in G.nodes()} G, emb, interaction_edges = unoverlapped_embedding( G, emb, interaction_edges) for node, data in G.nodes(data=True): if 'dummy' in data: v, x = node layout[node] = layout[v] for v, bag in bags.items(): for i, x in enumerate(bag): node_size_dict[(v, x)] = base_node_size * (len(bag) - i)**2 kwargs['node_size'] = [node_size_dict[p] for p in G.nodes()] qlabel = {q: v for v, chain in emb.items() for q in chain} edgelist = [] edge_color = [] background_edgelist = [] background_edge_color = [] if interaction_edges is not None: interactions = nx.Graph() interactions.add_edges_from(interaction_edges) def show(p, q, u, v): return interactions.has_edge(p, q) elif embedded_graph is not None: def show(p, q, u, v): return embedded_graph.has_edge(u, v) else: def show(p, q, u, v): return True for (p, q) in G.edges(): u = qlabel.get(p) v = qlabel.get(q) if u is None or v is None: ec = unused_color elif u == v: ec = chain_color.get(u) elif show(p, q, u, v): ec = (0, 0, 0, 1) else: ec = unused_color if ec == unused_color: background_edgelist.append((p, q)) background_edge_color.append(ec) elif ec is not None: edgelist.append((p, q)) edge_color.append(ec) nodelist = [] node_color = [] for p in G.nodes(): u = qlabel.get(p) if u is None: pc = unused_color else: pc = chain_color.get(u) if pc is not None: nodelist.append(p) node_color.append(pc) labels = {} if show_labels: if overlapped_embedding: node_labels = {q: [] for q in bags.keys()} node_index = {p: i for i, p in enumerate(G.nodes())} for v in emb.keys(): v_labelled = False chain = emb[v] for node in chain: (q, _) = node if len(bags[q]) == 1: # if there's a node that only has this label, use that labels[q] = str(v) v_labelled = True break if not v_labelled and chain: # otherwise, pick a random node for this label node = random.choice(list(chain)) (q, _) = node node_labels[q].append(v) for q, label_vars in node_labels.items(): x, y = layout[q] # TODO: find a better way of placing labels around the outside of nodes. # Currently, if the graph is resized, labels will appear at a strange distance from the vertices. # To fix this, the "scale" value below, rather than being a fixed constant, should be determined using # both the size of the nodes and the size of the coordinate space of the graph. scale = 0.1 # spread the labels evenly around the node. for i, v in enumerate(label_vars): theta = 2 * math.pi * i / len(label_vars) new_x = x + scale * math.sin(theta) new_y = y + scale * math.cos(theta) plt.text(new_x, new_y, str(v), color=node_color[node_index[(q, v)]], horizontalalignment='center', verticalalignment='center') else: for v in emb.keys(): c = emb[v] labels[list(c)[0]] = str(v) # draw the background (unused) graph first if unused_color is not None: draw(G, layout, nodelist=nodelist, edgelist=background_edgelist, node_color=node_color, edge_color=background_edge_color, **kwargs) draw(G, layout, nodelist=nodelist, edgelist=edgelist, node_color=node_color, edge_color=edge_color, labels=labels, **kwargs)
def draw_embedding(G, layout, emb, embedded_graph=None, interaction_edges=None, chain_color=None, unused_color=(0.9,0.9,0.9,1.0), cmap=None, show_labels=False, **kwargs): """Draws an embedding onto the graph G, according to layout. If interaction_edges is not None, then only display the couplers in that list. If embedded_graph is not None, the only display the couplers between chains with intended couplings according to embedded_graph. Parameters ---------- G : NetworkX graph The graph to be drawn layout : dict A dict of coordinates associated with each node in G. Should be of the form {node: coordinate, ...}. Coordinates will be treated as vectors, and should all have the same length. emb : dict A dict of chains associated with each node in G. Should be of the form {node: chain, ...}. Chains should be iterables of qubit labels (qubits are nodes in G). embedded_graph : NetworkX graph (optional, default None) A graph which contains all keys of emb as nodes. If specified, edges of G will be considered interactions if and only if they exist between two chains of emb if their keys are connected by an edge in embedded_graph interaction_edges : list (optional, default None) A list of edges which will be used as interactions. show_labels: boolean (optional, default False) If show_labels is True, then each chain in emb is labelled with its key. chain_color : dict (optional, default None) A dict of colors associated with each key in emb. Should be of the form {node: rgba_color, ...}. Colors should be length-4 tuples of floats between 0 and 1 inclusive. If chain_color is None, each chain will be assigned a different color. unused_color : tuple (optional, default (0.9,0.9,0.9,1.0)) The color to use for nodes and edges of G which are not involved in chains, and edges which are neither chain edges nor interactions. If unused_color is None, these nodes and edges will not be shown at all. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, with the exception of the `pos` parameter which is not used by this function. If `linear_biases` or `quadratic_biases` are provided, any provided `node_color` or `edge_color` arguments are ignored. """ try: import matplotlib.pyplot as plt import matplotlib as mpl except ImportError: raise ImportError("Matplotlib and numpy required for draw_chimera()") if chain_color is None: import matplotlib.cm n = max(1., len(emb) - 1.) if kwargs.get("cmap"): color = matplotlib.cm.get_cmap(kwargs.get("cmap")) else: color = distinguishable_color_map(int(n+1)) var_i = {v: i for i, v in enumerate(emb)} chain_color = {v: color(i/n) for i, v in enumerate(emb)} qlabel = {q: v for v, chain in iteritems(emb) for q in chain} edgelist = [] edge_color = [] background_edgelist = [] background_edge_color = [] if interaction_edges is not None: interactions = nx.Graph() interactions.add_edges_from(interaction_edges) def show(p, q, u, v): return interactions.has_edge(p, q) elif embedded_graph is not None: def show(p, q, u, v): return embedded_graph.has_edge(u, v) else: def show(p, q, u, v): return True for (p, q) in G.edges(): u = qlabel.get(p) v = qlabel.get(q) if u is None or v is None: ec = unused_color elif u == v: ec = chain_color.get(u) elif show(p, q, u, v): ec = (0, 0, 0, 1) else: ec = unused_color if ec == unused_color: background_edgelist.append((p, q)) background_edge_color.append(ec) elif ec is not None: edgelist.append((p, q)) edge_color.append(ec) nodelist = [] node_color = [] for p in G.nodes(): u = qlabel.get(p) if u is None: pc = unused_color else: pc = chain_color.get(u) if pc is not None: nodelist.append(p) node_color.append(pc) labels = {} if show_labels: for v in emb.keys(): c = emb[v] labels[list(c)[0]] = str(v) # draw the background (unused) graph first if unused_color is not None: draw(G, layout, nodelist=nodelist, edgelist=background_edgelist, node_color=node_color, edge_color=background_edge_color, **kwargs) draw(G, layout, nodelist=nodelist, edgelist=edgelist, node_color=node_color, edge_color=edge_color, labels=labels, **kwargs)