def axes_simpplot3d(ax, p, t, pmask=None, **kwargs): """Plot a surface or volume triangulation. Parameters ---------- p : array, shape (np, 3) t : array, shape (nt, 3) or (nt, 4) pmask : callable or bool array of shape (np,) Additional keyword arguments ---------------------------- facecolor : facecolor ifacecolor : facecolor for faces exposed by pmask """ if not ax._hold: ax.cla() had_data = ax.has_data() facecolor = kwargs.pop('facecolor', (0.8, 0.9, 1.0)) ifacecolor = kwargs.pop('ifacecolor', (0.9, 0.8, 1.0)) xs, ys, zs = p.T ret = cbook.silent_list('mpl_toolkits.mplot3d.art3d.PathPatch3D') if t.shape[1] == 4: tri1 = _mkfaces(t) if pmask is not None: if isinstance(pmask, collections.Callable): pmask = pmask(p) t = t[pmask[t].any(1)] tri2 = _mkfaces(t) tri1 = tri1.intersection(tri2) tri2 = tri2.difference(tri1) c = _trimesh(ax, tri2, xs, ys, zs, facecolor=ifacecolor) ret.extend(c) else: tri1 = t if pmask is not None: if isinstance(pmask, collections.Callable): pmask = pmask(p) tri1 = t[pmask[t].any(1)] c = _trimesh(ax, tri1, xs, ys, zs, facecolor=facecolor) ret.extend(c) ax.auto_scale_xyz(xs, ys, zs, had_data) return ret
def __init__(self, ax, *args, **kwargs): """ Draw contour lines or filled regions, depending on whether keyword arg 'filled' is False (default) or True. The first argument of the initializer must be an axes object. The remaining arguments and keyword arguments are described in ContourSet.contour_doc. """ self.ax = ax self.levels = kwargs.get('levels', None) self.filled = kwargs.get('filled', False) self.linewidths = kwargs.get('linewidths', None) self.linestyles = kwargs.get('linestyles', None) self.alpha = kwargs.get('alpha', 1.0) self.origin = kwargs.get('origin', None) self.extent = kwargs.get('extent', None) cmap = kwargs.get('cmap', None) self.colors = kwargs.get('colors', None) norm = kwargs.get('norm', None) self.extend = kwargs.get('extend', 'neither') self.antialiased = kwargs.get('antialiased', True) self.nchunk = kwargs.get('nchunk', 0) self.locator = kwargs.get('locator', None) if (isinstance(norm, colors.LogNorm) or isinstance(self.locator, ticker.LogLocator)): self.logscale = True if norm is None: norm = colors.LogNorm() if self.extend is not 'neither': raise ValueError( 'extend kwarg does not work yet with log scale') else: self.logscale = False if self.origin is not None: assert (self.origin in ['lower', 'upper', 'image']) if self.extent is not None: assert (len(self.extent) == 4) if cmap is not None: assert (isinstance(cmap, colors.Colormap)) if self.colors is not None and cmap is not None: raise ValueError('Either colors or cmap must be None') if self.origin == 'image': self.origin = mpl.rcParams['image.origin'] if isinstance(args[0], ContourSet): C = args[0].Cntr if self.levels is None: self.levels = args[0].levels else: x, y, z = self._contour_args(*args) x0 = ma.minimum(x) x1 = ma.maximum(x) y0 = ma.minimum(y) y1 = ma.maximum(y) self.ax.update_datalim([(x0, y0), (x1, y1)]) self.ax.autoscale_view() _mask = ma.getmask(z) if _mask is ma.nomask: _mask = None C = _cntr.Cntr(x, y, z.filled(), _mask) self.Cntr = C self._process_levels() if self.colors is not None: cmap = colors.ListedColormap(self.colors, N=len(self.layers)) if self.filled: self.collections = cbook.silent_list('collections.PathCollection') else: self.collections = cbook.silent_list('collections.LineCollection') # label lists must be initialized here self.labelTexts = [] self.labelCValues = [] kw = {'cmap': cmap} if norm is not None: kw['norm'] = norm cm.ScalarMappable.__init__(self, **kw) # sets self.cmap; self._process_colors() if self.filled: if self.linewidths is not None: warnings.warn('linewidths is ignored by contourf') lowers = self._levels[:-1] uppers = self._levels[1:] for level, level_upper in zip(lowers, uppers): nlist = C.trace(level, level_upper, nchunk=self.nchunk) nseg = len(nlist) // 2 segs = nlist[:nseg] kinds = nlist[nseg:] paths = self._make_paths(segs, kinds) col = collections.PathCollection( paths, antialiaseds=(self.antialiased, ), edgecolors='none', alpha=self.alpha) self.ax.add_collection(col) self.collections.append(col) else: tlinewidths = self._process_linewidths() self.tlinewidths = tlinewidths tlinestyles = self._process_linestyles() for level, width, lstyle in zip(self.levels, tlinewidths, tlinestyles): nlist = C.trace(level) nseg = len(nlist) // 2 segs = nlist[:nseg] #kinds = nlist[nseg:] col = collections.LineCollection(segs, linewidths=width, linestyle=lstyle, alpha=self.alpha) col.set_label('_nolegend_') self.ax.add_collection(col, False) self.collections.append(col) self.changed() # set the colors
def clabel(self, *args, **kwargs): """ call signature:: clabel(cs, **kwargs) adds labels to line contours in *cs*, where *cs* is a :class:`~matplotlib.contour.ContourSet` object returned by contour. :: clabel(cs, v, **kwargs) only labels contours listed in *v*. Optional keyword arguments: *fontsize*: See http://matplotlib.sf.net/fonts.html *colors*: - if *None*, the color of each label matches the color of the corresponding contour - if one string color, e.g. *colors* = 'r' or *colors* = 'red', all labels will be plotted in this color - if a tuple of matplotlib color args (string, float, rgb, etc), different labels will be plotted in different colors in the order specified *inline*: controls whether the underlying contour is removed or not. Default is *True*. *inline_spacing*: space in pixels to leave on each side of label when placing inline. Defaults to 5. This spacing will be exact for labels at locations where the contour is straight, less so for labels on curved contours. *fmt*: a format string for the label. Default is '%1.3f' Alternatively, this can be a dictionary matching contour levels with arbitrary strings to use for each contour level (i.e., fmt[level]=string) *manual*: if *True*, contour labels will be placed manually using mouse clicks. Click the first button near a contour to add a label, click the second button (or potentially both mouse buttons at once) to finish adding labels. The third button can be used to remove the last label added, but only if labels are not inline. Alternatively, the keyboard can be used to select label locations (enter to end label placement, delete or backspace act like the third mouse button, and any other key will select a label location). *rightside_up*: if *True* (default), label rotations will always be plus or minus 90 degrees from level. *use_clabeltext*: if *True* (default is False), ClabelText class (instead of matplotlib.Text) is used to create labels. ClabelText recalculates rotation angles of texts during the drawing time, therefore this can be used if aspect of the axes changes. .. plot:: mpl_examples/pylab_examples/contour_demo.py """ """ NOTES on how this all works: clabel basically takes the input arguments and uses them to add a list of "label specific" attributes to the ContourSet object. These attributes are all of the form label* and names should be fairly self explanatory. Once these attributes are set, clabel passes control to the labels method (case of automatic label placement) or BlockingContourLabeler (case of manual label placement). """ fontsize = kwargs.get('fontsize', None) inline = kwargs.get('inline', 1) inline_spacing = kwargs.get('inline_spacing', 5) self.labelFmt = kwargs.get('fmt', '%1.3f') _colors = kwargs.get('colors', None) self._use_clabeltext = kwargs.get('use_clabeltext', False) # Detect if manual selection is desired and remove from argument list self.labelManual = kwargs.get('manual', False) self.rightside_up = kwargs.get('rightside_up', True) if len(args) == 0: levels = self.levels indices = range(len(self.levels)) elif len(args) == 1: levlabs = list(args[0]) indices, levels = [], [] for i, lev in enumerate(self.levels): if lev in levlabs: indices.append(i) levels.append(lev) if len(levels) < len(levlabs): msg = "Specified levels " + str(levlabs) msg += "\n don't match available levels " msg += str(self.levels) raise ValueError(msg) else: raise TypeError("Illegal arguments to clabel, see help(clabel)") self.labelLevelList = levels self.labelIndiceList = indices self.labelFontProps = font_manager.FontProperties() if fontsize == None: font_size = int(self.labelFontProps.get_size_in_points()) else: if type(fontsize) not in [int, float, str]: raise TypeError("Font size must be an integer number.") # Can't it be floating point, as indicated in line above? else: if type(fontsize) == str: font_size = int(self.labelFontProps.get_size_in_points()) else: self.labelFontProps.set_size(fontsize) font_size = fontsize self.labelFontSizeList = [font_size] * len(levels) if _colors == None: self.labelMappable = self self.labelCValueList = np.take(self.cvalues, self.labelIndiceList) else: cmap = colors.ListedColormap(_colors, N=len(self.labelLevelList)) self.labelCValueList = range(len(self.labelLevelList)) self.labelMappable = cm.ScalarMappable(cmap=cmap, norm=colors.NoNorm()) #self.labelTexts = [] # Initialized in ContourSet.__init__ #self.labelCValues = [] # same self.labelXYs = [] if self.labelManual: print 'Select label locations manually using first mouse button.' print 'End manual selection with second mouse button.' if not inline: print 'Remove last label by clicking third mouse button.' blocking_contour_labeler = BlockingContourLabeler(self) blocking_contour_labeler(inline, inline_spacing) else: self.labels(inline, inline_spacing) # Hold on to some old attribute names. These are depricated and will # be removed in the near future (sometime after 2008-08-01), but keeping # for now for backwards compatibility self.cl = self.labelTexts self.cl_xy = self.labelXYs self.cl_cvalues = self.labelCValues self.labelTextsList = cbook.silent_list('text.Text', self.labelTexts) return self.labelTextsList
def clabel(self, *args, **kwargs): """ call signature:: clabel(cs, **kwargs) adds labels to line contours in *cs*, where *cs* is a :class:`~matplotlib.contour.ContourSet` object returned by contour. :: clabel(cs, v, **kwargs) only labels contours listed in *v*. Optional keyword arguments: *fontsize*: See http://matplotlib.sf.net/fonts.html .. TODO: Update this link to new fonts document *colors*: - if *None*, the color of each label matches the color of the corresponding contour - if one string color, e.g. *colors* = 'r' or *colors* = 'red', all labels will be plotted in this color - if a tuple of matplotlib color args (string, float, rgb, etc), different labels will be plotted in different colors in the order specified *inline*: controls whether the underlying contour is removed or not. Default is *True*. *inline_spacing*: space in pixels to leave on each side of label when placing inline. Defaults to 5. This spacing will be exact for labels at locations where the contour is straight, less so for labels on curved contours. *fmt*: a format string for the label. Default is '%1.3f' Alternatively, this can be a dictionary matching contour levels with arbitrary strings to use for each contour level (i.e., fmt[level]=string) *manual*: if *True*, contour labels will be placed manually using mouse clicks. Click the first button near a contour to add a label, click the second button (or potentially both mouse buttons at once) to finish adding labels. The third button can be used to remove the last label added, but only if labels are not inline. """ """ NOTES on how this all works: clabel basically takes the input arguments and uses them to add a list of "label specific" attributes to the ContourSet object. These attributes currently include: label_indices, label_levels, label_cvalues, fp (font properties), fslist (fontsize list), label_mappable, cl (list of text objects of labels), cl_xy (coordinates of labels), cl_cvalues (color values of the actual labels). Note that these property names do not conform to the standards set for coding matplotlib and I (DMK) eventually plan on changing them so that they are clearer and conform to standards. Once these attributes are set, clabel passes control to the labels method (case of automatic label placement) or BlockingContourLabeler (case of manual label placement). """ fontsize = kwargs.get('fontsize', None) inline = kwargs.get('inline', 1) inline_spacing = kwargs.get('inline_spacing', 5) self.labelFmt = kwargs.get('fmt', '%1.3f') _colors = kwargs.get('colors', None) # Detect if manual selection is desired and remove from argument list self.labelManual=kwargs.get('manual',False) if len(args) == 0: levels = self.levels indices = range(len(self.levels)) elif len(args) == 1: levlabs = list(args[0]) indices, levels = [], [] for i, lev in enumerate(self.levels): if lev in levlabs: indices.append(i) levels.append(lev) if len(levels) < len(levlabs): msg = "Specified levels " + str(levlabs) msg += "\n don't match available levels " msg += str(self.levels) raise ValueError(msg) else: raise TypeError("Illegal arguments to clabel, see help(clabel)") self.labelLevelList = levels self.labelIndiceList = indices self.labelFontProps = font_manager.FontProperties() if fontsize == None: font_size = int(self.labelFontProps.get_size_in_points()) else: if type(fontsize) not in [int, float, str]: raise TypeError("Font size must be an integer number.") # Can't it be floating point, as indicated in line above? else: if type(fontsize) == str: font_size = int(self.labelFontProps.get_size_in_points()) else: self.labelFontProps.set_size(fontsize) font_size = fontsize self.labelFontSizeList = [font_size] * len(levels) if _colors == None: self.labelMappable = self self.labelCValueList = np.take(self.cvalues, self.labelIndiceList) else: cmap = colors.ListedColormap(_colors, N=len(self.labelLevelList)) self.labelCValueList = range(len(self.labelLevelList)) self.labelMappable = cm.ScalarMappable(cmap = cmap, norm = colors.NoNorm()) #self.labelTexts = [] # Initialized in ContourSet.__init__ #self.labelCValues = [] # same self.labelXYs = [] if self.labelManual: print 'Select label locations manually using first mouse button.' print 'End manual selection with second mouse button.' if not inline: print 'Remove last label by clicking third mouse button.' blocking_contour_labeler = BlockingContourLabeler(self) blocking_contour_labeler(inline,inline_spacing) else: self.labels(inline,inline_spacing) # Hold on to some old attribute names. These are depricated and will # be moved in the near future (sometime after 2008-08-01), but keeping # for now for backwards compatibility self.cl = self.labelTexts self.cl_xy = self.labelXYs self.cl_cvalues = self.labelCValues self.labelTextsList = cbook.silent_list('text.Text', self.labelTexts) return self.labelTextsList
def get_patches(self): 'return a list of patch instances in the legend' return silent_list( 'Patch', [h for h in self.legendHandles if isinstance(h, Patch)])
def get_patches(self): 'return a list of patch instances in the legend' return silent_list('Patch', [h for h in self.legendHandles if isinstance(h, Patch)])
def get_texts(self): "return a list of text.Text instance in the legend" return silent_list("Text", self.texts)
def multihist(xvals, bins=10, normed=0, bottom=None, align='edge', orientation='vertical', width=None, log=False, type='overlap',gap=None, patch_kwargs=None, labels=None, **kwargs): #some integrity checks up front if type == 'bi' and len(xvals) != 2: raise ValueError('need exactly two data sets for "bi" multihist: %d given' % len(xvals)) if patch_kwargs is not None and len(patch_kwargs) != len(xvals): raise ValueError('need same number of patch kwargs and data sets') #calculate the common bins, more or less stolen from numpy.histogram xvals = [npy.asarray(x).ravel() for x in xvals] if not npy.iterable(bins): mn = float(min([x.min() for x in xvals])) mx = float(max([x.max() for x in xvals])) if mn == mx: mn -= 0.5 mx += 0.5 bins = npy.linspace(mn, mx, bins, endpoint=False) #make the histograms using the common bins xn = [] for x in xvals: n, bins2 = npy.histogram(x, bins, range=None, normed=normed) xn.append(n) #build the patches parameters depending on type argument if width is None: width = 0.9*(bins[1]-bins[0]) delta = 0 offset = 0 paint_width = width stay_on_top = True if type == 'beside': if npy.iterable(width): raise ValueError('no sequence of widths allowed for "beside" multihist') width /= len(xn) delta = width if align == 'edge': offset = 0 elif align == 'center': offset = ((len(xn) / -2.0 + 0.5) * width) else: raise ValueError('invalid alignment: %s' % align) if gap is None: gap = 0 paint_width = width - gap elif type == 'bi': stay_on_top = False elif type != 'overlap': raise ValueError('invalid multihist type: %s' % type) #build the patches patch_list = [] on_top = True for n in xn: obins = [b + offset for b in bins] if on_top: rn = n else: rn = [-v for v in n] if orientation == 'horizontal': patches = pylab.barh(obins, rn, height=paint_width, left=bottom, align=align, log=log) elif orientation == 'vertical': patches = pylab.bar(obins[:-1], rn, width=paint_width, bottom=bottom, align=align, log=log, linewidth=0) else: raise ValueError('invalid orientation: %s' % orientation) patch_list.append(cbook.silent_list('Patch', patches)) offset += delta on_top = on_top and stay_on_top for i in range(len(patch_list)): if patch_kwargs == None: kwa = kwargs else: kwa = patch_kwargs[i] if labels: lab = labels[i] for p in patch_list[i]: p.update(kwa) if labels: patch_list[i][0].update({"label":lab}) return xn, bins, patch_list
def hist(self, x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, **kwargs): """ call signature:: hist(x, bins=10, range=None, normed=False, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, **kwargs) Compute and draw the histogram of *x*. The return value is a tuple (*n*, *bins*, *patches*) or ([*n0*, *n1*, ...], *bins*, [*patches0*, *patches1*,...]) if the input contains multiple data. Multiple data can be provided via *x* as a list of datasets of potentially different length ([*x0*, *x1*, ...]), or as a 2-D ndarray in which each column is a dataset. Note that the ndarray form is transposed relative to the list form. Masked arrays are not supported at present. Keyword arguments: *bins*: Either an integer number of bins or a sequence giving the bins. If *bins* is an integer, *bins* + 1 bin edges will be returned, consistent with :func:`numpy.histogram` for numpy version >= 1.3, and with the *new* = True argument in earlier versions. Unequally spaced bins are supported if *bins* is a sequence. *range*: The lower and upper range of the bins. Lower and upper outliers are ignored. If not provided, *range* is (x.min(), x.max()). Range has no effect if *bins* is a sequence. If *bins* is a sequence or *range* is specified, autoscaling is based on the specified bin range instead of the range of x. *normed*: If *True*, the first element of the return tuple will be the counts normalized to form a probability density, i.e., ``n/(len(x)*dbin)``. In a probability density, the integral of the histogram should be 1; you can verify that with a trapezoidal integration of the probability density function:: pdf, bins, patches = ax.hist(...) print np.sum(pdf * np.diff(bins)) .. Note:: Until numpy release 1.5, the underlying numpy histogram function was incorrect with *normed*=*True* if bin sizes were unequal. MPL inherited that error. It is now corrected within MPL when using earlier numpy versions *weights* An array of weights, of the same shape as *x*. Each value in *x* only contributes its associated weight towards the bin count (instead of 1). If *normed* is True, the weights are normalized, so that the integral of the density over the range remains 1. *cumulative*: If *True*, then a histogram is computed where each bin gives the counts in that bin plus all bins for smaller values. The last bin gives the total number of datapoints. If *normed* is also *True* then the histogram is normalized such that the last bin equals 1. If *cumulative* evaluates to less than 0 (e.g. -1), the direction of accumulation is reversed. In this case, if *normed* is also *True*, then the histogram is normalized such that the first bin equals 1. *histtype*: [ 'bar' | 'barstacked' | 'step' | 'stepfilled' ] The type of histogram to draw. - 'bar' is a traditional bar-type histogram. If multiple data are given the bars are aranged side by side. - 'barstacked' is a bar-type histogram where multiple data are stacked on top of each other. - 'step' generates a lineplot that is by default unfilled. - 'stepfilled' generates a lineplot that is by default filled. *align*: ['left' | 'mid' | 'right' ] Controls how the histogram is plotted. - 'left': bars are centered on the left bin edges. - 'mid': bars are centered between the bin edges. - 'right': bars are centered on the right bin edges. *orientation*: [ 'horizontal' | 'vertical' ] If 'horizontal', :func:`~matplotlib.pyplot.barh` will be used for bar-type histograms and the *bottom* kwarg will be the left edges. *rwidth*: The relative width of the bars as a fraction of the bin width. If *None*, automatically compute the width. Ignored if *histtype* = 'step' or 'stepfilled'. *log*: If *True*, the histogram axis will be set to a log scale. If *log* is *True* and *x* is a 1D array, empty bins will be filtered out and only the non-empty (*n*, *bins*, *patches*) will be returned. *color*: Color spec or sequence of color specs, one per dataset. Default (*None*) uses the standard line color sequence. *label*: String, or sequence of strings to match multiple datasets. Bar charts yield multiple patches per dataset, but only the first gets the label, so that the legend command will work as expected:: ax.hist(10+2*np.random.randn(1000), label='men') ax.hist(12+3*np.random.randn(1000), label='women', alpha=0.5) ax.legend() kwargs are used to update the properties of the :class:`~matplotlib.patches.Patch` instances returned by *hist*: %(Patch)s **Example:** .. plot:: mpl_examples/pylab_examples/histogram_demo.py """ if not self._hold: self.cla() # NOTE: the range keyword overwrites the built-in func range !!! # needs to be fixed in numpy !!! # Validate string inputs here so we don't have to clutter # subsequent code. if histtype not in ['bar', 'barstacked', 'step', 'stepfilled']: raise ValueError("histtype %s is not recognized" % histtype) if align not in ['left', 'mid', 'right']: raise ValueError("align kwarg %s is not recognized" % align) if orientation not in [ 'horizontal', 'vertical']: raise ValueError( "orientation kwarg %s is not recognized" % orientation) if kwargs.get('width') is not None: raise DeprecationWarning( 'hist now uses the rwidth to give relative width ' 'and not absolute width') # Massage 'x' for processing. # NOTE: Be sure any changes here is also done below to 'weights' if isinstance(x, np.ndarray) or not iterable(x[0]): # TODO: support masked arrays; x = np.asarray(x) if x.ndim == 2: x = x.T # 2-D input with columns as datasets; switch to rows elif x.ndim == 1: x = x.reshape(1, x.shape[0]) # new view, single row else: raise ValueError("x must be 1D or 2D") if x.shape[1] < x.shape[0]: warnings.warn('2D hist input should be nsamples x nvariables;\n ' 'this looks transposed (shape is %d x %d)' % x.shape[::-1]) else: # multiple hist with data of different length x = [np.array(xi) for xi in x] nx = len(x) # number of datasets if color is None: color = [next(self._get_lines.color_cycle) for i in range(nx)] else: color = mcolors.colorConverter.to_rgba_array(color) if len(color) != nx: raise ValueError("color kwarg must have one color per dataset") # We need to do to 'weights' what was done to 'x' if weights is not None: if isinstance(weights, np.ndarray) or not iterable(weights[0]) : w = np.array(weights) if w.ndim == 2: w = w.T elif w.ndim == 1: w.shape = (1, w.shape[0]) else: raise ValueError("weights must be 1D or 2D") else: w = [np.array(wi) for wi in weights] if len(w) != nx: raise ValueError('weights should have the same shape as x') for i in range(nx): if len(w[i]) != len(x[i]): raise ValueError( 'weights should have the same shape as x') else: w = [None]*nx # Save autoscale state for later restoration; turn autoscaling # off so we can do it all a single time at the end, instead # of having it done by bar or fill and then having to be redone. _saved_autoscalex = self.get_autoscalex_on() _saved_autoscaley = self.get_autoscaley_on() self.set_autoscalex_on(False) self.set_autoscaley_on(False) # Save the datalimits for the same reason: _saved_bounds = self.dataLim.bounds # Check whether bins or range are given explicitly. In that # case use those values for autoscaling. binsgiven = (cbook.iterable(bins) or range != None) # If bins are not specified either explicitly or via range, # we need to figure out the range required for all datasets, # and supply that to np.histogram. if not binsgiven: xmin = np.inf xmax = -np.inf for xi in x: xmin = min(xmin, xi.min()) xmax = max(xmax, xi.max()) range = (xmin, xmax) #hist_kwargs = dict(range=range, normed=bool(normed)) # We will handle the normed kwarg within mpl until we # get to the point of requiring numpy >= 1.5. hist_kwargs = dict(range=range) if np.__version__ < "1.3": # version 1.1 and 1.2 hist_kwargs['new'] = True n = [] for i in range(nx): # this will automatically overwrite bins, # so that each histogram uses the same bins m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs) if normed: db = np.diff(bins) m = (m.astype(float) / db) / m.sum() n.append(m) if normed and db.std() > 0.01 * db.mean(): warnings.warn(""" This release fixes a normalization bug in the NumPy histogram function prior to version 1.5, occuring with non-uniform bin widths. The returned and plotted value is now a density: n / (N * bin width), where n is the bin count and N the total number of points. """) if cumulative: slc = slice(None) if cbook.is_numlike(cumulative) and cumulative < 0: slc = slice(None,None,-1) if normed: n = [(m * np.diff(bins))[slc].cumsum()[slc] for m in n] else: n = [m[slc].cumsum()[slc] for m in n] patches = [] if histtype.startswith('bar'): totwidth = np.diff(bins) if rwidth is not None: dr = min(1.0, max(0.0, rwidth)) elif len(n)>1: dr = 0.8 else: dr = 1.0 if histtype=='bar': width = dr*totwidth/nx dw = width if nx > 1: boffset = -0.5*dr*totwidth*(1.0-1.0/nx) else: boffset = 0.0 stacked = False elif histtype=='barstacked': width = dr*totwidth boffset, dw = 0.0, 0.0 stacked = True if align == 'mid' or align == 'edge': boffset += 0.5*totwidth elif align == 'right': boffset += totwidth if orientation == 'horizontal': _barfunc = self.barh else: # orientation == 'vertical' _barfunc = self.bar for m, c in zip(n, color): patch = _barfunc(bins[:-1]+boffset, m, width, bottom, align='center', log=log, color=c) patches.append(patch) if stacked: if bottom is None: bottom = 0.0 bottom += m boffset += dw elif histtype.startswith('step'): x = np.zeros( 2*len(bins), np.float ) y = np.zeros( 2*len(bins), np.float ) x[0::2], x[1::2] = bins, bins # FIX FIX FIX # This is the only real change. # minimum = min(bins) if log is True: minimum = 1.0 elif log: minimum = float(log) else: minimum = 0.0 # FIX FIX FIX end if align == 'left' or align == 'center': x -= 0.5*(bins[1]-bins[0]) elif align == 'right': x += 0.5*(bins[1]-bins[0]) if log: y[0],y[-1] = minimum, minimum if orientation == 'horizontal': self.set_xscale('log') else: # orientation == 'vertical' self.set_yscale('log') fill = (histtype == 'stepfilled') for m, c in zip(n, color): y[1:-1:2], y[2::2] = m, m if log: y[y<minimum]=minimum if orientation == 'horizontal': x,y = y,x if fill: patches.append( self.fill(x, y, closed=False, facecolor=c) ) else: patches.append( self.fill(x, y, closed=False, edgecolor=c, fill=False) ) # adopted from adjust_x/ylim part of the bar method if orientation == 'horizontal': xmin0 = max(_saved_bounds[0]*0.9, minimum) xmax = self.dataLim.intervalx[1] for m in n: xmin = np.amin(m[m!=0]) # filter out the 0 height bins xmin = max(xmin*0.9, minimum) xmin = min(xmin0, xmin) self.dataLim.intervalx = (xmin, xmax) elif orientation == 'vertical': ymin0 = max(_saved_bounds[1]*0.9, minimum) ymax = self.dataLim.intervaly[1] for m in n: ymin = np.amin(m[m!=0]) # filter out the 0 height bins ymin = max(ymin*0.9, minimum) ymin = min(ymin0, ymin) self.dataLim.intervaly = (ymin, ymax) if label is None: labels = ['_nolegend_'] elif is_string_like(label): labels = [label] elif is_sequence_of_strings(label): labels = list(label) else: raise ValueError( 'invalid label: must be string or sequence of strings') if len(labels) < nx: labels += ['_nolegend_'] * (nx - len(labels)) for (patch, lbl) in zip(patches, labels): for p in patch: p.update(kwargs) p.set_label(lbl) lbl = '_nolegend_' if binsgiven: if orientation == 'vertical': self.update_datalim([(bins[0],0), (bins[-1],0)], updatey=False) else: self.update_datalim([(0,bins[0]), (0,bins[-1])], updatex=False) self.set_autoscalex_on(_saved_autoscalex) self.set_autoscaley_on(_saved_autoscaley) self.autoscale_view() if nx == 1: return n[0], bins, cbook.silent_list('Patch', patches[0]) else: return n, bins, cbook.silent_list('Lists of Patches', patches)
def clabel(self, *args, **kwargs): """ clabel(CS, **kwargs) - add labels to line contours in CS, where CS is a ContourSet object returned by contour. clabel(CS, V, **kwargs) - only label contours listed in V keyword arguments: * fontsize = None: as described in http://matplotlib.sf.net/fonts.html * colors = None: - a tuple of matplotlib color args (string, float, rgb, etc), different labels will be plotted in different colors in the order specified - one string color, e.g. colors = 'r' or colors = 'red', all labels will be plotted in this color - if colors == None, the color of each label matches the color of the corresponding contour * inline = True: controls whether the underlying contour is removed (inline = True) or not (False) * fmt = '%1.3f': a format string for the label """ fontsize = kwargs.get('fontsize', None) inline = kwargs.get('inline', 1) self.fmt = kwargs.get('fmt', '%1.3f') _colors = kwargs.get('colors', None) if len(args) == 0: levels = self.levels indices = range(len(self.levels)) elif len(args) == 1: levlabs = list(args[0]) indices, levels = [], [] for i, lev in enumerate(self.levels): if lev in levlabs: indices.append(i) levels.append(lev) if len(levels) < len(levlabs): msg = "Specified levels " + str(levlabs) msg += "\n don't match available levels " msg += str(self.levels) raise ValueError(msg) else: raise TypeError("Illegal arguments to clabel, see help(clabel)") self.label_levels = levels self.label_indices = indices self.fp = font_manager.FontProperties() if fontsize == None: font_size = int(self.fp.get_size_in_points()) else: if type(fontsize) not in [int, float, str]: raise TypeError("Font size must be an integer number.") # Can't it be floating point, as indicated in line above? else: if type(fontsize) == str: font_size = int(self.fp.get_size_in_points()) else: self.fp.set_size(fontsize) font_size = fontsize self.fslist = [font_size] * len(levels) if _colors == None: self.label_mappable = self self.label_cvalues = npy.take(self.cvalues, self.label_indices) else: cmap = colors.ListedColormap(_colors, N=len(self.label_levels)) self.label_cvalues = range(len(self.label_levels)) self.label_mappable = cm.ScalarMappable(cmap = cmap, norm = colors.NoNorm()) #self.cl = [] # Initialized in ContourSet.__init__ #self.cl_cvalues = [] # same self.cl_xy = [] self.labels(inline) for label in self.cl: self.ax.add_artist(label) self.label_list = cbook.silent_list('text.Text', self.cl) return self.label_list
def clabel(self, *args, **kwargs): """ call signature:: clabel(cs, **kwargs) adds labels to line contours in *cs*, where *cs* is a :class:`~matplotlib.contour.ContourSet` object returned by contour. :: clabel(cs, v, **kwargs) only labels contours listed in *v*. Optional keyword arguments: *fontsize*: See http://matplotlib.sf.net/fonts.html .. TODO: Update this link to new fonts document *colors*: - if *None*, the color of each label matches the color of the corresponding contour - if one string color, e.g. *colors* = 'r' or *colors* = 'red', all labels will be plotted in this color - if a tuple of matplotlib color args (string, float, rgb, etc), different labels will be plotted in different colors in the order specified *inline*: controls whether the underlying contour is removed or not. Default is *True*. *fmt*: a format string for the label. Default is '%1.3f' """ fontsize = kwargs.get('fontsize', None) inline = kwargs.get('inline', 1) self.fmt = kwargs.get('fmt', '%1.3f') _colors = kwargs.get('colors', None) if len(args) == 0: levels = self.levels indices = range(len(self.levels)) elif len(args) == 1: levlabs = list(args[0]) indices, levels = [], [] for i, lev in enumerate(self.levels): if lev in levlabs: indices.append(i) levels.append(lev) if len(levels) < len(levlabs): msg = "Specified levels " + str(levlabs) msg += "\n don't match available levels " msg += str(self.levels) raise ValueError(msg) else: raise TypeError("Illegal arguments to clabel, see help(clabel)") self.label_levels = levels self.label_indices = indices self.fp = font_manager.FontProperties() if fontsize == None: font_size = int(self.fp.get_size_in_points()) else: if type(fontsize) not in [int, float, str]: raise TypeError("Font size must be an integer number.") # Can't it be floating point, as indicated in line above? else: if type(fontsize) == str: font_size = int(self.fp.get_size_in_points()) else: self.fp.set_size(fontsize) font_size = fontsize self.fslist = [font_size] * len(levels) if _colors == None: self.label_mappable = self self.label_cvalues = np.take(self.cvalues, self.label_indices) else: cmap = colors.ListedColormap(_colors, N=len(self.label_levels)) self.label_cvalues = range(len(self.label_levels)) self.label_mappable = cm.ScalarMappable(cmap = cmap, norm = colors.NoNorm()) #self.cl = [] # Initialized in ContourSet.__init__ #self.cl_cvalues = [] # same self.cl_xy = [] self.labels(inline) for label in self.cl: self.ax.add_artist(label) self.label_list = cbook.silent_list('text.Text', self.cl) return self.label_list
def clabel(self, *args, **kwargs): """ call signature:: clabel(cs, **kwargs) adds labels to line contours in *cs*, where *cs* is a :class:`~matplotlib.contour.ContourSet` object returned by contour. :: clabel(cs, v, **kwargs) only labels contours listed in *v*. Optional keyword arguments: *fontsize*: See http://matplotlib.sf.net/fonts.html .. TODO: Update this link to new fonts document *colors*: - if *None*, the color of each label matches the color of the corresponding contour - if one string color, e.g. *colors* = 'r' or *colors* = 'red', all labels will be plotted in this color - if a tuple of matplotlib color args (string, float, rgb, etc), different labels will be plotted in different colors in the order specified *inline*: controls whether the underlying contour is removed or not. Default is *True*. *fmt*: a format string for the label. Default is '%1.3f' """ fontsize = kwargs.get('fontsize', None) inline = kwargs.get('inline', 1) self.fmt = kwargs.get('fmt', '%1.3f') _colors = kwargs.get('colors', None) if len(args) == 0: levels = self.levels indices = range(len(self.levels)) elif len(args) == 1: levlabs = list(args[0]) indices, levels = [], [] for i, lev in enumerate(self.levels): if lev in levlabs: indices.append(i) levels.append(lev) if len(levels) < len(levlabs): msg = "Specified levels " + str(levlabs) msg += "\n don't match available levels " msg += str(self.levels) raise ValueError(msg) else: raise TypeError("Illegal arguments to clabel, see help(clabel)") self.label_levels = levels self.label_indices = indices self.fp = font_manager.FontProperties() if fontsize == None: font_size = int(self.fp.get_size_in_points()) else: if type(fontsize) not in [int, float, str]: raise TypeError("Font size must be an integer number.") # Can't it be floating point, as indicated in line above? else: if type(fontsize) == str: font_size = int(self.fp.get_size_in_points()) else: self.fp.set_size(fontsize) font_size = fontsize self.fslist = [font_size] * len(levels) if _colors == None: self.label_mappable = self self.label_cvalues = np.take(self.cvalues, self.label_indices) else: cmap = colors.ListedColormap(_colors, N=len(self.label_levels)) self.label_cvalues = range(len(self.label_levels)) self.label_mappable = cm.ScalarMappable(cmap=cmap, norm=colors.NoNorm()) #self.cl = [] # Initialized in ContourSet.__init__ #self.cl_cvalues = [] # same self.cl_xy = [] self.labels(inline) for label in self.cl: self.ax.add_artist(label) self.label_list = cbook.silent_list('text.Text', self.cl) return self.label_list
def __init__(self, ax, *args, **kwargs): """ Draw contour lines or filled regions, depending on whether keyword arg 'filled' is False (default) or True. The first argument of the initializer must be an axes object. The remaining arguments and keyword arguments are described in ContourSet.contour_doc. """ self.ax = ax self.levels = kwargs.get("levels", None) self.filled = kwargs.get("filled", False) self.linewidths = kwargs.get("linewidths", None) self.linestyles = kwargs.get("linestyles", None) self.alpha = kwargs.get("alpha", 1.0) self.origin = kwargs.get("origin", None) self.extent = kwargs.get("extent", None) cmap = kwargs.get("cmap", None) self.colors = kwargs.get("colors", None) norm = kwargs.get("norm", None) self.extend = kwargs.get("extend", "neither") self.antialiased = kwargs.get("antialiased", True) self.nchunk = kwargs.get("nchunk", 0) self.locator = kwargs.get("locator", None) if isinstance(norm, colors.LogNorm) or isinstance(self.locator, ticker.LogLocator): self.logscale = True if norm is None: norm = colors.LogNorm() if self.extend is not "neither": raise ValueError("extend kwarg does not work yet with log scale") else: self.logscale = False if self.origin is not None: assert self.origin in ["lower", "upper", "image"] if self.extent is not None: assert len(self.extent) == 4 if cmap is not None: assert isinstance(cmap, colors.Colormap) if self.colors is not None and cmap is not None: raise ValueError("Either colors or cmap must be None") if self.origin == "image": self.origin = mpl.rcParams["image.origin"] x, y, z = self._contour_args(*args) # also sets self.levels, # self.layers if self.colors is not None: cmap = colors.ListedColormap(self.colors, N=len(self.layers)) if self.filled: self.collections = cbook.silent_list("collections.PolyCollection") else: self.collections = cbook.silent_list("collections.LineCollection") # label lists must be initialized here self.labelTexts = [] self.labelCValues = [] kw = {"cmap": cmap} if norm is not None: kw["norm"] = norm cm.ScalarMappable.__init__(self, **kw) # sets self.cmap; self._process_colors() _mask = ma.getmask(z) if _mask is ma.nomask: _mask = None if self.filled: if self.linewidths is not None: warnings.warn("linewidths is ignored by contourf") C = _cntr.Cntr(x, y, z.filled(), _mask) lowers = self._levels[:-1] uppers = self._levels[1:] for level, level_upper in zip(lowers, uppers): nlist = C.trace(level, level_upper, points=0, nchunk=self.nchunk) col = collections.PolyCollection( nlist, antialiaseds=(self.antialiased,), edgecolors="none", alpha=self.alpha ) self.ax.add_collection(col) self.collections.append(col) else: tlinewidths = self._process_linewidths() self.tlinewidths = tlinewidths tlinestyles = self._process_linestyles() C = _cntr.Cntr(x, y, z.filled(), _mask) for level, width, lstyle in zip(self.levels, tlinewidths, tlinestyles): nlist = C.trace(level, points=0) col = collections.LineCollection(nlist, linewidths=width, linestyle=lstyle, alpha=self.alpha) col.set_label("_nolegend_") self.ax.add_collection(col, False) self.collections.append(col) self.changed() # set the colors x0 = ma.minimum(x) x1 = ma.maximum(x) y0 = ma.minimum(y) y1 = ma.maximum(y) self.ax.update_datalim([(x0, y0), (x1, y1)]) self.ax.autoscale_view()
def get_patches(self): r"""Return the list of `~.patches.Patch`\s in the legend.""" return silent_list('Patch', [h for h in self.legendHandles if isinstance(h, Patch)])
def clabel(self, *args, **kwargs): """ call signature:: clabel(cs, **kwargs) adds labels to line contours in *cs*, where *cs* is a :class:`~matplotlib.contour.ContourSet` object returned by contour. :: clabel(cs, v, **kwargs) only labels contours listed in *v*. Optional keyword arguments: *fontsize*: See http://matplotlib.sf.net/fonts.html *colors*: - if *None*, the color of each label matches the color of the corresponding contour - if one string color, e.g. *colors* = 'r' or *colors* = 'red', all labels will be plotted in this color - if a tuple of matplotlib color args (string, float, rgb, etc), different labels will be plotted in different colors in the order specified *inline*: controls whether the underlying contour is removed or not. Default is *True*. *inline_spacing*: space in pixels to leave on each side of label when placing inline. Defaults to 5. This spacing will be exact for labels at locations where the contour is straight, less so for labels on curved contours. *fmt*: a format string for the label. Default is '%1.3f' Alternatively, this can be a dictionary matching contour levels with arbitrary strings to use for each contour level (i.e., fmt[level]=string) *manual*: if *True*, contour labels will be placed manually using mouse clicks. Click the first button near a contour to add a label, click the second button (or potentially both mouse buttons at once) to finish adding labels. The third button can be used to remove the last label added, but only if labels are not inline. Alternatively, the keyboard can be used to select label locations (enter to end label placement, delete or backspace act like the third mouse button, and any other key will select a label location). *rightside_up*: if *True* (default), label rotations will always be plus or minus 90 degrees from level. .. plot:: mpl_examples/pylab_examples/contour_demo.py """ """ NOTES on how this all works: clabel basically takes the input arguments and uses them to add a list of "label specific" attributes to the ContourSet object. These attributes are all of the form label* and names should be fairly self explanatory. Once these attributes are set, clabel passes control to the labels method (case of automatic label placement) or BlockingContourLabeler (case of manual label placement). """ fontsize = kwargs.get('fontsize', None) inline = kwargs.get('inline', 1) inline_spacing = kwargs.get('inline_spacing', 5) self.labelFmt = kwargs.get('fmt', '%1.3f') _colors = kwargs.get('colors', None) self.labelManual=kwargs.get('manual',False) self.rightside_up = kwargs.get('rightside_up', True) if len(args) == 0: levels = self.levels indices = range(len(self.levels)) elif len(args) == 1: levlabs = list(args[0]) indices, levels = [], [] for i, lev in enumerate(self.levels): if lev in levlabs: indices.append(i) levels.append(lev) if len(levels) < len(levlabs): msg = "Specified levels " + str(levlabs) msg += "\n don't match available levels " msg += str(self.levels) raise ValueError(msg) else: raise TypeError("Illegal arguments to clabel, see help(clabel)") self.labelLevelList = levels self.labelIndiceList = indices self.labelFontProps = font_manager.FontProperties() if fontsize == None: font_size = int(self.labelFontProps.get_size_in_points()) else: if type(fontsize) not in [int, float, str]: raise TypeError("Font size must be an integer number.") else: if type(fontsize) == str: font_size = int(self.labelFontProps.get_size_in_points()) else: self.labelFontProps.set_size(fontsize) font_size = fontsize self.labelFontSizeList = [font_size] * len(levels) if _colors == None: self.labelMappable = self self.labelCValueList = np.take(self.cvalues, self.labelIndiceList) else: cmap = colors.ListedColormap(_colors, N=len(self.labelLevelList)) self.labelCValueList = range(len(self.labelLevelList)) self.labelMappable = cm.ScalarMappable(cmap = cmap, norm = colors.NoNorm()) self.labelXYs = [] if self.labelManual: print 'Select label locations manually using first mouse button.' print 'End manual selection with second mouse button.' if not inline: print 'Remove last label by clicking third mouse button.' blocking_contour_labeler = BlockingContourLabeler(self) blocking_contour_labeler(inline,inline_spacing) else: self.labels(inline,inline_spacing) self.cl = self.labelTexts self.cl_xy = self.labelXYs self.cl_cvalues = self.labelCValues self.labelTextsList = cbook.silent_list('text.Text', self.labelTexts) return self.labelTextsList
def get_texts(self): r"""Return the list of `~.text.Text`\s in the legend.""" return silent_list('Text', self.texts)
def __init__(self, ax, *args, **kwargs): """ Draw contour lines or filled regions, depending on whether keyword arg 'filled' is False (default) or True. The first argument of the initializer must be an axes object. The remaining arguments and keyword arguments are described in ContourSet.contour_doc. """ self.ax = ax self.levels = kwargs.get('levels', None) self.filled = kwargs.get('filled', False) self.linewidths = kwargs.get('linewidths', None) self.linestyles = kwargs.get('linestyles', None) self.alpha = kwargs.get('alpha', 1.0) self.origin = kwargs.get('origin', None) self.extent = kwargs.get('extent', None) cmap = kwargs.get('cmap', None) self.colors = kwargs.get('colors', None) norm = kwargs.get('norm', None) self.extend = kwargs.get('extend', 'neither') self.antialiased = kwargs.get('antialiased', True) self.nchunk = kwargs.get('nchunk', 0) self.locator = kwargs.get('locator', None) if (isinstance(norm, colors.LogNorm) or isinstance(self.locator, ticker.LogLocator)): self.logscale = True if norm is None: norm = colors.LogNorm() if self.extend is not 'neither': raise ValueError('extend kwarg does not work yet with log scale') else: self.logscale = False if self.origin is not None: assert(self.origin in ['lower', 'upper', 'image']) if self.extent is not None: assert(len(self.extent) == 4) if cmap is not None: assert(isinstance(cmap, colors.Colormap)) if self.colors is not None and cmap is not None: raise ValueError('Either colors or cmap must be None') if self.origin == 'image': self.origin = mpl.rcParams['image.origin'] if isinstance(args[0], ContourSet): C = args[0].Cntr if self.levels is None: self.levels = args[0].levels else: x, y, z = self._contour_args(*args) x0 = ma.minimum(x) x1 = ma.maximum(x) y0 = ma.minimum(y) y1 = ma.maximum(y) self.ax.update_datalim([(x0,y0), (x1,y1)]) self.ax.autoscale_view() _mask = ma.getmask(z) if _mask is ma.nomask: _mask = None C = _cntr.Cntr(x, y, z.filled(), _mask) self.Cntr = C self._process_levels() if self.colors is not None: cmap = colors.ListedColormap(self.colors, N=len(self.layers)) if self.filled: self.collections = cbook.silent_list('collections.PathCollection') else: self.collections = cbook.silent_list('collections.LineCollection') self.labelTexts = [] self.labelCValues = [] kw = {'cmap': cmap} if norm is not None: kw['norm'] = norm cm.ScalarMappable.__init__(self, **kw) # sets self.cmap; self._process_colors() if self.filled: if self.linewidths is not None: warnings.warn('linewidths is ignored by contourf') lowers = self._levels[:-1] uppers = self._levels[1:] for level, level_upper in zip(lowers, uppers): nlist = C.trace(level, level_upper, nchunk = self.nchunk) nseg = len(nlist)//2 segs = nlist[:nseg] kinds = nlist[nseg:] paths = self._make_paths(segs, kinds) col = collections.PathCollection(paths, antialiaseds = (self.antialiased,), edgecolors= 'none', alpha=self.alpha) self.ax.add_collection(col) self.collections.append(col) else: tlinewidths = self._process_linewidths() self.tlinewidths = tlinewidths tlinestyles = self._process_linestyles() for level, width, lstyle in zip(self.levels, tlinewidths, tlinestyles): nlist = C.trace(level) nseg = len(nlist)//2 segs = nlist[:nseg] col = collections.LineCollection(segs, linewidths = width, linestyle = lstyle, alpha=self.alpha) col.set_label('_nolegend_') self.ax.add_collection(col, False) self.collections.append(col) self.changed() # set the colors
def get_texts(self): 'Return a list of `~.text.Text` instances in the legend.' return silent_list('Text', self.texts)
def get_texts(self): 'return a list of text.Text instance in the legend' return silent_list('Text', self.texts)
def hist(self, x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, **kwargs): """ call signature:: hist(x, bins=10, range=None, normed=False, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, **kwargs) Compute and draw the histogram of *x*. The return value is a tuple (*n*, *bins*, *patches*) or ([*n0*, *n1*, ...], *bins*, [*patches0*, *patches1*,...]) if the input contains multiple data. Multiple data can be provided via *x* as a list of datasets of potentially different length ([*x0*, *x1*, ...]), or as a 2-D ndarray in which each column is a dataset. Note that the ndarray form is transposed relative to the list form. Masked arrays are not supported at present. Keyword arguments: *bins*: Either an integer number of bins or a sequence giving the bins. If *bins* is an integer, *bins* + 1 bin edges will be returned, consistent with :func:`numpy.histogram` for numpy version >= 1.3, and with the *new* = True argument in earlier versions. Unequally spaced bins are supported if *bins* is a sequence. *range*: The lower and upper range of the bins. Lower and upper outliers are ignored. If not provided, *range* is (x.min(), x.max()). Range has no effect if *bins* is a sequence. If *bins* is a sequence or *range* is specified, autoscaling is based on the specified bin range instead of the range of x. *normed*: If *True*, the first element of the return tuple will be the counts normalized to form a probability density, i.e., ``n/(len(x)*dbin)``. In a probability density, the integral of the histogram should be 1; you can verify that with a trapezoidal integration of the probability density function:: pdf, bins, patches = ax.hist(...) print np.sum(pdf * np.diff(bins)) .. Note:: Until numpy release 1.5, the underlying numpy histogram function was incorrect with *normed*=*True* if bin sizes were unequal. MPL inherited that error. It is now corrected within MPL when using earlier numpy versions *weights* An array of weights, of the same shape as *x*. Each value in *x* only contributes its associated weight towards the bin count (instead of 1). If *normed* is True, the weights are normalized, so that the integral of the density over the range remains 1. *cumulative*: If *True*, then a histogram is computed where each bin gives the counts in that bin plus all bins for smaller values. The last bin gives the total number of datapoints. If *normed* is also *True* then the histogram is normalized such that the last bin equals 1. If *cumulative* evaluates to less than 0 (e.g. -1), the direction of accumulation is reversed. In this case, if *normed* is also *True*, then the histogram is normalized such that the first bin equals 1. *histtype*: [ 'bar' | 'barstacked' | 'step' | 'stepfilled' ] The type of histogram to draw. - 'bar' is a traditional bar-type histogram. If multiple data are given the bars are aranged side by side. - 'barstacked' is a bar-type histogram where multiple data are stacked on top of each other. - 'step' generates a lineplot that is by default unfilled. - 'stepfilled' generates a lineplot that is by default filled. *align*: ['left' | 'mid' | 'right' ] Controls how the histogram is plotted. - 'left': bars are centered on the left bin edges. - 'mid': bars are centered between the bin edges. - 'right': bars are centered on the right bin edges. *orientation*: [ 'horizontal' | 'vertical' ] If 'horizontal', :func:`~matplotlib.pyplot.barh` will be used for bar-type histograms and the *bottom* kwarg will be the left edges. *rwidth*: The relative width of the bars as a fraction of the bin width. If *None*, automatically compute the width. Ignored if *histtype* = 'step' or 'stepfilled'. *log*: If *True*, the histogram axis will be set to a log scale. If *log* is *True* and *x* is a 1D array, empty bins will be filtered out and only the non-empty (*n*, *bins*, *patches*) will be returned. *color*: Color spec or sequence of color specs, one per dataset. Default (*None*) uses the standard line color sequence. *label*: String, or sequence of strings to match multiple datasets. Bar charts yield multiple patches per dataset, but only the first gets the label, so that the legend command will work as expected:: ax.hist(10+2*np.random.randn(1000), label='men') ax.hist(12+3*np.random.randn(1000), label='women', alpha=0.5) ax.legend() kwargs are used to update the properties of the :class:`~matplotlib.patches.Patch` instances returned by *hist*: %(Patch)s **Example:** .. plot:: mpl_examples/pylab_examples/histogram_demo.py """ if not self._hold: self.cla() # NOTE: the range keyword overwrites the built-in func range !!! # needs to be fixed in numpy !!! # Validate string inputs here so we don't have to clutter # subsequent code. if histtype not in ['bar', 'barstacked', 'step', 'stepfilled']: raise ValueError("histtype %s is not recognized" % histtype) if align not in ['left', 'mid', 'right']: raise ValueError("align kwarg %s is not recognized" % align) if orientation not in ['horizontal', 'vertical']: raise ValueError("orientation kwarg %s is not recognized" % orientation) if kwargs.get('width') is not None: raise DeprecationWarning( 'hist now uses the rwidth to give relative width ' 'and not absolute width') # Massage 'x' for processing. # NOTE: Be sure any changes here is also done below to 'weights' if isinstance(x, np.ndarray) or not iterable(x[0]): # TODO: support masked arrays; x = np.asarray(x) if x.ndim == 2: x = x.T # 2-D input with columns as datasets; switch to rows elif x.ndim == 1: x = x.reshape(1, x.shape[0]) # new view, single row else: raise ValueError("x must be 1D or 2D") if x.shape[1] < x.shape[0]: warnings.warn('2D hist input should be nsamples x nvariables;\n ' 'this looks transposed (shape is %d x %d)' % x.shape[::-1]) else: # multiple hist with data of different length x = [np.array(xi) for xi in x] nx = len(x) # number of datasets if color is None: color = [self._get_lines.color_cycle.next() for i in xrange(nx)] else: color = mcolors.colorConverter.to_rgba_array(color) if len(color) != nx: raise ValueError("color kwarg must have one color per dataset") # We need to do to 'weights' what was done to 'x' if weights is not None: if isinstance(weights, np.ndarray) or not iterable(weights[0]): w = np.array(weights) if w.ndim == 2: w = w.T elif w.ndim == 1: w.shape = (1, w.shape[0]) else: raise ValueError("weights must be 1D or 2D") else: w = [np.array(wi) for wi in weights] if len(w) != nx: raise ValueError('weights should have the same shape as x') for i in xrange(nx): if len(w[i]) != len(x[i]): raise ValueError('weights should have the same shape as x') else: w = [None] * nx # Save autoscale state for later restoration; turn autoscaling # off so we can do it all a single time at the end, instead # of having it done by bar or fill and then having to be redone. _saved_autoscalex = self.get_autoscalex_on() _saved_autoscaley = self.get_autoscaley_on() self.set_autoscalex_on(False) self.set_autoscaley_on(False) # Save the datalimits for the same reason: _saved_bounds = self.dataLim.bounds # Check whether bins or range are given explicitly. In that # case use those values for autoscaling. binsgiven = (cbook.iterable(bins) or range != None) # If bins are not specified either explicitly or via range, # we need to figure out the range required for all datasets, # and supply that to np.histogram. if not binsgiven: xmin = np.inf xmax = -np.inf for xi in x: xmin = min(xmin, xi.min()) xmax = max(xmax, xi.max()) range = (xmin, xmax) #hist_kwargs = dict(range=range, normed=bool(normed)) # We will handle the normed kwarg within mpl until we # get to the point of requiring numpy >= 1.5. hist_kwargs = dict(range=range) if np.__version__ < "1.3": # version 1.1 and 1.2 hist_kwargs['new'] = True n = [] for i in xrange(nx): # this will automatically overwrite bins, # so that each histogram uses the same bins m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs) if normed: db = np.diff(bins) m = (m.astype(float) / db) / m.sum() n.append(m) if normed and db.std() > 0.01 * db.mean(): warnings.warn(""" This release fixes a normalization bug in the NumPy histogram function prior to version 1.5, occuring with non-uniform bin widths. The returned and plotted value is now a density: n / (N * bin width), where n is the bin count and N the total number of points. """) if cumulative: slc = slice(None) if cbook.is_numlike(cumulative) and cumulative < 0: slc = slice(None, None, -1) if normed: n = [(m * np.diff(bins))[slc].cumsum()[slc] for m in n] else: n = [m[slc].cumsum()[slc] for m in n] patches = [] if histtype.startswith('bar'): totwidth = np.diff(bins) if rwidth is not None: dr = min(1.0, max(0.0, rwidth)) elif len(n) > 1: dr = 0.8 else: dr = 1.0 if histtype == 'bar': width = dr * totwidth / nx dw = width if nx > 1: boffset = -0.5 * dr * totwidth * (1.0 - 1.0 / nx) else: boffset = 0.0 stacked = False elif histtype == 'barstacked': width = dr * totwidth boffset, dw = 0.0, 0.0 stacked = True if align == 'mid' or align == 'edge': boffset += 0.5 * totwidth elif align == 'right': boffset += totwidth if orientation == 'horizontal': _barfunc = self.barh else: # orientation == 'vertical' _barfunc = self.bar for m, c in zip(n, color): patch = _barfunc(bins[:-1] + boffset, m, width, bottom, align='center', log=log, color=c) patches.append(patch) if stacked: if bottom is None: bottom = 0.0 bottom += m boffset += dw elif histtype.startswith('step'): x = np.zeros(2 * len(bins), np.float) y = np.zeros(2 * len(bins), np.float) x[0::2], x[1::2] = bins, bins # FIX FIX FIX # This is the only real change. # minimum = min(bins) if log is True: minimum = 1.0 elif log: minimum = float(log) else: minimum = 0.0 # FIX FIX FIX end if align == 'left' or align == 'center': x -= 0.5 * (bins[1] - bins[0]) elif align == 'right': x += 0.5 * (bins[1] - bins[0]) if log: y[0], y[-1] = minimum, minimum if orientation == 'horizontal': self.set_xscale('log') else: # orientation == 'vertical' self.set_yscale('log') fill = (histtype == 'stepfilled') for m, c in zip(n, color): y[1:-1:2], y[2::2] = m, m if log: y[y < minimum] = minimum if orientation == 'horizontal': x, y = y, x if fill: patches.append(self.fill(x, y, closed=False, facecolor=c)) else: patches.append( self.fill(x, y, closed=False, edgecolor=c, fill=False)) # adopted from adjust_x/ylim part of the bar method if orientation == 'horizontal': xmin0 = max(_saved_bounds[0] * 0.9, minimum) xmax = self.dataLim.intervalx[1] for m in n: xmin = np.amin(m[m != 0]) # filter out the 0 height bins xmin = max(xmin * 0.9, minimum) xmin = min(xmin0, xmin) self.dataLim.intervalx = (xmin, xmax) elif orientation == 'vertical': ymin0 = max(_saved_bounds[1] * 0.9, minimum) ymax = self.dataLim.intervaly[1] for m in n: ymin = np.amin(m[m != 0]) # filter out the 0 height bins ymin = max(ymin * 0.9, minimum) ymin = min(ymin0, ymin) self.dataLim.intervaly = (ymin, ymax) if label is None: labels = ['_nolegend_'] elif is_string_like(label): labels = [label] elif is_sequence_of_strings(label): labels = list(label) else: raise ValueError( 'invalid label: must be string or sequence of strings') if len(labels) < nx: labels += ['_nolegend_'] * (nx - len(labels)) for (patch, lbl) in zip(patches, labels): for p in patch: p.update(kwargs) p.set_label(lbl) lbl = '_nolegend_' if binsgiven: if orientation == 'vertical': self.update_datalim([(bins[0], 0), (bins[-1], 0)], updatey=False) else: self.update_datalim([(0, bins[0]), (0, bins[-1])], updatex=False) self.set_autoscalex_on(_saved_autoscalex) self.set_autoscaley_on(_saved_autoscaley) self.autoscale_view() if nx == 1: return n[0], bins, cbook.silent_list('Patch', patches[0]) else: return n, bins, cbook.silent_list('Lists of Patches', patches)
def __init__(self, ax, *args, **kwargs): """ Draw contour lines or filled regions, depending on whether keyword arg 'filled' is False (default) or True. The first three arguments must be: *ax*: axes object. *levels*: [level0, level1, ..., leveln] A list of floating point numbers indicating the contour levels. *allsegs*: [level0segs, level1segs, ...] List of all the polygon segments for all the *levels*. For contour lines len(allsegs) == len(levels), and for filled contour regions len(allsegs) = len(levels)-1. level0segs = [polygon0, polygon1, ...] polygon0 = array_like [[x0,y0], [x1,y1], ...] *allkinds*: None or [level0kinds, level1kinds, ...] Optional list of all the polygon vertex kinds (code types), as described and used in Path. This is used to allow multiply- connected paths such as holes within filled polygons. If not None, len(allkinds) == len(allsegs). level0kinds = [polygon0kinds, ...] polygon0kinds = [vertexcode0, vertexcode1, ...] If allkinds is not None, usually all polygons for a particular contour level are grouped together so that level0segs = [polygon0] and level0kinds = [polygon0kinds]. Keyword arguments are as described in :class:`~matplotlib.contour.QuadContourSet` object. **Examples:** .. plot:: mpl_examples/misc/contour_manual.py """ self.ax = ax self.levels = kwargs.get('levels', None) self.filled = kwargs.get('filled', False) self.linewidths = kwargs.get('linewidths', None) self.linestyles = kwargs.get('linestyles', None) self.alpha = kwargs.get('alpha', None) self.origin = kwargs.get('origin', None) self.extent = kwargs.get('extent', None) cmap = kwargs.get('cmap', None) self.colors = kwargs.get('colors', None) norm = kwargs.get('norm', None) self.extend = kwargs.get('extend', 'neither') self.antialiased = kwargs.get('antialiased', True) self.nchunk = kwargs.get('nchunk', 0) self.locator = kwargs.get('locator', None) if (isinstance(norm, colors.LogNorm) or isinstance(self.locator, ticker.LogLocator)): self.logscale = True if norm is None: norm = colors.LogNorm() if self.extend is not 'neither': raise ValueError('extend kwarg does not work yet with log scale') else: self.logscale = False if self.origin is not None: assert(self.origin in ['lower', 'upper', 'image']) if self.extent is not None: assert(len(self.extent) == 4) if cmap is not None: assert(isinstance(cmap, colors.Colormap)) if self.colors is not None and cmap is not None: raise ValueError('Either colors or cmap must be None') if self.origin == 'image': self.origin = mpl.rcParams['image.origin'] self._process_args(*args, **kwargs) self._process_levels() if self.colors is not None: ncolors = len(self.levels) if self.filled: ncolors -= 1 cmap = colors.ListedColormap(self.colors, N=ncolors) if self.filled: self.collections = cbook.silent_list('collections.PathCollection') else: self.collections = cbook.silent_list('collections.LineCollection') self.labelTexts = [] self.labelCValues = [] kw = {'cmap': cmap} if norm is not None: kw['norm'] = norm cm.ScalarMappable.__init__(self, **kw) # sets self.cmap; self._process_colors() self.allsegs, self.allkinds = self._get_allsegs_and_allkinds() if self.filled: if self.linewidths is not None: warnings.warn('linewidths is ignored by contourf') lowers, uppers = self._get_lowers_and_uppers() if self.allkinds is None: self.allkinds = [None]*len(self.allsegs) for level, level_upper, segs, kinds in \ zip(lowers, uppers, self.allsegs, self.allkinds): paths = self._make_paths(segs, kinds) zorder = kwargs.get('zorder', 1) col = collections.PathCollection(paths, antialiaseds = (self.antialiased,), edgecolors= 'none', alpha=self.alpha, zorder=zorder) self.ax.add_collection(col) self.collections.append(col) else: tlinewidths = self._process_linewidths() self.tlinewidths = tlinewidths tlinestyles = self._process_linestyles() for level, width, lstyle, segs in \ zip(self.levels, tlinewidths, tlinestyles, self.allsegs): zorder = kwargs.get('zorder', 2) col = collections.LineCollection(segs, linewidths = width, linestyle = lstyle, alpha=self.alpha, zorder=zorder) col.set_label('_nolegend_') self.ax.add_collection(col, False) self.collections.append(col) self.changed() # set the colors