123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- import numpy as np
- from scipy._lib.decorator import decorator as _decorator
- __all__ = ['delaunay_plot_2d', 'convex_hull_plot_2d', 'voronoi_plot_2d']
- @_decorator
- def _held_figure(func, obj, ax=None, **kw):
- import matplotlib.pyplot as plt
- if ax is None:
- fig = plt.figure()
- ax = fig.gca()
- return func(obj, ax=ax, **kw)
- # As of matplotlib 2.0, the "hold" mechanism is deprecated.
- # When matplotlib 1.x is no longer supported, this check can be removed.
- was_held = getattr(ax, 'ishold', lambda: True)()
- if was_held:
- return func(obj, ax=ax, **kw)
- try:
- ax.hold(True)
- return func(obj, ax=ax, **kw)
- finally:
- ax.hold(was_held)
- def _adjust_bounds(ax, points):
- margin = 0.1 * points.ptp(axis=0)
- xy_min = points.min(axis=0) - margin
- xy_max = points.max(axis=0) + margin
- ax.set_xlim(xy_min[0], xy_max[0])
- ax.set_ylim(xy_min[1], xy_max[1])
- @_held_figure
- def delaunay_plot_2d(tri, ax=None):
- """
- Plot the given Delaunay triangulation in 2-D
- Parameters
- ----------
- tri : scipy.spatial.Delaunay instance
- Triangulation to plot
- ax : matplotlib.axes.Axes instance, optional
- Axes to plot on
- Returns
- -------
- fig : matplotlib.figure.Figure instance
- Figure for the plot
- See Also
- --------
- Delaunay
- matplotlib.pyplot.triplot
- Notes
- -----
- Requires Matplotlib.
- Examples
- --------
- >>> import numpy as np
- >>> import matplotlib.pyplot as plt
- >>> from scipy.spatial import Delaunay, delaunay_plot_2d
- The Delaunay triangulation of a set of random points:
- >>> rng = np.random.default_rng()
- >>> points = rng.random((30, 2))
- >>> tri = Delaunay(points)
- Plot it:
- >>> _ = delaunay_plot_2d(tri)
- >>> plt.show()
- """
- if tri.points.shape[1] != 2:
- raise ValueError("Delaunay triangulation is not 2-D")
- x, y = tri.points.T
- ax.plot(x, y, 'o')
- ax.triplot(x, y, tri.simplices.copy())
- _adjust_bounds(ax, tri.points)
- return ax.figure
- @_held_figure
- def convex_hull_plot_2d(hull, ax=None):
- """
- Plot the given convex hull diagram in 2-D
- Parameters
- ----------
- hull : scipy.spatial.ConvexHull instance
- Convex hull to plot
- ax : matplotlib.axes.Axes instance, optional
- Axes to plot on
- Returns
- -------
- fig : matplotlib.figure.Figure instance
- Figure for the plot
- See Also
- --------
- ConvexHull
- Notes
- -----
- Requires Matplotlib.
- Examples
- --------
- >>> import numpy as np
- >>> import matplotlib.pyplot as plt
- >>> from scipy.spatial import ConvexHull, convex_hull_plot_2d
- The convex hull of a random set of points:
- >>> rng = np.random.default_rng()
- >>> points = rng.random((30, 2))
- >>> hull = ConvexHull(points)
- Plot it:
- >>> _ = convex_hull_plot_2d(hull)
- >>> plt.show()
- """
- from matplotlib.collections import LineCollection
- if hull.points.shape[1] != 2:
- raise ValueError("Convex hull is not 2-D")
- ax.plot(hull.points[:, 0], hull.points[:, 1], 'o')
- line_segments = [hull.points[simplex] for simplex in hull.simplices]
- ax.add_collection(LineCollection(line_segments,
- colors='k',
- linestyle='solid'))
- _adjust_bounds(ax, hull.points)
- return ax.figure
- @_held_figure
- def voronoi_plot_2d(vor, ax=None, **kw):
- """
- Plot the given Voronoi diagram in 2-D
- Parameters
- ----------
- vor : scipy.spatial.Voronoi instance
- Diagram to plot
- ax : matplotlib.axes.Axes instance, optional
- Axes to plot on
- show_points : bool, optional
- Add the Voronoi points to the plot.
- show_vertices : bool, optional
- Add the Voronoi vertices to the plot.
- line_colors : string, optional
- Specifies the line color for polygon boundaries
- line_width : float, optional
- Specifies the line width for polygon boundaries
- line_alpha : float, optional
- Specifies the line alpha for polygon boundaries
- point_size : float, optional
- Specifies the size of points
- Returns
- -------
- fig : matplotlib.figure.Figure instance
- Figure for the plot
- See Also
- --------
- Voronoi
- Notes
- -----
- Requires Matplotlib.
- Examples
- --------
- >>> import numpy as np
- >>> import matplotlib.pyplot as plt
- >>> from scipy.spatial import Voronoi, voronoi_plot_2d
- Create a set of points for the example:
- >>> rng = np.random.default_rng()
- >>> points = rng.random((10,2))
- Generate the Voronoi diagram for the points:
- >>> vor = Voronoi(points)
- Use `voronoi_plot_2d` to plot the diagram:
- >>> fig = voronoi_plot_2d(vor)
- Use `voronoi_plot_2d` to plot the diagram again, with some settings
- customized:
- >>> fig = voronoi_plot_2d(vor, show_vertices=False, line_colors='orange',
- ... line_width=2, line_alpha=0.6, point_size=2)
- >>> plt.show()
- """
- from matplotlib.collections import LineCollection
- if vor.points.shape[1] != 2:
- raise ValueError("Voronoi diagram is not 2-D")
- if kw.get('show_points', True):
- point_size = kw.get('point_size', None)
- ax.plot(vor.points[:, 0], vor.points[:, 1], '.', markersize=point_size)
- if kw.get('show_vertices', True):
- ax.plot(vor.vertices[:, 0], vor.vertices[:, 1], 'o')
- line_colors = kw.get('line_colors', 'k')
- line_width = kw.get('line_width', 1.0)
- line_alpha = kw.get('line_alpha', 1.0)
- center = vor.points.mean(axis=0)
- ptp_bound = vor.points.ptp(axis=0)
- finite_segments = []
- infinite_segments = []
- for pointidx, simplex in zip(vor.ridge_points, vor.ridge_vertices):
- simplex = np.asarray(simplex)
- if np.all(simplex >= 0):
- finite_segments.append(vor.vertices[simplex])
- else:
- i = simplex[simplex >= 0][0] # finite end Voronoi vertex
- t = vor.points[pointidx[1]] - vor.points[pointidx[0]] # tangent
- t /= np.linalg.norm(t)
- n = np.array([-t[1], t[0]]) # normal
- midpoint = vor.points[pointidx].mean(axis=0)
- direction = np.sign(np.dot(midpoint - center, n)) * n
- if (vor.furthest_site):
- direction = -direction
- far_point = vor.vertices[i] + direction * ptp_bound.max()
- infinite_segments.append([vor.vertices[i], far_point])
- ax.add_collection(LineCollection(finite_segments,
- colors=line_colors,
- lw=line_width,
- alpha=line_alpha,
- linestyle='solid'))
- ax.add_collection(LineCollection(infinite_segments,
- colors=line_colors,
- lw=line_width,
- alpha=line_alpha,
- linestyle='dashed'))
- _adjust_bounds(ax, vor.points)
- return ax.figure
|