Source code for pycapacity.visual

"""
Overview
---------

This is a python module helping to visualise 2d and 3d polytopes and ellipsoids. It is based on the module  ``matplotlib``.

* visualising 2d and 3d `polytope <#pycapacity\.visual\.plot_polytope>`_
* visualising 2d and 3d polytope `faces <#pycapacity\.visual\.plot_polytope_faces>`_ and `vertices  <#pycapacity\.visual\.plot_polytope_vertex>`_
* visualising 2d and 3d `ellipsoids <#pycapacity\.visual\.plot_ellipsoid>`_

"""


import matplotlib.pyplot as plt
import matplotlib
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import mpl_toolkits
from matplotlib.patches import Ellipse
import numpy as np
from pycapacity.objects import *

[docs] def plot_polytope(polytope, plot=None, color=None, vertex_color='black', face_color=None, edge_color=None, alpha=None,label=None, center=None, scale=1.0, show_vertices=True, wireframe=False): """ A polytope plotting function in 2d and 3d. It plots the polytope faces and vertices from the polytope object. Note: ``plot`` parameter can be either ``matplotlib.pyplot`` or ``matplotlib.axes.Axes`` or ``matplotlib.figure.Figure`` or ``mpl_toolkits.mplot3d.axes3d.Axes3D``. Args: plot: matplotlib ax to plot on, can be either ``matplotlib.pyplot`` or ``matplotlib.axes.Axes`` or ``matplotlib.figure.Figure`` or ``mpl_toolkits.mplot3d.axes3d.Axes3D`` polytope(Polytope) : polytope object it has to be provided face_color: polytope face color (optional) edge_color: polytope edge color (optional) vertex_color: polytope vertex color (optional) alpha: polytope opacity (optional) label: legend label (optional) center: offset the polytope (optional) scale: scale the polytope with a scalar (optional) show_vertices: show the vertices of the polytope (optional) wireframe: show the polytope as a wireframe (optional) color: polytope color - it can be either a string (one color for faces, edges and vertices) or a list of 3 values for face, edge and vertex color (optional) """ if not isinstance(polytope, Polytope): print("no polytope provided") return plot # if color is one value, use it for all if color is not None and (isinstance(color, str) or len(color) == 1): face_color=color, edge_color=color, vertex_color=color # if color is a list of 3 values, use it for face, edge and vertex elif color is not None and len(color) == 3: face_color, edge_color, vertex_color = color if vertex_color is None: show_vertices = False if label is None: label = '' if show_vertices: if polytope.vertices is None: print("Visual: no vertices found, calculating vertices") polytope.find_vertices() if polytope.vertices is not None: plot = plot_polytope_vertex(polytope=polytope, plot=plot, label=label+' vertex', color=vertex_color, center=center, scale=scale) else: print("Visual: cannot find vertices") if polytope.faces is None: print("Visual: no faces found, calculating faces") polytope.find_faces() if polytope.faces is not None: plot = plot_polytope_faces(polytope=polytope, plot=plot, face_color=face_color, edge_color=edge_color, alpha=alpha,label=label+' faces', center=center, scale=scale, wireframe=wireframe) else: print("Visual: cannot find faces") return plot
[docs] def plot_polytope_faces(faces=None, polytope=None, plot=None, face_color=None, edge_color=None, alpha=None,label=None, center=None, scale=1.0, wireframe=False): """ Polytope faces plotting function in 2d and 3d. Note: ``plot`` parameter can be either matplotlib.pyplot or matplotlib.axes.Axes or matplotlib.figure.Figure. Examples: >>> import pycapacity.visual >>> import matplotlib.pyplot as plt >>> import numpy as np >>> fig = plt.figure() >>> pycapacity.visual.plot_polytope_faces([[6,5,4,3],[1,2,2,1]],plot=fig,face_color='blue') >>> pycapacity.visual.plot_polytope_faces([[10,8,7,6],[1,2,2,1]],plot=fig,face_color='red') >>> plt.show() Args: plot: matplotlib ax to plot on, can be either ``matplotlib.pyplot`` or ``matplotlib.axes.Axes`` or ``matplotlib.figure.Figure`` or ``mpl_toolkits.mplot3d.axes3d.Axes3D`` faces: list of faces (optional **either vertex or polytope must be provided**) polytope(Polytope): polytope object - if it is provided, it will use polytope.faces (optional **either vertex or polytope must be provided**) face_color: polytope face color (optional) edge_color: polytope edge color (optional) alpha: polytope opacity (optional) label: legend label (optional) center: offset the polytope (optional) scale: scale the polytope with a scalar (optional) wireframe: show the polytope as a wireframe (optional) Returns: ax: matplotlib ax used for plotting """ ax = None if faces is None and polytope is not None: faces = polytope.faces if faces is None: print("no data to plot") return ax # check if face shape is equal to 2 or 3 dim = np.array(faces).shape if 2 in dim: dim = 2 elif 3 in dim: dim = 3 # figure out what axes to plot on if plot == matplotlib.pyplot: # if its plt provided, get the current axes # see if the first one is already an axis, if not create one axes = plt.gcf().get_axes() if dim == 2: if len(axes) != 0 and isinstance(axes[0], matplotlib.axes.Axes): ax = axes[0] else: ax = plt.axes() else: if len(axes) != 0 and isinstance(axes[0], mpl_toolkits.mplot3d.axes3d.Axes3D): ax = axes[0] print("using existing 3d axis") else: ax = plt.axes(projection='3d') print("creating a new 3d axis") elif isinstance(plot, matplotlib.figure.Figure): # if its figure provided, get the current axes # see if the first one is already an axis, if not create one axes = plot.get_axes() if dim == 2: if len(axes) != 0 and isinstance(axes[0], matplotlib.axes.Axes): ax = axes[0] else: ax = plot.add_subplot(111) else: if len(axes) != 0 and isinstance(axes[0], mpl_toolkits.mplot3d.axes3d.Axes3D): print("using existing 3d axis") ax = axes[0] else: print("creating a new 3d axis") ax = plot.add_subplot(111, projection='3d') elif dim==2 and isinstance(plot, matplotlib.axes.Axes): #if its axes provided, use it ax = plot elif dim==3 and isinstance(plot, mpl_toolkits.mplot3d.axes3d.Axes3D): #if its axes provided, use it ax = plot print("using provided 3d axis") else: print(f"no matplotlib {dim}d axes provided") return ax # scale the data faces= np.array(faces)*scale if dim == 2: if center is None: center = (0,0) if wireframe: ax.fill(faces[0]+center[0],faces[1]+center[1], alpha=0.4, facecolor='none', edgecolor=edge_color, linewidth=3,label=label) else: ax.fill(faces[0]+center[0],faces[1]+center[1], alpha=0.4, facecolor=face_color, edgecolor=edge_color, linewidth=3,label=label) elif dim == 3: if center is None: center = (0,0,0) for polygone in faces: try: # a small management of python3 poly = Poly3DCollection([list(zip(polygone[0,:]+center[0],polygone[1,:]+center[1],polygone[2,:]+center[2]))]) except ValueError: # vs python2 poly = Poly3DCollection(list([zip(polygone[0,:]+center[0],polygone[1,:]+center[1],polygone[2,:]+center[2])])) if not wireframe: if alpha != None: poly.set_alpha(alpha) if face_color != None: poly.set_facecolors(face_color) if edge_color != None: poly.set_edgecolor(edge_color) else: poly.set_facecolors((0,0,0,0)) if edge_color != None: poly.set_edgecolor(edge_color) # cannot set alpha for the moment else: poly.set_edgecolor((0,0,0,alpha)) ax.add_collection3d(poly) try: # a small management of python3 poly._facecolors2d = poly._facecolor3d poly._edgecolors2d = poly._edgecolor3d except AttributeError: # vs python2 poly._edgecolors2d=poly._edgecolors3d poly._facecolors2d=poly._facecolors3d if label != None: poly.set_label(label) else: print("cannot visualise data with dimension: "+str(dim)) return ax
[docs] def plot_polytope_vertex(vertex=None, polytope=None, plot=None, label=None, color='black' , center=None, scale=1.0): """ Polytope vertices plotting function in 2d and 3d Note: ``plot`` parameter can be either ``matplotlib.pyplot`` or ``matplotlib.axes.Axes`` or ``matplotlib.figure.Figure`` or ``mpl_toolkits.mplot3d.axes3d.Axes3D``. Examples: >>> import pycapacity.visual >>> import matplotlib.pyplot as plt >>> import numpy as np >>> fig = plt.figure() >>> pycapacity.visual.plot_polytope_vertex(np.array([[6,5,4,3],[1,2,2,1]]),plot=fig,color='blue') >>> pycapacity.visual.plot_polytope_vertex(np.array([[10,8,7,6],[1,2,2,1]]),plot=fig, color='red') >>> plt.show() Args: plot: matplotlib ax to plot on, can be either ``matplotlib.pyplot`` or ``matplotlib.axes.Axes`` or ``matplotlib.figure.Figure`` or ``mpl_toolkits.mplot3d.axes3d.Axes3D`` vertex : vertices to be plotted (optional **either vertex or polytope must be provided**) polytope(Polytope): polytope object - if it is provided, it will use the polytope vertices (optional **either vertex or polytope must be provided**) color : vertex color (optional) label : legend label (optional) center: offset the polytope (optional) scale: scale the polytope with a scalar (optional) Returns: ax : matplotlib ax used for plotting """ ax = None if polytope is not None: vertex = polytope.vertices if polytope is None and vertex is None: print("no data to plot") return ax # check if face shape is equal to 2 or 3 dim = np.array(vertex).shape if 2 in dim: dim = 2 elif 3 in dim: dim = 3 # figure out what axes to plot on if plot == matplotlib.pyplot: # if its plt provided, get the current axes # see if the first one is already an axis, if not create one axes = plt.gcf().get_axes() if dim == 2: if len(axes) != 0 and isinstance(axes[0], matplotlib.axes.Axes): ax = axes[0] else: ax = plt.axes() else: if len(axes) != 0 and isinstance(axes[0], mpl_toolkits.mplot3d.axes3d.Axes3D): ax = axes[0] else: ax = plt.axes(projection='3d') elif isinstance(plot, matplotlib.figure.Figure): # if its figure provided, get the current axes # see if the first one is already an axis, if not create one axes = plot.get_axes() if dim == 2: if len(axes) != 0 and isinstance(axes[0], matplotlib.axes.Axes): ax = axes[0] else: ax = plot.add_subplot(111) else: if len(axes) != 0 and isinstance(axes[0], mpl_toolkits.mplot3d.axes3d.Axes3D): ax = axes[0] else: ax = plot.add_subplot(111, projection='3d') elif dim==2 and isinstance(plot, matplotlib.axes.Axes): #if its axes provided, use it ax = plot elif dim==3 and isinstance(plot, mpl_toolkits.mplot3d.axes3d.Axes3D): #if its axes provided, use it ax = plot else: print(f"no matplotlib {dim}d axes provided") return ax # scale the vertices vertex = np.array(vertex)*scale if dim == 2: if center is None: center = np.array([[0],[0]]).reshape(-1,1) else: center = np.array(center).reshape(-1,1) vertex = vertex + center if label != None: ax.scatter(vertex[0,:],vertex[1,:],color=color, label=label) else: ax.scatter(vertex[0,:],vertex[1,:],color=color) elif dim == 3: if center is None: center = np.array([[0],[0],[0]]) else: center = np.array(center).reshape(-1,1) vertex = vertex + center if label != None: ax.scatter(vertex[0,:],vertex[1,:],vertex[2,:],color=color, label=label) else: ax.scatter(vertex[0,:],vertex[1,:],vertex[2,:],color=color) else: print("cannot visualise data with dimension: "+str(dim)) return ax
[docs] def plot_ellipsoid(radii=None, rotation=None, ellipsoid=None, center=None, plot=None, label=None, color=None, edge_color=None, alpha=1.0, scale=1.0): """ Plotting ellipsoid in 2d and 3d Note: ``plot`` parameter can be either ``matplotlib.pyplot`` or ``matplotlib.axes.Axes`` or ``matplotlib.figure.Figure`` or ``mpl_toolkits.mplot3d.axes3d.Axes3D``. Examples: >>> import pycapacity.visual >>> import matplotlib.pyplot as plt >>> import numpy as np >>> fig = plt.figure() >>> pycapacity.visual.plot_ellipsoid([6,5,4],np.eye(3),plot=fig, color='blue', alpha=0.5) >>> pycapacity.visual.plot_ellipsoid([1,2,3],np.eye(3),plot=fig, color='red', alpha=0.5) >>> plt.show() Args: plot: matplotlib ax to plot on, can be either ``matplotlib.pyplot`` or ``matplotlib.axes.Axes`` or ``matplotlib.figure.Figure`` or ``mpl_toolkits.mplot3d.axes3d.Axes3D`` radii : radii of the ellipsoid in each axis (optional **either radii and rotation or ellipsoid must be provided**) rotation : rotation matrix (optional ***either radii and rotation or ellipsoid must be provided***) ellipsoid(Ellipsoid): ellipsoid object - if it is provided, it will use the ellipsoid radii and rotation (optional either radii and rotation or ellipsoid must be provided) center : offset of the ellipsoid from origin (optional) color : face color (optional) edge_color : egde collor (optional) alpha : opacity (optional) label : legend label (optional) scale: scale the polytope with a scalar (optional) Returns: ax : matplotlib ax used for plotting """ ax = None if ellipsoid is not None: radii = ellipsoid.radii rotation = ellipsoid.rotation center = ellipsoid.center if ellipsoid is None and radii is None: print("no data to plot") return ax dim = np.array(radii).shape[0] U = rotation # scaling the ellipsoid radii = np.array(radii)*scale # figure out what axes to plot on if plot == matplotlib.pyplot: # if its plt provided, get the current axes # see if the first one is already an axis, if not create one axes = plt.gcf().get_axes() if dim == 2: if len(axes) != 0 and isinstance(axes[0], matplotlib.axes.Axes): ax = axes[0] else: ax = plt.axes() else: if len(axes) != 0 and isinstance(axes[0], mpl_toolkits.mplot3d.axes3d.Axes3D): ax = axes[0] else: ax = plt.axes(projection='3d') elif isinstance(plot, matplotlib.figure.Figure): # if its figure provided, get the current axes # see if the first one is already an axis, if not create one axes = plot.get_axes() if dim == 2: if len(axes) != 0 and isinstance(axes[0], matplotlib.axes.Axes): ax = axes[0] else: ax = plot.add_subplot(111) else: if len(axes) != 0 and isinstance(axes[0], mpl_toolkits.mplot3d.axes3d.Axes3D): ax = axes[0] else: ax = plot.add_subplot(111, projection='3d') elif dim==2 and isinstance(plot, matplotlib.axes.Axes): #if its axes provided, use it ax = plot elif dim==3 and isinstance(plot, mpl_toolkits.mplot3d.axes3d.Axes3D): #if its axes provided, use it ax = plot else: print(f"no matplotlib {dim}d axes provided") return ax if dim == 2: if center is None: center = (0,0) rx, ry = radii ellipse = Ellipse(xy=center, width=2*ry, height=2*rx, edgecolor=edge_color, fc='None', lw=2, angle=-np.arctan2(U[0,0],U[0,1])*180/np.pi) if label is not None: ellipse.set_label(label) ax.add_patch(ellipse) elif dim == 3: if center is None: center = (0,0,0) # Radii corresponding to the coefficients: rx, ry, rz = radii # Set of all spherical angles: u = np.linspace(0, 2 * np.pi, 30) v = np.linspace(0, np.pi, 30) # Cartesian coordinates that correspond to the spherical angles: # (this is the equation of an ellipsoid): x = rx * np.outer(np.cos(u), np.sin(v)) y = ry * np.outer(np.sin(u), np.sin(v)) z = rz * np.outer(np.ones_like(u), np.cos(v)) for i in range(len(x)): for j in range(len(x)): [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], rotation.T) + center if label != None: surf = ax.plot_surface(x, y, z, color=color, alpha=alpha, edgecolor=edge_color, linewidth=1, label=label) else: surf = ax.plot_surface(x, y, z, color=color, alpha=alpha, edgecolor=edge_color, linewidth=1) try: # a small management of python3 surf._facecolors2d = surf._facecolor3d surf._edgecolors2d = surf._edgecolor3d except AttributeError: # vs python2 surf._edgecolors2d=surf._edgecolors3d surf._facecolors2d=surf._facecolors3d else: print("cannot visualise data with dimension: "+str(dim)) return ax