From 25b0adc39f1d069eb19fc82ab4f917ef872e8041 Mon Sep 17 00:00:00 2001 From: Kelly Boothby Date: Mon, 13 Dec 2021 16:23:18 -0800 Subject: [PATCH] review --- dwave_networkx/drawing/chimera_layout.py | 84 ++++++++++++---------- dwave_networkx/drawing/pegasus_layout.py | 78 +++++++++++--------- dwave_networkx/drawing/qubit_layout.py | 91 ++++++++++++++++-------- dwave_networkx/drawing/zephyr_layout.py | 74 ++++++++++--------- 4 files changed, 190 insertions(+), 137 deletions(-) diff --git a/dwave_networkx/drawing/chimera_layout.py b/dwave_networkx/drawing/chimera_layout.py index 985b22e7..206d1756 100644 --- a/dwave_networkx/drawing/chimera_layout.py +++ b/dwave_networkx/drawing/chimera_layout.py @@ -27,7 +27,7 @@ __all__ = ['chimera_layout', 'draw_chimera', 'draw_chimera_embedding', 'draw_chimera_yield'] -def chimera_layout(G, scale=1., center=None, dim=2, normalize_kwargs = None): +def chimera_layout(G, scale=1., center=None, dim=2, plot_kwargs=None): """Positions the nodes of graph G in a Chimera cross topology. NumPy (https://scipy.org) is required for this function. @@ -51,10 +51,12 @@ def chimera_layout(G, scale=1., center=None, dim=2, normalize_kwargs = None): Number of dimensions. When dim > 2, all extra dimensions are set to 0. - normalize_kwargs : None or dict (default None) - A dict of keyword arguments to be used in a plotting function. If not - None, we will populate the "ax" keyword with matplotlib axes, and the - "node_size" and "width" keywords with defaults if they are not set. + plot_kwargs : None or dict (default None) + A dict of keyword arguments to be used in a plotting function (see + :func:`networkx.draw` and :func:`draw_lineplot`), to scale node and edge + sizes appropriately to the graph `G`. Optional keys in ``plot_kwargs`` + are set to default values by the :func:`normalize_size_and_aspect` + function. Do nothing if ``plot_kwargs`` is None. Returns ------- @@ -80,7 +82,7 @@ def chimera_layout(G, scale=1., center=None, dim=2, normalize_kwargs = None): n = G.graph['columns'] t = G.graph['tile'] # get a node placement function - xy_coords = chimera_node_placer_2d(m, n, t, scale, center, dim, normalize_kwargs = normalize_kwargs) + xy_coords = chimera_node_placer_2d(m, n, t, scale, center, dim, plot_kwargs=plot_kwargs) if G.graph['labels'] == 'coordinate': pos = {v: xy_coords(*v) for v in G.nodes()} @@ -102,7 +104,7 @@ def chimera_layout(G, scale=1., center=None, dim=2, normalize_kwargs = None): m = max(idx[0] for idx in chimera_indices.values()) + 1 n = max(idx[1] for idx in chimera_indices.values()) + 1 t = max(idx[3] for idx in chimera_indices.values()) + 1 - xy_coords = chimera_node_placer_2d(m, n, t, scale, center, dim, normalize_kwargs = normalize_kwargs) + xy_coords = chimera_node_placer_2d(m, n, t, scale, center, dim, plot_kwargs=plot_kwargs) # compute our coordinates pos = {v: xy_coords(i, j, u, k) for v, (i, j, u, k) in chimera_indices.items()} @@ -110,7 +112,7 @@ def chimera_layout(G, scale=1., center=None, dim=2, normalize_kwargs = None): return pos -def chimera_node_placer_2d(m, n, t, scale=1., center=None, dim=2, normalize_kwargs = None): +def chimera_node_placer_2d(m, n, t, scale=1., center=None, dim=2, plot_kwargs=None): """Generates a function that converts Chimera indices to x, y coordinates for a plot. @@ -135,11 +137,13 @@ def chimera_node_placer_2d(m, n, t, scale=1., center=None, dim=2, normalize_kwar dim : int (default 2) Number of dimensions. When dim > 2, all extra dimensions are set to 0. - - normalize_kwargs : None or dict (default None) - A dict of keyword arguments to be used in a plotting function. If not - None, we will populate the "ax" keyword with matplotlib axes, and the - "node_size" and "width" keywords with defaults if they are not set. + + plot_kwargs : None or dict (default None) + A dict of keyword arguments to be used in a plotting function (see + :func:`networkx.draw` and :func:`draw_lineplot`), to scale node and edge + sizes appropriately to the graph `G`. Optional keys in ``plot_kwargs`` + are set to default values by the :func:`normalize_size_and_aspect` + function. Do nothing if ``plot_kwargs`` is None. Returns ------- @@ -151,19 +155,20 @@ def chimera_node_placer_2d(m, n, t, scale=1., center=None, dim=2, normalize_kwar """ import numpy as np - line_plot = False if normalize_kwargs is None else normalize_kwargs.get('line_plot') + line_plot = False if plot_kwargs is None else plot_kwargs.get('line_plot') center_pad = 0 if line_plot else 1 + border_pad = 2 tile_center = t // 2 - tile_length = t + 2 + center_pad # 2 for spacing between tiles + tile_length = t + border_pad + center_pad # want the enter plot to fill in [0, 1] when scale=1 - fabric_scale = max(m, n) * tile_length - 2 - center_pad + fabric_scale = max(m, n) * tile_length - border_pad - center_pad scale /= fabric_scale - if normalize_kwargs is not None: - normalize_size_and_aspect(fabric_scale, 200, normalize_kwargs) + if plot_kwargs is not None: + normalize_size_and_aspect(fabric_scale, 200, plot_kwargs) grid_offsets = {} @@ -175,6 +180,7 @@ def chimera_node_placer_2d(m, n, t, scale=1., center=None, dim=2, normalize_kwar if dim < 2: raise ValueError("layout must have at least two dimensions") + # pad the dimensions beyond the second with zeros paddims = np.zeros(dim - 2, dtype='float') if len(center) != dim: @@ -241,12 +247,12 @@ def draw_chimera(G, **kwargs): edges (i.e., :math:`i=j`) are treated as linear biases. line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -265,7 +271,7 @@ def draw_chimera(G, **kwargs): >>> plt.show() # doctest: +SKIP """ - layout = chimera_layout(G, normalize_kwargs = kwargs) + layout = chimera_layout(G, plot_kwargs=kwargs) draw_qubit_graph(G, layout, **kwargs) def draw_chimera_embedding(G, *args, **kwargs): @@ -314,12 +320,12 @@ def draw_chimera_embedding(G, *args, **kwargs): concentric circles. line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -327,7 +333,7 @@ def draw_chimera_embedding(G, *args, **kwargs): function. If `linear_biases` or `quadratic_biases` are provided, any provided `node_color` or `edge_color` arguments are ignored. """ - layout = chimera_layout(G, normalize_kwargs = kwargs) + layout = chimera_layout(G, plot_kwargs=kwargs) draw_embedding(G, layout, *args, **kwargs) @@ -358,12 +364,12 @@ def draw_chimera_yield(G, **kwargs): Edge fault line style (solid|dashed|dotted|dashdot) line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -382,5 +388,5 @@ def draw_chimera_yield(G, **kwargs): tile, and label attributes to be able to identify faulty qubits.") perfect_graph = chimera_graph(m,n,t, coordinates=coordinates) - layout = chimera_layout(perfect_graph, normalize_kwargs = kwargs) + layout = chimera_layout(perfect_graph, plot_kwargs=kwargs) draw_yield(G, layout, perfect_graph, **kwargs) diff --git a/dwave_networkx/drawing/pegasus_layout.py b/dwave_networkx/drawing/pegasus_layout.py index c2bc70fe..69b29123 100644 --- a/dwave_networkx/drawing/pegasus_layout.py +++ b/dwave_networkx/drawing/pegasus_layout.py @@ -31,7 +31,7 @@ ] -def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False, normalize_kwargs=None): +def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False, plot_kwargs=None): """Positions the nodes of graph G in a Pegasus topology. `NumPy `_ is required for this function. @@ -58,10 +58,12 @@ def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False, normalize_kwa rather than L configuration. Ignored if G is defined with ``nice_coordinates=True``. - normalize_kwargs : None or dict (default None) - A dict of keyword arguments to be used in a plotting function. If not - None, we will populate the "ax" keyword with matplotlib axes, and the - "node_size" and "width" keywords with defaults if they are not set. + plot_kwargs : None or dict (default None) + A dict of keyword arguments to be used in a plotting function (see + :func:`networkx.draw` and :func:`draw_lineplot`), to scale node and edge + sizes appropriately to the graph `G`. Optional keys in ``plot_kwargs`` + are set to default values by the :func:`normalize_size_and_aspect` + function. Do nothing if ``plot_kwargs`` is None. Returns ------- @@ -81,7 +83,10 @@ def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False, normalize_kwa raise ValueError("G must be generated by dwave_networkx.pegasus_graph") labels = G.graph.get('labels') - xy_coords = pegasus_node_placer_2d(G, scale, center, dim, crosses=(crosses or labels == 'nice_coordinates'), normalize_kwargs = normalize_kwargs) + if labels == 'coordinate': + crosses = True + + xy_coords = pegasus_node_placer_2d(G, scale, center, dim, crosses, plot_kwargs) if labels == 'coordinate': pos = {v: xy_coords(*v) for v in G.nodes()} @@ -100,7 +105,7 @@ def pegasus_layout(G, scale=1., center=None, dim=2, crosses=False, normalize_kwa return pos -def pegasus_node_placer_2d(G, scale=1., center=None, dim=2, crosses=False, normalize_kwargs=None): +def pegasus_node_placer_2d(G, scale=1., center=None, dim=2, crosses=False, plot_kwargs=None): """Generates a function to convert Pegasus indices to plottable coordinates. Parameters @@ -124,6 +129,13 @@ def pegasus_node_placer_2d(G, scale=1., center=None, dim=2, crosses=False, norma If True, :math:`K_{4,4}` subgraphs are shown in a cross rather than L configuration. + plot_kwargs : None or dict (default None) + A dict of keyword arguments to be used in a plotting function (see + :func:`networkx.draw` and :func:`draw_lineplot`), to scale node and edge + sizes appropriately to the graph `G`. Optional keys in ``plot_kwargs`` + are set to default values by the :func:`normalize_size_and_aspect` + function. Do nothing if ``plot_kwargs`` is None. + Returns ------- xy_coords : function @@ -133,7 +145,7 @@ def pegasus_node_placer_2d(G, scale=1., center=None, dim=2, crosses=False, norma """ import numpy as np - line_plot = False if normalize_kwargs is None else normalize_kwargs.get('line_plot') + line_plot = False if plot_kwargs is None else plot_kwargs.get('line_plot') if line_plot: crosses = False @@ -150,8 +162,8 @@ def pegasus_node_placer_2d(G, scale=1., center=None, dim=2, crosses=False, norma fabric_scale = m*tile_width - 2*odd_k_wobble - 1 scale /= fabric_scale - if normalize_kwargs is not None: - normalize_size_and_aspect(fabric_scale, 150, normalize_kwargs) + if plot_kwargs is not None: + normalize_size_and_aspect(fabric_scale, 150, plot_kwargs) if center is None: center = np.zeros(dim) @@ -164,6 +176,7 @@ def pegasus_node_placer_2d(G, scale=1., center=None, dim=2, crosses=False, norma if dim < 0: raise ValueError("layout must have at least two dimensions") + # pad the dimensions beyond the second with zeros paddims = np.zeros(dim - 2) if len(center) != dim: @@ -227,13 +240,12 @@ def draw_pegasus(G, crosses=False, **kwargs): ``nice_coordinates=True`` or ``line_plot=True``. line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. - + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -253,7 +265,7 @@ def draw_pegasus(G, crosses=False, **kwargs): >>> plt.show() # doctest: +SKIP """ - layout = pegasus_layout(G, normalize_kwargs = kwargs) + layout = pegasus_layout(G, plot_kwargs=kwargs) draw_qubit_graph(G, layout, **kwargs) def draw_pegasus_embedding(G, *args, crosses=False, **kwargs): @@ -304,13 +316,12 @@ def draw_pegasus_embedding(G, *args, crosses=False, **kwargs): in G), and these overlaps are displayed as concentric circles. line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. - + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -318,7 +329,7 @@ def draw_pegasus_embedding(G, *args, crosses=False, **kwargs): function. If ``linear_biases`` or ``quadratic_biases`` are provided, any provided ``node_color`` or ``edge_color`` arguments are ignored. """ - layout = pegasus_layout(G, crosses=crosses, normalize_kwargs=kwargs) + layout = pegasus_layout(G, crosses=crosses, plot_kwargs=kwargs) draw_embedding(G, layout, *args, **kwargs) def draw_pegasus_yield(G, crosses=False, **kwargs): @@ -353,13 +364,12 @@ def draw_pegasus_yield(G, crosses=False, **kwargs): ``nice_coordinates=True`` or ``line_plot=True``. line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. - + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -380,5 +390,5 @@ def draw_pegasus_yield(G, crosses=False, **kwargs): perfect_graph = pegasus_graph(m, offset_lists=offset_lists, coordinates=coordinates, nice_coordinates=nice) - layout = pegasus_layout(perfect_graph, crosses=crosses, normalize_kwargs=kwargs) + layout = pegasus_layout(perfect_graph, crosses=crosses, plot_kwargs=kwargs) draw_yield(G, layout, perfect_graph, **kwargs) diff --git a/dwave_networkx/drawing/qubit_layout.py b/dwave_networkx/drawing/qubit_layout.py index e69d2959..5a248b13 100644 --- a/dwave_networkx/drawing/qubit_layout.py +++ b/dwave_networkx/drawing/qubit_layout.py @@ -526,7 +526,7 @@ def draw_yield(G, layout, perfect_graph, unused_color=(0.9,0.9,0.9,1.0), import matplotlib.pyplot as plt import matplotlib as mpl except ImportError: - raise ImportError("Matplotlib and numpy required for draw_yield()") + raise ImportError("Matplotlib required for draw_yield()") edgeset = lambda E: set(map(lambda e: tuple(sorted(e)), E)) nodelist = G.nodes() @@ -569,6 +569,35 @@ def draw_yield(G, layout, perfect_graph, unused_color=(0.9,0.9,0.9,1.0), def normalize_size_and_aspect(scale, node_scale, kwargs): + """Sets default values for the "ax", "node_size" and "width" keys. + + If the `"ax"` is not set, then we create an axis from the current + `matplotlib` figure (:func:`matplotlib.pyplot.gcf()`). Then, the the axis + (either the one we created, or the pre-existing one) is set to have an + aspect ratio of 1 and the drawing of axes is turned off. + + Then, if `"node_size"` and `"width"` are not set, we compute default values + for them based on the scale of the current figure and the scale parameters + as appropriate. + + Note, if `kwargs["line_plot"]` is True, then the interpretation of the + `"width"` and `"node_size"` parameters determine the area of edge-circles + and line widths (used for both nodes and edges) respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. + + Parameters + ---------- + scale : float + A geometric size of a figure to be drawn. This is roughly the number + of qubits in any given row or column of the graph. + + node_scale : float + A magic number used to scale node circles -- ignored and replaced with + the number 50 when `kwargs["line_plot"]` is True. + + kwargs : dict + A dictionary to populate with default values. + """ ax = kwargs.get('ax') if ax is None: try: @@ -606,7 +635,7 @@ def draw_lineplot(G, layout, *, ax, node_size, width, nodelist=None, edgelist=None, node_color='blue', edge_color='black', cmap=None, vmin=None, vmax=None, edge_cmap=None, edge_vmin=None, edge_vmax=None, z_offset=0): - """Draws the graph G with line segments representing nodes + """Draws the graph G with line segments representing nodes. This function is meant to be a drop-in replacement for :func:`networkx.draw` where nodes are associated with line segments (specified as 2x2 matrices @@ -617,22 +646,22 @@ def draw_lineplot(G, layout, *, ax, node_size, width, nodelist=None, have three classes of edges: * internal edges between qubits whose line segments are perpendicular - and intersect at a point, which we draw with a circle located at the - point of intersection, - * external edges between qubits whose line segments are colinear, which - we draw as a line segment between the nearest endpoints, and + and intersect at a point, drawn as a circle located at the point of + intersection, + * external edges between qubits whose line segments are colinear, drawn + as a line segment between the nearest endpoints, and * odd edges between parallel qubits whose line segments are parallel and - overlap in a perpendicular projection, which we draw as a line segment - between the midpoints of the respective perpendicular projections + overlap in a perpendicular projection, drawn as a line segment between + the midpoints of the respective perpendicular projections. Parameters ---------- G : networkx.Graph - A graph constructed by :func:`chimera_layout`, :func:`pegasus_layout, or - :func:`zephyr_layout` + A graph constructed by :func:`chimera_layout`, :func:`pegasus_layout`, + or :func:`zephyr_layout`. - pos : dict + layout : dict A dictionary with nodes as keys and 2x2 matrices [[x0, y0], [x1, y1]] representing the line segments of nodes. @@ -650,9 +679,9 @@ def draw_lineplot(G, layout, *, ax, node_size, width, nodelist=None, The set of nodes to draw. If None, all nodes from G are drawn. edgelist : iterable or None (default=None) - The set of edges to draw. If both nodelist and edgelist are None, all - edges of G are drawn. If edgelist is None, all edges from the subgraph - ``G.subgraph(nodelist)`` are drawn. + The set of edges to draw. If both nodelist and ``edgelist`` are None, + all edges of G are drawn. If ``edgelist`` is None, all edges from the + subgraph ``G.subgraph(nodelist)`` are drawn. node_color : iterable or string (default='blue') The sequence of colors to use in drawing nodes of G. If node_color is @@ -661,18 +690,20 @@ def draw_lineplot(G, layout, *, ax, node_size, width, nodelist=None, edge_color : iterable or string (default='black') The sequence of colors to use in drawing edges of G. If edge_color is - not a string, the colors are taken in the same order as edgelist, and - each color is either a float, a 3-tuple or 4-tuple of floats. + not a string, the colors are taken in the same order as ``edgelist``, + and each color is either a float, a 3-tuple or 4-tuple of floats. cmap : string or matplotlib.ColorMap or None (default=None) A colormap to color nodes with. Presumes that node_color is a sequence of floats. vmin : float or None (default=None) - Minimum value to use to use when normalizing node colors through cmap. + Minimum value to use to use when normalizing node colors through + ``cmap``. vmax : float or None (default=None) - Maximum value to use to use when normalizing node colors through cmap. + Maximum value to use to use when normalizing node colors through + ``cmap``. edge_cmap : string or matplotlib.ColorMap or None (default=None) A colormap to color edges with. Presumes that edge_color is a sequence @@ -680,23 +711,25 @@ def draw_lineplot(G, layout, *, ax, node_size, width, nodelist=None, edge_vmin : float or None (default=None) Minimum value to use to use when normalizing edge colors through - edge_cmap + ``edge_cmap``. edge_vmax : float or None (default=None) Maximum value to use to use when normalizing edge colors through - edge_cmap + ``edge_cmap``. z_offset : int (default=0) - An offset to the zorder that various elements are drawn in. Edge lines - are drawn with zorder=z_offset; horizontal node lines are drawn with - zorder=zoffset+1; vertical node lines are drawn with zorder=zoffset+2, - and edge circles are drawn with zorder=zoffset+3. This parameter can be - used to layer line plots over or under eachother. + An offset to the "zorder: that various elements are drawn in. Edge + lines are drawn with `zorder=z_offset`; horizontal node lines are drawn + with `zorder=zoffset+1`; vertical node lines are drawn with + `zorder=zoffset+2`, and edge circles are drawn with `zorder=zoffset+3`. + This parameter can be used to layer line plots over or under each other. """ - - from networkx.drawing.nx_pylab import apply_alpha - import numpy as np - from matplotlib.collections import LineCollection, CircleCollection + try: + from networkx.drawing.nx_pylab import apply_alpha + import numpy as np + from matplotlib.collections import LineCollection, CircleCollection + except ImportError: + raise ImportError("Matplotlib and NumPy required for draw_lineplot()") if not isinstance(node_size, Number) or not isinstance(width, Number): raise NotImplementedError("Varying node size and edge width per element in line plots is not implemented") diff --git a/dwave_networkx/drawing/zephyr_layout.py b/dwave_networkx/drawing/zephyr_layout.py index cd63cbba..da155b7a 100644 --- a/dwave_networkx/drawing/zephyr_layout.py +++ b/dwave_networkx/drawing/zephyr_layout.py @@ -30,7 +30,7 @@ ] -def zephyr_layout(G, scale=1., center=None, dim=2, normalize_kwargs=None): +def zephyr_layout(G, scale=1., center=None, dim=2, plot_kwargs=None): """Positions the nodes of graph G in a Zephyr topology. `NumPy `_ is required for this function. @@ -52,10 +52,12 @@ def zephyr_layout(G, scale=1., center=None, dim=2, normalize_kwargs=None): Number of dimensions. When dim > 2, all extra dimensions are set to 0. - normalize_kwargs : None or dict (default None) - A dict of keyword arguments to be used in a plotting function. If not - None, we will populate the "ax" keyword with matplotlib axes, and the - "node_size" and "width" keywords with defaults if they are not set. + plot_kwargs : None or dict (default None) + A dict of keyword arguments to be used in a plotting function (see + :func:`networkx.draw` and :func:`draw_lineplot`), to scale node and edge + sizes appropriately to the graph `G`. Optional keys in ``plot_kwargs`` + are set to default values by the :func:`normalize_size_and_aspect` + function. Do nothing if ``plot_kwargs`` is None. Returns ------- @@ -74,7 +76,7 @@ def zephyr_layout(G, scale=1., center=None, dim=2, normalize_kwargs=None): if not isinstance(G, nx.Graph) or G.graph.get("family") != "zephyr": raise ValueError("G must be generated by dwave_networkx.zephyr_graph") - xy_coords = zephyr_node_placer_2d(G, scale, center, dim, normalize_kwargs) + xy_coords = zephyr_node_placer_2d(G, scale, center, dim, plot_kwargs) if G.graph['labels'] == 'coordinate': pos = {v: xy_coords(*v) for v in G.nodes()} @@ -89,7 +91,7 @@ def zephyr_layout(G, scale=1., center=None, dim=2, normalize_kwargs=None): return pos -def zephyr_node_placer_2d(G, scale=1., center=None, dim=2, normalize_kwargs = None): +def zephyr_node_placer_2d(G, scale=1., center=None, dim=2, plot_kwargs=None): """Generates a function to convert Zephyr indices to plottable coordinates. Parameters @@ -109,10 +111,12 @@ def zephyr_node_placer_2d(G, scale=1., center=None, dim=2, normalize_kwargs = No Number of dimensions. When dim > 2, all extra dimensions are set to 0. - normalize_kwargs : None or dict (default None) - A dict of keyword arguments to be used in a plotting function. If not - None, we will populate the "ax" keyword with matplotlib axes, and the - "node_size" and "width" keywords with defaults if they are not set. + plot_kwargs : None or dict (default None) + A dict of keyword arguments to be used in a plotting function (see + :func:`networkx.draw` and :func:`draw_lineplot`), to scale node and edge + sizes appropriately to the graph `G`. Optional keys in ``plot_kwargs`` + are set to default values by the :func:`normalize_size_and_aspect` + function. Do nothing if ``plot_kwargs`` is None. Returns ------- @@ -123,7 +127,7 @@ def zephyr_node_placer_2d(G, scale=1., center=None, dim=2, normalize_kwargs = No """ import numpy as np - line_plot = False if normalize_kwargs is None else normalize_kwargs.get('line_plot') + line_plot = False if plot_kwargs is None else plot_kwargs.get('line_plot') m = G.graph['rows'] tile_width = 2*G.graph["tile"] @@ -156,8 +160,8 @@ def _xy_coords(u, w, k, j, z): fabric_scale = max(map(abs, _xy_coords(0, 2*m, G.graph["tile"]-1, 1, m-1))) scale /= fabric_scale - if normalize_kwargs is not None: - normalize_size_and_aspect(fabric_scale, 200, normalize_kwargs) + if plot_kwargs is not None: + normalize_size_and_aspect(fabric_scale, 200, plot_kwargs) if line_plot: qubit_dx = np.hstack(([tile_width - .25, 0], paddims)) * scale @@ -194,12 +198,12 @@ def draw_zephyr(G, **kwargs): edges (i.e., :math:`i=j`) are treated as linear biases. line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -219,7 +223,7 @@ def draw_zephyr(G, **kwargs): >>> plt.show() # doctest: +SKIP """ - layout = zephyr_layout(G, normalize_kwargs = kwargs) + layout = zephyr_layout(G, plot_kwargs=kwargs) draw_qubit_graph(G, layout, **kwargs) def draw_zephyr_embedding(G, *args, **kwargs): @@ -265,12 +269,12 @@ def draw_zephyr_embedding(G, *args, **kwargs): in G), and these overlaps are displayed as concentric circles. line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -278,7 +282,7 @@ def draw_zephyr_embedding(G, *args, **kwargs): function. If ``linear_biases`` or ``quadratic_biases`` are provided, any provided ``node_color`` or ``edge_color`` arguments are ignored. """ - layout = zephyr_layout(G, normalize_kwargs = kwargs) + layout = zephyr_layout(G, plot_kwargs=kwargs) draw_embedding(G, layout, *args, **kwargs) def draw_zephyr_yield(G, **kwargs): @@ -308,12 +312,12 @@ def draw_zephyr_yield(G, **kwargs): Edge fault line style (solid|dashed|dotted|dashdot) line_plot : boolean (optional, default False) - If line_plot is True, then qubits are drawn as line segments, and edges - are drawn either as line segments between qubits, or as circles where - two qubits overlap. In this drawing style, the interpretation the width - and node_size parameters (provided in kwargs) determines the area of the - circles, and line widths, respectively. For more information, see - :func:`dwave_networkx.qubit_layout.draw_lineplot`. + If ``line_plot`` is True, then qubits are drawn as line segments, and + edges are drawn either as line segments between qubits, or as circles + where two qubits overlap. In this drawing style, the interpretation of + the ``width`` and ``node_size`` parameters (provided in ``kwargs``) + determine the area of the circles and line widths respectively. See + :func:`dwave_networkx.qubit_layout.draw_lineplot` for more information. kwargs : optional keywords See networkx.draw_networkx() for a description of optional keywords, @@ -331,5 +335,5 @@ def draw_zephyr_yield(G, **kwargs): tile, and label attributes to be able to identify faulty qubits.") perfect_graph = zephyr_graph(m, t, coordinates=coordinates) - layout = zephyr_layout(perfect_graph, normalize_kwargs = kwargs) + layout = zephyr_layout(perfect_graph, plot_kwargs=kwargs) draw_yield(G, layout, perfect_graph, **kwargs)