def generate_polycollection(ax, x, y1, y2): """ Accessory function that creates new PolyCollection class instance representing new correct field-of-view. We use its output to assign new *path* to the old one instance. Algorithm has been taken from the matplotlib' sources for the fill_between() function and used because there is no easy way to update polygon with new data input: same as for the fill_between() function returns: matplotlib.collections.PolyCollection instance """ # i.e. where = outer_circle >= fov_circle where = y2 >= y1 kwargs = {'facecolor': colors['fov_outer'], 'alpha': 0.25} # Convert the arrays so we can work with them x = np.ma.masked_invalid(ax.convert_xunits(x)) y1 = np.ma.masked_invalid(ax.convert_yunits(y1)) y2 = np.ma.masked_invalid(ax.convert_yunits(y2)) where = where & ~functools.reduce(np.logical_or, map(np.ma.getmask, [x, y1, y2])) x, y1, y2 = np.broadcast_arrays(np.atleast_1d(x), y1, y2) polys = [] for ind0, ind1 in contiguous_regions(where): xslice = x[ind0:ind1] y1slice = y1[ind0:ind1] y2slice = y2[ind0:ind1] if not len(xslice): continue N = len(xslice) X = np.zeros((2 * N + 2, 2), float) # the purpose of the next two lines is for when y2 is a # scalar like 0 and we want the fill to go all the way # down to 0 even if none of the y1 sample points do start = xslice[0], y2slice[0] end = xslice[-1], y2slice[-1] X[0] = start X[N + 1] = end X[1:N + 1, 0] = xslice X[1:N + 1, 1] = y1slice X[N + 2:, 0] = xslice[::-1] X[N + 2:, 1] = y2slice[::-1] polys.append(X) return mcoll.PolyCollection(polys, **kwargs)
def test_contiguous_regions(): a, b, c = 3, 4, 5 # Starts and ends with True mask = [True]*a + [False]*b + [True]*c expected = [(0, a), (a+b, a+b+c)] assert cbook.contiguous_regions(mask) == expected d, e = 6, 7 # Starts with True ends with False mask = mask + [False]*e assert cbook.contiguous_regions(mask) == expected # Starts with False ends with True mask = [False]*d + mask[:-e] expected = [(d, d+a), (d+a+b, d+a+b+c)] assert cbook.contiguous_regions(mask) == expected # Starts and ends with False mask = mask + [False]*e assert cbook.contiguous_regions(mask) == expected # No True in mask assert cbook.contiguous_regions([False]*5) == [] # Empty mask assert cbook.contiguous_regions([]) == []
def test_contiguous_regions(): a, b, c = 3, 4, 5 # Starts and ends with True mask = [True] * a + [False] * b + [True] * c expected = [(0, a), (a + b, a + b + c)] assert cbook.contiguous_regions(mask) == expected d, e = 6, 7 # Starts with True ends with False mask = mask + [False] * e assert cbook.contiguous_regions(mask) == expected # Starts with False ends with True mask = [False] * d + mask[:-e] expected = [(d, d + a), (d + a + b, d + a + b + c)] assert cbook.contiguous_regions(mask) == expected # Starts and ends with False mask = mask + [False] * e assert cbook.contiguous_regions(mask) == expected # No True in mask assert cbook.contiguous_regions([False] * 5) == [] # Empty mask assert cbook.contiguous_regions([]) == []
def fill_gradient(self, canvas, X, percentiles, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs): ax = canvas plots = [] if 'edgecolors' not in kwargs: kwargs['edgecolors'] = 'none' if 'facecolors' in kwargs: color = kwargs.pop('facecolors') if 'array' in kwargs: array = kwargs.pop('array') else: array = 1. - np.abs(np.linspace(-.97, .97, len(percentiles) - 1)) if 'alpha' in kwargs: alpha = kwargs.pop('alpha') else: alpha = .8 if 'cmap' in kwargs: cmap = kwargs.pop('cmap') else: cmap = LinearSegmentedColormap.from_list('WhToColor', (color, color), N=array.size) cmap._init() cmap._lut[:-3, -1] = alpha * array kwargs['facecolors'] = [cmap(i) for i in np.linspace(0, 1, cmap.N)] # pop where from kwargs where = kwargs.pop('where') if 'where' in kwargs else None # pop interpolate, which we actually do not do here! if 'interpolate' in kwargs: kwargs.pop('interpolate') def pairwise(iterable): "s -> (s0,s1), (s1,s2), (s2, s3), ..." from itertools import tee #try: # from itertools import izip as zip #except ImportError: # pass a, b = tee(iterable) next(b, None) return zip(a, b) polycol = [] for y1, y2 in pairwise(percentiles): try: from matplotlib.cbook import contiguous_regions except ImportError: from matplotlib.mlab import contiguous_regions # Handle united data, such as dates ax._process_unit_info(xdata=X, ydata=y1) ax._process_unit_info(ydata=y2) # Convert the arrays so we can work with them from numpy import ma x = ma.masked_invalid(ax.convert_xunits(X)) y1 = ma.masked_invalid(ax.convert_yunits(y1)) y2 = ma.masked_invalid(ax.convert_yunits(y2)) if y1.ndim == 0: y1 = np.ones_like(x) * y1 if y2.ndim == 0: y2 = np.ones_like(x) * y2 if where is None: where = np.ones(len(x), np.bool) else: where = np.asarray(where, np.bool) if not (x.shape == y1.shape == y2.shape == where.shape): raise ValueError("Argument dimensions are incompatible") from functools import reduce mask = reduce(ma.mask_or, [ma.getmask(a) for a in (x, y1, y2)]) if mask is not ma.nomask: where &= ~mask polys = [] for ind0, ind1 in contiguous_regions(where): xslice = x[ind0:ind1] y1slice = y1[ind0:ind1] y2slice = y2[ind0:ind1] if not len(xslice): continue N = len(xslice) p = np.zeros((2 * N + 2, 2), np.float) # the purpose of the next two lines is for when y2 is a # scalar like 0 and we want the fill to go all the way # down to 0 even if none of the y1 sample points do start = xslice[0], y2slice[0] end = xslice[-1], y2slice[-1] p[0] = start p[N + 1] = end p[1:N + 1, 0] = xslice p[1:N + 1, 1] = y1slice p[N + 2:, 0] = xslice[::-1] p[N + 2:, 1] = y2slice[::-1] polys.append(p) polycol.extend(polys) from matplotlib.collections import PolyCollection if 'zorder' not in kwargs: kwargs['zorder'] = 0 plots.append(PolyCollection(polycol, label=label, **kwargs)) ax.add_collection(plots[-1], autolim=True) ax.autoscale_view() return plots