def hist(self, x, **kwargs): # pylint: disable=arguments-differ if iterable(x) and not numpy.size(x): x = numpy.ndarray((0,)) logbins = kwargs.pop('logbins', False) bins = kwargs.get('bins', 30) weights = kwargs.get('weights', None) if isinstance(weights, (float, int)): if isinstance(x, numpy.ndarray) or not iterable(x[0]): kwargs['weights'] = numpy.ones_like(x) * weights else: kwargs['weights'] = [] for arr in x: kwargs['weights'].append(numpy.ones_like(arr) * weights) kwargs['weights'] = numpy.asarray(kwargs['weights']) if logbins and (bins is None or isinstance(bins, (float, int))): bins = bins or 30 range_ = kwargs.pop('range', self.common_limits(x)) if range_[1] == range_[0]: kwargs['bins'] = bins else: kwargs['bins'] = self.bin_boundaries(range_[0], range_[1], bins, log=True) if kwargs.get('histtype', None) == 'stepfilled': kwargs.setdefault('edgecolor', 'black') return super(HistogramAxes, self).hist(x, **kwargs)
def fetch_historical_yahoo(ticker, date1, date2, cachename=None,dividends=False): """ Fetch historical data for ticker between date1 and date2. date1 and date2 are date or datetime instances, or (year, month, day) sequences. Ex: fh = fetch_historical_yahoo('^GSPC', (2000, 1, 1), (2001, 12, 31)) cachename is the name of the local file cache. If None, will default to the md5 hash or the url (which incorporates the ticker and date range) set dividends=True to return dividends instead of price data. With this option set, parse functions will not work a file handle is returned """ ticker = ticker.upper() if iterable(date1): d1 = (date1[1]-1, date1[2], date1[0]) else: d1 = (date1.month-1, date1.day, date1.year) if iterable(date2): d2 = (date2[1]-1, date2[2], date2[0]) else: d2 = (date2.month-1, date2.day, date2.year) if dividends: g='v' verbose.report('Retrieving dividends instead of prices') else: g='d' urlFmt = 'http://table.finance.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=%s&ignore=.csv' url = urlFmt % (d1[0], d1[1], d1[2], d2[0], d2[1], d2[2], ticker, g) if cachename is None: cachename = os.path.join(cachedir, md5(url).hexdigest()) if os.path.exists(cachename): fh = open(cachename) verbose.report('Using cachefile %s for %s'%(cachename, ticker)) else: mkdirs(cachedir) urlfh = urlopen(url) fh = open(cachename, 'wb') fh.write(urlfh.read()) fh.close() verbose.report('Saved %s data to cache file %s'%(ticker, cachename)) fh = open(cachename, 'r') return fh
def from_list(name, colors, N=256, gamma=1.0): """ Make a linear segmented colormap with *name* from a sequence of *colors* which evenly transitions from colors[0] at val=0 to colors[-1] at val=1. *N* is the number of rgb quantization levels. Alternatively, a list of (value, color) tuples can be given to divide the range unevenly. """ if not cbook.iterable(colors): raise ValueError('colors must be iterable') if cbook.iterable(colors[0]) and len(colors[0]) == 2 and \ not cbook.is_string_like(colors[0]): # List of value, color pairs vals, colors = zip(*colors) else: vals = np.linspace(0., 1., len(colors)) cdict = dict(red=[], green=[], blue=[]) for val, color in zip(vals, colors): r,g,b = colorConverter.to_rgb(color) cdict['red'].append((val, r, r)) cdict['green'].append((val, g, g)) cdict['blue'].append((val, b, b)) return LinearSegmentedColormap(name, cdict, N, gamma)
def getStock(ticker, d1, d2, verbose=False): if not iterable(d1): d1 = (d1, 1, 1) if not iterable(d2): d2 = (d2, 1, 1) saveStock(ticker, d1, d2) pickleFile = "%s/%s.pklz" % (storageDir, ticker) d = { } d["days"] = { } try: fh = gzip.open(pickleFile, "rb") dOld = pickle.load(fh) fh.close() except: if(verbose): print "[MM] Error: file (%s/%s.pklz) does not exist" % (storageDir, ticker) return d dt1, dt2 = datetime.datetime(*d1), datetime.datetime(*d2) day1, day2 = u.tuple2inum(d1), u.tuple2inum(d2) for day in dOld["days"].keys(): if( day1 <= day <= day2 ): d["days"][day] = dOld["days"][day] return d
def plot(self, xs, ys, *args, **kwargs): ''' Plot 2D or 3D data. ========== ================================================ Argument Description ========== ================================================ *xs*, *ys* X, y coordinates of vertices *zs* z value(s), either one for all points or one for each point. *zdir* Which direction to use as z ('x', 'y' or 'z') when plotting a 2d set. ========== ================================================ Other arguments are passed on to :func:`~matplotlib.axes.Axes.plot` ''' had_data = self.has_data() zs = kwargs.pop('zs', 0) zdir = kwargs.pop('zdir', 'z') argsi = 0 if len(args) > 0 and cbook.iterable(args[0]) and \ len(xs) == len(args[0]) and cbook.is_scalar(args[0][0]): zs = args[argsi] argsi += 1 elif len(args) > 0 and cbook.is_scalar(args[0]): zs = args[argsi] argsi += 1 if not cbook.iterable(zs): zs = np.ones(len(xs)) * zs lines = Axes.plot(self, xs, ys, *args[argsi:], **kwargs) for line in lines: art3d.line_2d_to_3d(line, zs=zs, zdir=zdir) self.auto_scale_xyz(xs, ys, zs, had_data) return lines
def add_lines(self, levels, colors, linewidths, erase=True): """ Draw lines on the colorbar. *colors* and *linewidths* must be scalars or sequences the same length as *levels*. Set *erase* to False to add lines without first removing any previously added lines. """ y = self._locate(levels) igood = (y < 1.001) & (y > -0.001) y = y[igood] if cbook.iterable(colors): colors = np.asarray(colors)[igood] if cbook.iterable(linewidths): linewidths = np.asarray(linewidths)[igood] N = len(y) x = np.array([0.0, 1.0]) X, Y = np.meshgrid(x, y) if self.orientation == "vertical": xy = [list(zip(X[i], Y[i])) for i in range(N)] else: xy = [list(zip(Y[i], X[i])) for i in range(N)] col = collections.LineCollection(xy, linewidths=linewidths) if erase and self.lines: for lc in self.lines: lc.remove() self.lines = [] self.lines.append(col) col.set_color(colors) self.ax.add_collection(col)
def _fetch_historical_yahoo(self, ticker, date1, date2, freq=None, cachename=None): """matplotlib's implementation, modified to provide proxy support and frequency Fetch historical data for ticker between date1 and date2. date1 and date2 are date or datetime instances, or (year, month, day) sequences. Ex: fh = fetch_historical_yahoo('^GSPC', (2000, 1, 1), (2001, 12, 31)) cachename is the name of the local file cache. If None, will default to the md5 hash or the url (which incorporates the ticker and date range) a file handle is returned """ if freq is None or type(freq) != str: raise ValueError('Must enter a frequency as a string, m, w, or d') proxy = self._proxy ticker = ticker.upper() configdir = get_configdir() cachedir = os.path.join(configdir, 'finance.cache') if iterable(date1): d1 = (date1[1]-1, date1[2], date1[0]) else: d1 = (date1.month-1, date1.day, date1.year) if iterable(date2): d2 = (date2[1]-1, date2[2], date2[0]) else: d2 = (date2.month-1, date2.day, date2.year) urlFmt = 'http://table.finance.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=%s&ignore=.csv' url = urlFmt % (d1[0], d1[1], d1[2], d2[0], d2[1], d2[2], ticker, freq) if proxy: proxy_support = urllib2.ProxyHandler(proxy) opener = urllib2.build_opener(proxy_support) urllib2.install_opener(opener) if cachename is None: cachename = os.path.join(cachedir, md5(url).hexdigest()) if os.path.exists(cachename): fh = file(cachename) verbose.report('Using cachefile %s for %s'%(cachename, ticker)) else: if not os.path.isdir(cachedir): os.mkdir(cachedir) urlfh = urllib2.urlopen(url) fh = file(cachename, 'w') fh.write(urlfh.read()) fh.close() verbose.report('Saved %s data to cache file %s'%(ticker, cachename)) fh = file(cachename, 'r') return fh
def plot(self, xs, ys, *args, **kwargs): ''' Plot 2D or 3D data. ========== ================================================ Argument Description ========== ================================================ *xs*, *ys* X, y coordinates of vertices *zs* z value(s), either one for all points or one for each point. *zdir* Which direction to use as z ('x', 'y' or 'z') when plotting a 2d set. ========== ================================================ Other arguments are passed on to :func:`~matplotlib.axes.Axes.plot` ''' # FIXME: This argument parsing might be better handled # when we set later versions of python for # minimum requirements. Currently at 2.4. # Note that some of the reason for the current difficulty # is caused by the fact that we want to insert a new # (semi-optional) positional argument 'Z' right before # many other traditional positional arguments occur # such as the color, linestyle and/or marker. had_data = self.has_data() zs = kwargs.pop('zs', 0) zdir = kwargs.pop('zdir', 'z') argsi = 0 # First argument is array of zs if len(args) > 0 and cbook.iterable(args[0]) and \ len(xs) == len(args[0]) : # So, we know that it is an array with # first dimension the same as xs. # Next, check to see if the data contained # therein (if any) is scalar (and not another array). if len(args[0]) == 0 or cbook.is_scalar(args[0][0]) : zs = args[argsi] argsi += 1 # First argument is z value elif len(args) > 0 and cbook.is_scalar(args[0]): zs = args[argsi] argsi += 1 # Match length if not cbook.iterable(zs): zs = np.ones(len(xs)) * zs lines = Axes.plot(self, xs, ys, *args[argsi:], **kwargs) for line in lines: art3d.line_2d_to_3d(line, zs=zs, zdir=zdir) self.auto_scale_xyz(xs, ys, zs, had_data) return lines
def bar3d(self, x, y, z, dx, dy, dz, color='b'): ''' Generate a 3D bar, or multiple bars. When generating multiple bars, x, y, z have to be arrays. dx, dy, dz can still be scalars. ''' had_data = self.has_data() if not cbook.iterable(x): x, y, z = [x], [y], [z] if not cbook.iterable(dx): dx, dy, dz = [dx], [dy], [dz] if len(dx) == 1: dx = dx * len(x) dy = dy * len(x) dz = dz * len(x) minx, miny, minz = 1e20, 1e20, 1e20 maxx, maxy, maxz = -1e20, -1e20, -1e20 polys = [] for xi, yi, zi, dxi, dyi, dzi in zip(x, y, z, dx, dy, dz): minx = min(xi, minx) maxx = max(xi + dxi, maxx) miny = min(yi, miny) maxy = max(yi + dyi, maxy) minz = min(zi, minz) maxz = max(zi + dzi, maxz) polys.extend([ ((xi, yi, zi), (xi + dxi, yi, zi), (xi + dxi, yi + dyi, zi), (xi, yi + dyi, zi)), ((xi, yi, zi + dzi), (xi + dxi, yi, zi + dzi), (xi + dxi, yi + dyi, zi + dzi), (xi, yi + dyi, zi + dzi)), ((xi, yi, zi), (xi + dxi, yi, zi), (xi + dxi, yi, zi + dzi), (xi, yi, zi + dzi)), ((xi, yi + dyi, zi), (xi + dxi, yi + dyi, zi), (xi + dxi, yi + dyi, zi + dzi), (xi, yi + dyi, zi + dzi)), ((xi, yi, zi), (xi, yi + dyi, zi), (xi, yi + dyi, zi + dzi), (xi, yi, zi + dzi)), ((xi + dxi, yi, zi), (xi + dxi, yi + dyi, zi), (xi + dxi, yi + dyi, zi + dzi), (xi + dxi, yi, zi + dzi)), ]) color = np.array(colorConverter.to_rgba(color)) normals = self._generate_normals(polys) colors = self._shade_colors(color, normals) col = art3d.Poly3DCollection(polys, facecolor=colors) self.add_collection(col) self.auto_scale_xyz((minx, maxx), (miny, maxy), (minz, maxz), had_data)
def _process_linewidths(self): linewidths = self.linewidths Nlev = len(self.levels) if linewidths is None: tlinewidths = [(mpl.rcParams['lines.linewidth'],)] *Nlev else: if cbook.iterable(linewidths) and len(linewidths) < Nlev: linewidths = list(linewidths) * int(npy.ceil(Nlev/len(linewidths))) elif not cbook.iterable(linewidths) and type(linewidths) in [int, float]: linewidths = [linewidths] * Nlev tlinewidths = [(w,) for w in linewidths] return tlinewidths
def getTimeIntervall(stream, start=None, end=None, relative='starttime', ret_rel='utc'): """ Create two lists of UTCDateTimes - start list and end list 'time' can stand for UTCDateTime, list of UTCDateTimes, header entry out of ('ponset', 'sonset', 'startime', 'endtime') or 'middle' :param start, end: - None (means start- resp. endtime) - time object - or seconds relative to param relative :param relative: times (if given as seconds=numbers) are taken relative to this parameter, is also needed for param ret_rel='relative -time object :param ret_rel: - 'utc' output in absolute UTCDateTime - 'relative': output in seconds relative to param relative - time object: output in seconds relative to time :return: start and end list of UTCDateTime or None if stream has length 0 """ N = len(stream) if N == 0: return # get list of UTCDateTimes for start_out and end_out if start == None: start = 'starttime' if end == None: end = 'endtime' start_out = _getUTCListFromSth(stream, start) end_out = _getUTCListFromSth(stream, end) # get list of UTCDateTimes for relative if needed if start_out == None or end_out == None or ret_rel == 'relative': relative = _getUTCListFromSth(stream, relative, raisenumber=True) # get list of UTCDateTimes for start_out and end_out if start_out == None: if cbook.iterable(start): start_out = [utc + start[i] for i, utc in enumerate(relative)] else: start_out = [i + start for i in relative] if end_out == None: if cbook.iterable(start): end_out = [utc + end[i] for i, utc in enumerate(relative)] else: end_out = [i + end for i in relative] # convert UTCDateTimes to seconds if ret_rel demands it if ret_rel == 'utc': return start_out, end_out elif ret_rel != 'relative': relative = _getUTCListFromSth(stream, ret_rel) start_out = [start_out[i] - relative[i] for i in range(N)] end_out = [end_out[i] - relative[i] for i in range(N)] return start_out, end_out
def append_fields(rec, names, arr, dtype=None): """ Appends a field to an existing record array, handling masked fields if necessary. Parameters ---------- rec : numpy record array Array to which the new field should be appended names : string Names to be given to the new fields arr : ndarray Array containing the data for the new fields. dtype : data-type or None, optional Data type of the new fields. If this is None, the data types will be obtained from `arr`. Returns ------- out : numpy record array `rec` with the new field appended. rec = append_fields(rec, name, arr) """ if not iterable(names): names = [names] if not iterable(arr): arr = [arr] if dtype is None: dtype = [a.dtype for a in arr] newdtype = np.dtype(rec.dtype.descr + zip(names, dtype)) newrec = np.empty(rec.shape, dtype=newdtype).view(type(rec)) for name in rec.dtype.names: newrec[name] = rec[name] try: newrec.mask[name] = rec.mask[name] except AttributeError: pass #Not a masked array for n,a in zip(names, arr): newrec[n] = a try: old_mask = a.mask except AttributeError: old_mask = np.array([False]*a.size).reshape(a.shape) try: newrec[n].mask = old_mask except AttributeError: pass return newrec
def wsat(Temp, press): """ wsat(Temp, press) Calculates the saturation vapor mixing ratio of an air parcel. Parameters - - - - - - Temp : float or array_like Temperature in Kelvin. press : float or array_like Pressure in Pa. Returns - - - - theWs : float or array_like Saturation water vapor mixing ratio in (kg/kg). Raises - - - - IOError If both 'Temp' and 'press' are array_like. Examples - - - - - >>> test.assert_almost_equal(wsat(300, 8e4),0.02875,decimal=4) >>> test.assert_array_almost_equal(wsat([300,310], 8e4),[0.0287, 0.0525],decimal=4) >>> test.assert_array_almost_equal(wsat(300, [8e4, 7e4]),[0.0287, 0.0330],decimal=4) >>> wsat([300, 310], [8e4, 7e4]) Traceback (most recent call last): ... IOError: Can't have two vector inputs. """ is_scalar_temp=True if cbook.iterable(Temp): is_scalar_temp = False is_scalar_press=True if cbook.iterable(press): is_scalar_press = False Temp=np.atleast_1d(Temp) press=np.atleast_1d(press) if (np.size(Temp) !=1) and (np.size(press) != 1): raise IOError, "Can't have two vector inputs." es = esat(Temp); theWs=(c.eps * es/ (press - es)) theWs[theWs > 0.060]=0.06 theWs[theWs < 0.0] = 0. if is_scalar_temp and is_scalar_press: theWs=theWs[0] return theWs
def __call__(self, value, clip=None): if clip is None: clip = self.clip if cbook.iterable(value): vtype = 'array' val = np.ma.asarray(value).astype(np.float) else: vtype = 'scalar' val = np.ma.array([value]).astype(np.float) self.autoscale_None(val) vmin, vmax = float(self.vmin), float(self.vmax) if vmin > vmax: raise ValueError("minvalue must be less than or equal to maxvalue") elif vmin==vmax: return 0.0 * val else: if clip: mask = np.ma.getmask(val) val = np.ma.array(np.clip(val.filled(vmax), vmin, vmax), mask=mask) result = np.ma.array(np.interp(val, self.xval, self.yval), mask=np.ma.getmask(val)) result[np.isinf(val.data)] = -np.inf if vtype == 'scalar': result = result[0] return result
def set_3d_properties(self, verts, zs=0, zdir='z'): if not iterable(zs): zs = np.ones(len(verts)) * zs self._segment3d = [juggle_axes(x, y, z, zdir) \ for ((x, y), z) in zip(verts, zs)] self._facecolor3d = Patch.get_facecolor(self)
def convert(val, unit, axis): if units.ConversionInterface.is_numlike(val): return val if iterable(val): return [thisval.convert_to(unit).get_value() for thisval in val] else: return val.convert_to(unit).get_value()
def get_converter(self, x): 'get the converter interface instance for x, or None' if not len(self): return None # nothing registered #DISABLED idx = id(x) #DISABLED cached = self._cached.get(idx) #DISABLED if cached is not None: return cached converter = None classx = getattr(x, '__class__', None) if classx is not None: converter = self.get(classx) # Check explicity for strings here because they would otherwise # lead to an infinite recursion, because a single character will # pass the iterable() check. if converter is None and iterable(x) and not is_string_like(x): # if this is anything but an object array, we'll assume # there are no custom units if isinstance(x, np.ndarray) and x.dtype != np.object: return None for thisx in x: converter = self.get_converter( thisx ) return converter #DISABLED self._cached[idx] = converter return converter
def __init__(self, artists, tolerance=5, offsets=(-20, 20), template="x: %0.2f\ny: %0.2f", display_all=False): """Create the data cursor and connect it to the relevant figure. "artists" is the matplotlib artist or sequence of artists that will be selected. "tolerance" is the radius (in points) that the mouse click must be within to select the artist. "offsets" is a tuple of (x,y) offsets in points from the selected point to the displayed annotation box "template" is the format string to be used. Note: For compatibility with older versions of python, this uses the old-style (%) formatting specification. "display_all" controls whether more than one annotation box will be shown if there are multiple axes. Only one will be shown per-axis, regardless. """ self.template = template self.offsets = offsets self.display_all = display_all if not cbook.iterable(artists): artists = [artists] self.artists = artists self.axes = tuple(set(art.axes for art in self.artists)) self.figures = tuple(set(ax.figure for ax in self.axes)) self.annotations = {} for ax in self.axes: self.annotations[ax] = self.annotate(ax) for artist in self.artists: artist.set_picker(tolerance) for fig in self.figures: fig.canvas.mpl_connect("pick_event", self)
def hist(*args, **kwargs): """ Plots a histogram of the provided data. Can provide optional argument "grid='x'" or "grid='y'" to draw a white grid over the histogram. Almost like "erasing" some of the plot, but it adds more information! """ ax, args, kwargs = maybe_get_ax(*args, **kwargs) color_cycle = ax._get_lines.color_cycle # Reassign the default colors to Set2 by Colorbrewer if iterable(args[0]): if isinstance(args[0], list): ncolors = len(args[0]) else: if len(args[0].shape) == 2: ncolors = args[0].shape[1] else: ncolors = 1 kwargs.setdefault('color', [next(color_cycle) for _ in range(ncolors)]) else: kwargs.setdefault('color', next(color_cycle)) kwargs.setdefault('edgecolor', 'white') show_ticks = kwargs.pop('show_ticks', False) # If no grid specified, don't draw one. grid = kwargs.pop('grid', None) # print 'hist kwargs', kwargs patches = ax.hist(*args, **kwargs) remove_chartjunk(ax, ['top', 'right'], grid=grid, show_ticks=show_ticks) return ax
def __init__(self, artists, lookUp, formatFunction, convert, tolerance=5, offsets=(-30, 20), display_all=False): """Create the data cursor and connect it to the relevant figure. "artists" is the matplotlib artist or sequence of artists that will be selected. "tolerance" is the radius (in points) that the mouse click must be within to select the artist. "offsets" is a tuple of (x,y) offsets in points from the selected point to the displayed annotation box "display_all" controls whether more than one annotation box will be shown if there are multiple axes. Only one will be shown per-axis, regardless. """ self.lookUp = lookUp self.formatFunction = formatFunction self.offsets = offsets self.display_all = display_all if not cbook.iterable(artists): artists = [artists] self.artists = artists self.convert = convert self.axes = tuple(set(art.axes for art in self.artists)) self.figures = tuple(set(ax.figure for ax in self.axes)) self.annotations = {} for ax in self.axes: self.annotations[ax] = self.annotate(ax) for artist in self.artists: artist.set_picker(tolerance) for fig in self.figures: fig.canvas.mpl_connect('pick_event', self) fig.canvas.mpl_connect('key_press_event', self.keyPressed)
def __call__(self, value, clip=None): if clip is None: clip = self.clip if cbook.iterable(value): vtype = 'array' val = ma.asarray(value).astype(np.float) else: vtype = 'scalar' val = ma.array([value]).astype(np.float) self.autoscale_None(val) vmin, vmax = self.vmin, self.vmax if vmin > vmax: raise ValueError("minvalue must be less than or equal to maxvalue") elif vmin<=0: raise ValueError("values must all be positive") elif vmin==vmax: return 0.0 * val else: if clip: mask = ma.getmask(val) val = ma.array(np.clip(val.filled(vmax), vmin, vmax), mask=mask) result = (ma.log(val)-np.log(vmin))/(np.log(vmax)-np.log(vmin)) if vtype == 'scalar': result = result[0] return result
def process_value(value): """ Homogenize the input *value* for easy and efficient normalization. *value* can be a scalar or sequence. Returns *result*, *is_scalar*, where *result* is a masked array matching *value*. Float dtypes are preserved; integer types with two bytes or smaller are converted to np.float32, and larger types are converted to np.float. Preserving float32 when possible, and using in-place operations, can greatly improve speed for large arrays. Experimental; we may want to add an option to force the use of float32. """ if cbook.iterable(value): is_scalar = False result = ma.asarray(value) if result.dtype.kind == 'f': if isinstance(value, np.ndarray): result = result.copy() elif result.dtype.itemsize > 2: result = result.astype(np.float) else: result = result.astype(np.float32) else: is_scalar = True result = ma.array([value]).astype(np.float) return result, is_scalar
def to_rgba(self, arg, alpha=None): """ Returns an *RGBA* tuple of four floats from 0-1. For acceptable values of *arg*, see :meth:`to_rgb`. If *arg* is an *RGBA* sequence and *alpha* is not *None*, *alpha* will replace the original *A*. """ try: if not cbook.is_string_like(arg) and cbook.iterable(arg): if len(arg) == 4: if [x for x in arg if (float(x) < 0) or (x > 1)]: # This will raise TypeError if x is not a number. raise ValueError('number in rbga sequence outside 0-1 range') if alpha is None: return tuple(arg) if alpha < 0.0 or alpha > 1.0: raise ValueError("alpha must be in range 0-1") return arg[0], arg[1], arg[2], arg[3] * alpha r,g,b = arg[:3] if [x for x in (r,g,b) if (float(x) < 0) or (x > 1)]: raise ValueError('number in rbg sequence outside 0-1 range') else: r,g,b = self.to_rgb(arg) if alpha is None: alpha = 1.0 return r,g,b,alpha except (TypeError, ValueError), exc: raise ValueError('to_rgba: Invalid rgba arg "%s"\n%s' % (str(arg), exc))
def __init__(self, artists, x = [], y = [], tolerance = 5, offsets = (-20, 20), formatter = fmt, display_all = False): """Create the data cursor and connect it to the relevant figure. "artists" is the matplotlib artist or sequence of artists that will be selected. "tolerance" is the radius (in points) that the mouse click must be within to select the artist. "offsets" is a tuple of (x,y) offsets in points from the selected point to the displayed annotation box "formatter" is a callback function which takes 2 numeric arguments and returns a string "display_all" controls whether more than one annotation box will be shown if there are multiple axes. Only one will be shown per-axis, regardless. """ self._points = np.column_stack((x,y)) self.formatter = formatter self.offsets = offsets self.display_all = display_all if not cbook.iterable(artists): artists = [artists] self.artists = artists self.axes = tuple(set(art.axes for art in self.artists)) self.figures = tuple(set(ax.figure for ax in self.axes)) self.annotations = {} for ax in self.axes: self.annotations[ax] = self.annotate(ax) for artist in self.artists: artist.set_picker(tolerance) for fig in self.figures: fig.canvas.mpl_connect('pick_event', self)
def get_dir_vector(zdir): """ Return a direction vector. Parameters ---------- zdir : {'x', 'y', 'z', None, 3-tuple} The direction. Possible values are: - 'x': equivalent to (1, 0, 0) - 'y': euqivalent to (0, 1, 0) - 'z': equivalent to (0, 0, 1) - *None*: euqivalent to (0, 0, 0) - an iterable (x, y, z) is returned unchanged. Returns ------- x, y, z : array-like The direction vector. This is either a numpy.array or *zdir* itself if *zdir* is already a length-3 iterable. """ if zdir == 'x': return np.array((1, 0, 0)) elif zdir == 'y': return np.array((0, 1, 0)) elif zdir == 'z': return np.array((0, 0, 1)) elif zdir is None: return np.array((0, 0, 0)) elif cbook.iterable(zdir) and len(zdir) == 3: return zdir else: raise ValueError("'x', 'y', 'z', None or vector of length 3 expected")
def get_converter(self, x): 'get the converter interface instance for x, or None' if not len(self): return None # nothing registered #DISABLED idx = id(x) #DISABLED cached = self._cached.get(idx) #DISABLED if cached is not None: return cached converter = None classx = getattr(x, '__class__', None) if classx is not None: converter = self.get(classx) if converter is None and iterable(x): for thisx in x: # Make sure that recursing might actually lead to a solution, if # we are just going to re-examine another item of the same kind, # then do not look at it. if classx and classx != getattr(thisx, '__class__', None): converter = self.get_converter( thisx ) return converter #DISABLED self._cached[idx] = converter return converter
def to_rgba(self, arg, alpha=None): """ Returns an RGBA tuple of four floats from 0-1. For acceptable values of arg, see to_rgb. If arg is an RGBA sequence and alpha is not None, alpha will replace the original A. """ try: if not cbook.is_string_like(arg) and cbook.iterable(arg): if len(arg) == 4 and alpha is None: if [x for x in arg if (float(x) < 0) or (x > 1)]: # This will raise TypeError if x is not a number. raise ValueError('number in rbga sequence outside 0-1 range') return tuple(arg) r,g,b = arg[:3] if [x for x in (r,g,b) if (float(x) < 0) or (x > 1)]: raise ValueError('number in rbg sequence outside 0-1 range') else: r,g,b = self.to_rgb(arg) if alpha is None: alpha = 1.0 return r,g,b,alpha except (TypeError, ValueError), exc: raise ValueError('to_rgba: Invalid rgba arg "%s"\n%s' % (str(arg), exc))
def _determine_lims(self, xmin=None, xmax=None, *args, **kwargs): if xmax is None and cbook.iterable(xmin): xmin, xmax = xmin if xmin == xmax: xmin -= 0.5 xmax += 0.5 return (xmin, xmax)
def __call__(self, value, clip=None): if clip is None: clip = self.clip if cbook.iterable(value): vtype = 'array' val = np.ma.asarray(value).astype(np.float) else: vtype = 'scalar' val = np.ma.array([value]).astype(np.float) winf = np.isinf(val.data) val = np.ma.masked_where(winf,val) self.autoscale_None(val) vmin, vmax = float(self.vmin), float(self.vmax) if vmin > vmax: raise ValueError("minvalue must be less than or equal to maxvalue") elif vmin==vmax: return type(value)(0.0 * np.asarray(value)) else: if clip: mask = np.ma.getmask(val) val = np.ma.array(np.clip(val.filled(vmax), vmin, vmax), mask=mask) result = (val-vmin) * (1./(vmax-vmin)) result.data[result.data<0]=0.0 result.data[result.data>1]=1.0 result[winf] = -np.inf if result.mask is not np.ma.nomask: result.mask[winf] = False if vtype == 'scalar': result = result[0] return result
def common_limits(datasets, default_min=0, default_max=0): """Find the global maxima and minima of a list of datasets. Parameters ---------- datasets : `iterable` list (or any other iterable) of data arrays to analyse. default_min : `float`, optional fall-back minimum value if datasets are all empty. default_max : `float`, optional fall-back maximum value if datasets are all empty. Returns ------- (min, max) : `float` 2-tuple of common minimum and maximum over all datasets. """ from glue import iterutils if isinstance(datasets, numpy.ndarray) or not iterable(datasets[0]): datasets = [datasets] max_stat = max(list(iterutils.flatten(datasets)) + [-numpy.inf]) min_stat = min(list(iterutils.flatten(datasets)) + [numpy.inf]) if numpy.isinf(-max_stat): max_stat = default_max if numpy.isinf(min_stat): min_stat = default_min return min_stat, max_stat
def cos(x): if iterable(x): return [math.cos(val.convert_to(radians).get_value()) for val in x] else: return math.cos(x.convert_to(radians).get_value())
def get_color_dict(color, item_list, vmin=None, vmax=None, cmap=None): """ Determine color rgb color values given a data list. This function is used to take a sequence of data and convert it into a dictionary which of possible rgb values. It can take a number of different types of data explained below. If no colormap is given it will return the grayscale for scalar values. Parameters: ----------- color: A string, scalar, or iterable of either. This can be a color in a variety of formats. A matplotlib a single color, which can be a matplotlib color specification e.g. 'rgbcmykw', a hex color string '#00FFFF', a standard html name like 'aqua', or a numeric value to be scaled with vmax or vmin. It can also be a list of any of these types as well as a dictionary of any of these types. item_list: a list A list of keys which correspond to the values given in color. vmin: A scalar The minimum value if scalar values are given for color vmax: A scalar The maximum value if scalar values are given for color cmap: A matplotlib colormap A colormap to be used if scalar values are given. Returns: ------- color_dict: dict A dictionary of rgb colors keyed by values in item_list """ CC = mcolors.ColorConverter() if cb.is_string_like(color): return {}.fromkeys(item_list, CC.to_rgb(color)) elif cb.is_scalar(color): CN = mcolors.Normalize(0.0, 1.0) if cmap is not None: return {}.fromkeys(item_list, cmap(CN(color))) else: return {}.fromkeys(item_list, CC.to_rgb(str(CN(color)))) elif cb.iterable(color) and not cb.is_string_like(color): try: vals = [color[i] for i in item_list] except: vals = color keys = item_list if len(item_list) > len(vals): raise nx.NetworkXError("Must provide a value for each item") if cb.alltrue([cb.is_string_like(c) for c in vals]): return dict(zip(keys, [CC.to_rgb(v) for v in vals])) elif cb.alltrue([cb.is_scalar(c) for c in vals]): if vmin is None: vmin = float(min(vals)) if vmax is None: vmax = float(max(vals)) CN = mcolors.Normalize(vmin, vmax) if cmap is not None: return dict(zip(keys, [cmap(CN(v)) for v in vals])) else: return dict(zip(keys, [CC.to_rgb(str(CN(v))) for v in vals])) elif cb.alltrue([cb.iterable(c) and not cb.is_string(c) for c in vals]): return dict(zip(keys, vals)) else: raise nx.NetworkXError("Could not convert colors")
maxy = np.amax(temp_y) w = max(maxx - minx, 1.0) h = max(maxy - miny, 1.0) #for scaling axcorn = ax.get_position().get_points() xperc = (axcorn[1][0] - axcorn[0][0]) * .5 yperc = (axcorn[1][1] - axcorn[0][1]) * .5 area2radius = lambda a: math.sqrt( (a * w * h) / (ax.figure.get_figheight() * ax.figure.get_figwidth( ) * ax.figure.dpi * ax.figure.dpi * math.pi * xperc * yperc)) if cb.iterable(node_size): try: vals = node_size.values() except: vals = node_size node_size = dict(zip(nodelist, map(area2radius, vals))) else: node_size = {}.fromkeys(nodelist, area2radius(node_size)) for n in node_size: if node_size[n] == 0.0: node_size[n] = .00001 if cmap is None: cmap = cm.get_cmap(mpl.rcParams['image.cmap']) n_colors = get_color_dict(node_color, nodelist, vmin, vmax, cmap)
def __call__(self, X, alpha=None, bytes=False): """ *X* is either a scalar or an array (of any dimension). If scalar, a tuple of rgba values is returned, otherwise an array with the new shape = oldshape+(4,). If the X-values are integers, then they are used as indices into the array. If they are floating point, then they must be in the interval (0.0, 1.0). Alpha must be a scalar between 0 and 1, or None. If bytes is False, the rgba values will be floats on a 0-1 scale; if True, they will be uint8, 0-255. """ if not self._isinit: self._init() mask_bad = None if not cbook.iterable(X): vtype = 'scalar' xa = np.array([X]) else: vtype = 'array' xma = ma.array(X, copy=False) mask_bad = xma.mask xa = xma.data.copy() # Copy here to avoid side effects. del xma # masked values are substituted below; no need to fill them here if xa.dtype.char in np.typecodes['Float']: np.putmask(xa, xa==1.0, 0.9999999) #Treat 1.0 as slightly less than 1. # The following clip is fast, and prevents possible # conversion of large positive values to negative integers. xa *= self.N if NP_CLIP_OUT: np.clip(xa, -1, self.N, out=xa) else: xa = np.clip(xa, -1, self.N) # ensure that all 'under' values will still have negative # value after casting to int np.putmask(xa, xa<0.0, -1) xa = xa.astype(int) # Set the over-range indices before the under-range; # otherwise the under-range values get converted to over-range. np.putmask(xa, xa>self.N-1, self._i_over) np.putmask(xa, xa<0, self._i_under) if mask_bad is not None: if mask_bad.shape == xa.shape: np.putmask(xa, mask_bad, self._i_bad) elif mask_bad: xa.fill(self._i_bad) if bytes: lut = (self._lut * 255).astype(np.uint8) else: lut = self._lut.copy() # Don't let alpha modify original _lut. if alpha is not None: alpha = min(alpha, 1.0) # alpha must be between 0 and 1 alpha = max(alpha, 0.0) if bytes: alpha = int(alpha * 255) if (lut[-1] == 0).all(): lut[:-1, -1] = alpha # All zeros is taken as a flag for the default bad # color, which is no color--fully transparent. We # don't want to override this. else: lut[:,-1] = alpha # If the bad value is set to have a color, then we # override its alpha just as for any other value. rgba = np.empty(shape=xa.shape+(4,), dtype=lut.dtype) lut.take(xa, axis=0, mode='clip', out=rgba) # twice as fast as lut[xa]; # using the clip or wrap mode and providing an # output array speeds it up a little more. if vtype == 'scalar': rgba = tuple(rgba[0,:]) return rgba
def draw_networkx_edges(G, pos, edgelist=None, width=1.0, edge_color='k', style='solid', alpha=1.0, ax=None, **kwds): """Draw the edges of the graph G This draws only the edges of the graph G. pos is a dictionary keyed by vertex with a two-tuple of x-y positions as the value. See networkx.layout for functions that compute node positions. edgelist is an optional list of the edges in G to be drawn. If provided, only the edges in edgelist will be drawn. See draw_networkx for the list of other optional parameters. """ from matplotlib.pylab import gca, hold, draw_if_interactive from matplotlib.patches import FancyArrow from matplotlib.collections import PolyCollection if ax is None: ax = gca() if edgelist is None: edgelist = G.edges() if not edgelist: # no edges! return None # set edge positions head = [] tail = [] for e in edgelist: # edge e can be a 2-tuple (Graph) or a 3-tuple (Xgraph) u = e[0] v = e[1] head.append(pos[u]) tail.append(pos[v]) edge_pos = asarray(zip(head, tail)) if not cb.iterable(width): lw = (width, ) else: lw = width # edge colors specified with floats won't work here # since LineCollection doesn't use ScalarMappable. # You can use an array of RGBA or text labels if not cb.is_string_like(edge_color) \ and cb.iterable(edge_color) \ and len(edge_color)==len(edge_pos): edge_colors = None else: edge_colors = (colorConverter.to_rgba(edge_color, alpha), ) if not G.is_directed(): edge_collection = LineCollection( edge_pos, colors=edge_colors, linewidths=lw, antialiaseds=(1, ), linestyle=style, transOffset=ax.transData, ) edge_collection.set_alpha(alpha) else: arrows = [] for src, dst in edge_pos: x1, y1 = src x2, y2 = dst dx = x2 - x1 # x offset dy = y2 - y1 # y offset vu_x = dx / sqrt(dx * dx + dy * dy) #direction in arc sense vu_y = dy / sqrt(dx * dx + dy * dy) p = 0.026 arrows.append( FancyArrow( x1, y1, dx - p * vu_x, dy - p * vu_y, head_width=p, length_includes_head=True, ).get_verts()) edge_collection = PolyCollection( arrows, facecolors=edge_colors, antialiaseds=(1, ), transOffset=ax.transData, ) # update view xx = [x for (x, y) in head + tail] yy = [y for (x, y) in head + tail] minx = amin(xx) maxx = amax(xx) miny = amin(yy) maxy = amax(yy) w = maxx - minx h = maxy - miny padx, pady = 0.05 * w, 0.05 * h corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady) ax.update_datalim(corners) ax.autoscale_view() edge_collection.set_zorder(1) # edges go behind nodes ax.add_collection(edge_collection) return edge_collection
def __init__( self, ax, cmap=None, norm=None, alpha=1.0, values=None, boundaries=None, orientation='vertical', extend='neither', spacing='uniform', # uniform or proportional ticks=None, format=None, drawedges=False, filled=True, ): self.ax = ax if cmap is None: cmap = cm.get_cmap() if norm is None: norm = colors.Normalize() self.alpha = alpha cm.ScalarMappable.__init__(self, cmap=cmap, norm=norm) self.values = values self.boundaries = boundaries self.extend = extend self.spacing = spacing self.orientation = orientation self.drawedges = drawedges self.filled = filled # artists self.solids = None self.lines = None self.dividers = None self.extension_patch1 = None self.extension_patch2 = None if orientation == "vertical": self.cbar_axis = self.ax.yaxis else: self.cbar_axis = self.ax.xaxis if format is None: if isinstance(self.norm, colors.LogNorm): # change both axis for proper aspect self.ax.set_xscale("log") self.ax.set_yscale("log") self.cbar_axis.set_minor_locator(ticker.NullLocator()) formatter = ticker.LogFormatter() else: formatter = None elif isinstance(format, six.string_types): formatter = ticker.FormatStrFormatter(format) else: formatter = format # Assume it is a Formatter if formatter is None: formatter = self.cbar_axis.get_major_formatter() else: self.cbar_axis.set_major_formatter(formatter) if cbook.iterable(ticks): self.cbar_axis.set_ticks(ticks) elif ticks is not None: self.cbar_axis.set_major_locator(ticks) else: self._select_locator(formatter) self._config_axes() self.update_artists() self.set_label_text('')
def psd(x, blocksize=256, NFFT=256, Fs=1, detrend=detrend_none, window=window_hanning, noverlap=0): """ The power spectral density by Welches average periodogram method. The vector x is divided into blocklength length segments. Each segment is detrended by function detrend and windowed by function window. noperlap gives the length of the overlap between segments. The absolute(fft(segment))**2 of each segment are averaged to compute Pxx, with a scaling to correct for power loss due to windowing. Fs is the sampling frequency (samples per time unit). It is used to calculate the Fourier frequencies, freqs, in cycles per time unit. -- detrend is a function, unlike in matlab where it is a vector. -- window can be a function or a vector of length blocksize. To create window vectors see numpy.blackman, numpy.hamming, numpy.bartlett, scipy.signal, scipy.signal.get_window etc. -- if length x < blocksize, it will be zero padded to blocksize Returns the tuple Pxx, freqs Refs: Bendat & Piersol -- Random Data: Analysis and Measurement Procedures, John Wiley & Sons (1986) """ x = np.asarray(x) # make sure we're dealing with a numpy array blocksize=int(blocksize) NFFT=int(NFFT) # zero pad x up to blocksize if it is shorter than blocksize if len(x)<blocksize: n = len(x) x = np.resize(x, (blocksize,)) # Can't use resize method. x[n:] = 0 # for real x, ignore the negative frequencies if np.iscomplexobj(x): numFreqs = blocksize else: numFreqs = blocksize//2+1 if cbook.iterable(window): assert(len(window) == blocksize) windowVals = window else: windowVals = window(np.ones((blocksize,),x.dtype)) step = blocksize-noverlap ind = range(0,len(x)-blocksize+1,step) n = len(ind) Pxx = np.zeros((numFreqs,n), np.float_) # do the ffts of the slices for i in range(n): thisX = x[ind[i]:ind[i]+blocksize] thisX = windowVals * detrend(thisX) fx = (np.absolute(np.fft.fft(thisX,n=NFFT))**2)/(blocksize) Pxx[:,i] = fx[:numFreqs] if n>1: Pxx = Pxx.mean(axis=1) # Scale the spectrum by the norm of the window to compensate for # windowing loss; see Bendat & Piersol Sec 11.5.2 Pxx /= (np.abs(windowVals)**2).sum()/(blocksize) freqs = Fs/np.float(NFFT) * np.arange(numFreqs) return Pxx, freqs
def is_iterable(var): return cbook.iterable(var) and not is_string(var)
def is_scalar_or_string(val): """ Return whether the given object is a scalar or string like. """ return is_string(val) or not cbook.iterable(val)
def setp(obj, *args, **kwargs): """ Set a property on an artist object. matplotlib supports the use of :func:`setp` ("set property") and :func:`getp` to set and get object properties, as well as to do introspection on the object. For example, to set the linestyle of a line to be dashed, you can do:: >>> line, = plot([1,2,3]) >>> setp(line, linestyle='--') If you want to know the valid types of arguments, you can provide the name of the property you want to set without a value:: >>> setp(line, 'linestyle') linestyle: [ '-' | '--' | '-.' | ':' | 'steps' | 'None' ] If you want to see all the properties that can be set, and their possible values, you can do:: >>> setp(line) ... long output listing omitted You may specify another output file to `setp` if `sys.stdout` is not acceptable for some reason using the `file` keyword-only argument:: >>> with fopen('output.log') as f: >>> setp(line, file=f) :func:`setp` operates on a single instance or a iterable of instances. If you are in query mode introspecting the possible values, only the first instance in the sequence is used. When actually setting values, all the instances will be set. e.g., suppose you have a list of two lines, the following will make both lines thicker and red:: >>> x = arange(0,1.0,0.01) >>> y1 = sin(2*pi*x) >>> y2 = sin(4*pi*x) >>> lines = plot(x, y1, x, y2) >>> setp(lines, linewidth=2, color='r') :func:`setp` works with the MATLAB style string/value pairs or with python kwargs. For example, the following are equivalent:: >>> setp(lines, 'linewidth', 2, 'color', 'r') # MATLAB style >>> setp(lines, linewidth=2, color='r') # python style """ if not cbook.iterable(obj): objs = [obj] else: objs = list(cbook.flatten(obj)) insp = ArtistInspector(objs[0]) # file has to be popped before checking if kwargs is empty printArgs = {} if 'file' in kwargs: printArgs['file'] = kwargs.pop('file') if not kwargs and len(args) < 2: if args: print(insp.pprint_setters(prop=args[0]), **printArgs) else: print('\n'.join(insp.pprint_setters()), **printArgs) return if len(args) % 2: raise ValueError('The set args must be string, value pairs') # put args into ordereddict to maintain order funcvals = OrderedDict() for i in range(0, len(args) - 1, 2): funcvals[args[i]] = args[i + 1] ret = [o.update(funcvals) for o in objs] ret.extend([o.set(**kwargs) for o in objs]) return [x for x in cbook.flatten(ret)]
def default_units(x, axis): 'return the default unit for x or None' if iterable(x): for thisx in x: return thisx.unit return x.unit
def add(self, patchlabel='', flows=None, orientations=None, labels='', trunklength=1.0, pathlengths=0.25, prior=None, connect=(0, 0), rotation=0, **kwargs): """ Add a simple Sankey diagram with flows at the same hierarchical level. Return value is the instance of :class:`Sankey`. Optional keyword arguments: =============== =================================================== Keyword Description =============== =================================================== *patchlabel* label to be placed at the center of the diagram Note: *label* (not *patchlabel*) will be passed to the patch through ``**kwargs`` and can be used to create an entry in the legend. *flows* array of flow values By convention, inputs are positive and outputs are negative. *orientations* list of orientations of the paths Valid values are 1 (from/to the top), 0 (from/to the left or right), or -1 (from/to the bottom). If *orientations* == 0, inputs will break in from the left and outputs will break away to the right. *labels* list of specifications of the labels for the flows Each value may be *None* (no labels), '' (just label the quantities), or a labeling string. If a single value is provided, it will be applied to all flows. If an entry is a non-empty string, then the quantity for the corresponding flow will be shown below the string. However, if the *unit* of the main diagram is None, then quantities are never shown, regardless of the value of this argument. *trunklength* length between the bases of the input and output groups *pathlengths* list of lengths of the arrows before break-in or after break-away If a single value is given, then it will be applied to the first (inside) paths on the top and bottom, and the length of all other arrows will be justified accordingly. The *pathlengths* are not applied to the horizontal inputs and outputs. *prior* index of the prior diagram to which this diagram should be connected *connect* a (prior, this) tuple indexing the flow of the prior diagram and the flow of this diagram which should be connected If this is the first diagram or *prior* is *None*, *connect* will be ignored. *rotation* angle of rotation of the diagram [deg] *rotation* is ignored if this diagram is connected to an existing one (using *prior* and *connect*). The interpretation of the *orientations* argument will be rotated accordingly (e.g., if *rotation* == 90, an *orientations* entry of 1 means to/from the left). =============== =================================================== Valid kwargs are :meth:`matplotlib.patches.PathPatch` arguments: %(Patch)s As examples, ``fill=False`` and ``label='A legend entry'``. By default, ``facecolor='#bfd1d4'`` (light blue) and ``linewidth=0.5``. The indexing parameters (*prior* and *connect*) are zero-based. The flows are placed along the top of the diagram from the inside out in order of their index within the *flows* list or array. They are placed along the sides of the diagram from the top down and along the bottom from the outside in. If the the sum of the inputs and outputs is nonzero, the discrepancy will appear as a cubic Bezier curve along the top and bottom edges of the trunk. .. seealso:: :meth:`finish` """ # Check and preprocess the arguments. if flows is None: flows = np.array([1.0, -1.0]) else: flows = np.array(flows) n = flows.shape[0] # Number of flows if rotation is None: rotation = 0 else: # In the code below, angles are expressed in deg/90. rotation /= 90.0 if orientations is None: orientations = [0, 0] assert len(orientations) == n, ( "orientations and flows must have the same length.\n" "orientations has length %d, but flows has length %d." % (len(orientations), n)) if labels != '' and getattr(labels, '__iter__', False): # iterable() isn't used because it would give True if labels is a # string assert len(labels) == n, ( "If labels is a list, then labels and flows must have the " "same length.\nlabels has length %d, but flows has length %d." % (len(labels), n)) else: labels = [labels] * n assert trunklength >= 0, ( "trunklength is negative.\nThis isn't allowed, because it would " "cause poor layout.") if np.absolute(np.sum(flows)) > self.tolerance: verbose.report( "The sum of the flows is nonzero (%f).\nIs the " "system not at steady state?" % np.sum(flows), 'helpful') scaled_flows = self.scale * flows gain = sum(max(flow, 0) for flow in scaled_flows) loss = sum(min(flow, 0) for flow in scaled_flows) if not (0.5 <= gain <= 2.0): verbose.report( "The scaled sum of the inputs is %f.\nThis may " "cause poor layout.\nConsider changing the scale so" " that the scaled sum is approximately 1.0." % gain, 'helpful') if not (-2.0 <= loss <= -0.5): verbose.report( "The scaled sum of the outputs is %f.\nThis may " "cause poor layout.\nConsider changing the scale so" " that the scaled sum is approximately 1.0." % gain, 'helpful') if prior is not None: assert prior >= 0, "The index of the prior diagram is negative." assert min(connect) >= 0, ( "At least one of the connection indices is negative.") assert prior < len(self.diagrams), ( "The index of the prior diagram is %d, but there are " "only %d other diagrams.\nThe index is zero-based." % (prior, len(self.diagrams))) assert connect[0] < len(self.diagrams[prior].flows), ( "The connection index to the source diagram is %d, but " "that diagram has only %d flows.\nThe index is zero-based." % (connect[0], len(self.diagrams[prior].flows))) assert connect[1] < n, ( "The connection index to this diagram is %d, but this diagram" "has only %d flows.\n The index is zero-based." % (connect[1], n)) assert self.diagrams[prior].angles[connect[0]] is not None, ( "The connection cannot be made. Check that the magnitude " "of flow %d of diagram %d is greater than or equal to the " "specified tolerance." % (connect[0], prior)) flow_error = (self.diagrams[prior].flows[connect[0]] + flows[connect[1]]) assert abs(flow_error) < self.tolerance, ( "The scaled sum of the connected flows is %f, which is not " "within the tolerance (%f)." % (flow_error, self.tolerance)) # Determine if the flows are inputs. are_inputs = [None] * n for i, flow in enumerate(flows): if flow >= self.tolerance: are_inputs[i] = True elif flow <= -self.tolerance: are_inputs[i] = False else: verbose.report( "The magnitude of flow %d (%f) is below the " "tolerance (%f).\nIt will not be shown, and it " "cannot be used in a connection." % (i, flow, self.tolerance), 'helpful') # Determine the angles of the arrows (before rotation). angles = [None] * n for i, (orient, is_input) in enumerate(zip(orientations, are_inputs)): if orient == 1: if is_input: angles[i] = DOWN elif not is_input: # Be specific since is_input can be None. angles[i] = UP elif orient == 0: if is_input is not None: angles[i] = RIGHT else: assert orient == -1, ("The value of orientations[%d] is %d, " "but it must be -1, 0, or 1." % (i, orient)) if is_input: angles[i] = UP elif not is_input: angles[i] = DOWN # Justify the lengths of the paths. if iterable(pathlengths): assert len(pathlengths) == n, ( "If pathlengths is a list, then pathlengths and flows must " "have the same length.\npathlengths has length %d, but flows " "has length %d." % (len(pathlengths), n)) else: # Make pathlengths into a list. urlength = pathlengths ullength = pathlengths lrlength = pathlengths lllength = pathlengths d = dict(RIGHT=pathlengths) pathlengths = [d.get(angle, 0) for angle in angles] # Determine the lengths of the top-side arrows # from the middle outwards. for i, (angle, is_input, flow) in enumerate(zip(angles, are_inputs, scaled_flows)): if angle == DOWN and is_input: pathlengths[i] = ullength ullength += flow elif angle == UP and not is_input: pathlengths[i] = urlength urlength -= flow # Flow is negative for outputs. # Determine the lengths of the bottom-side arrows # from the middle outwards. for i, (angle, is_input, flow) in enumerate( reversed(list(zip(angles, are_inputs, scaled_flows)))): if angle == UP and is_input: pathlengths[n - i - 1] = lllength lllength += flow elif angle == DOWN and not is_input: pathlengths[n - i - 1] = lrlength lrlength -= flow # Determine the lengths of the left-side arrows # from the bottom upwards. has_left_input = False for i, (angle, is_input, spec) in enumerate( reversed( list( zip(angles, are_inputs, zip(scaled_flows, pathlengths))))): if angle == RIGHT: if is_input: if has_left_input: pathlengths[n - i - 1] = 0 else: has_left_input = True # Determine the lengths of the right-side arrows # from the top downwards. has_right_output = False for i, (angle, is_input, spec) in enumerate( zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))): if angle == RIGHT: if not is_input: if has_right_output: pathlengths[i] = 0 else: has_right_output = True # Begin the subpaths, and smooth the transition if the sum of the flows # is nonzero. urpath = [ ( Path.MOVETO, [ (self.gap - trunklength / 2.0), # Upper right gain / 2.0 ]), (Path.LINETO, [(self.gap - trunklength / 2.0) / 2.0, gain / 2.0]), (Path.CURVE4, [(self.gap - trunklength / 2.0) / 8.0, gain / 2.0]), (Path.CURVE4, [(trunklength / 2.0 - self.gap) / 8.0, -loss / 2.0]), (Path.LINETO, [(trunklength / 2.0 - self.gap) / 2.0, -loss / 2.0]), (Path.LINETO, [(trunklength / 2.0 - self.gap), -loss / 2.0]) ] llpath = [ ( Path.LINETO, [ (trunklength / 2.0 - self.gap), # Lower left loss / 2.0 ]), (Path.LINETO, [(trunklength / 2.0 - self.gap) / 2.0, loss / 2.0]), (Path.CURVE4, [(trunklength / 2.0 - self.gap) / 8.0, loss / 2.0]), (Path.CURVE4, [(self.gap - trunklength / 2.0) / 8.0, -gain / 2.0]), (Path.LINETO, [(self.gap - trunklength / 2.0) / 2.0, -gain / 2.0]), (Path.LINETO, [(self.gap - trunklength / 2.0), -gain / 2.0]) ] lrpath = [( Path.LINETO, [ (trunklength / 2.0 - self.gap), # Lower right loss / 2.0 ])] ulpath = [( Path.LINETO, [ self.gap - trunklength / 2.0, # Upper left gain / 2.0 ])] # Add the subpaths and assign the locations of the tips and labels. tips = np.zeros((n, 2)) label_locations = np.zeros((n, 2)) # Add the top-side inputs and outputs from the middle outwards. for i, (angle, is_input, spec) in enumerate( zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))): if angle == DOWN and is_input: tips[i, :], label_locations[i, :] = self._add_input( ulpath, angle, *spec) elif angle == UP and not is_input: tips[i, :], label_locations[i, :] = self._add_output( urpath, angle, *spec) # Add the bottom-side inputs and outputs from the middle outwards. for i, (angle, is_input, spec) in enumerate( reversed( list( zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))))): if angle == UP and is_input: tip, label_location = self._add_input(llpath, angle, *spec) tips[n - i - 1, :] = tip label_locations[n - i - 1, :] = label_location elif angle == DOWN and not is_input: tip, label_location = self._add_output(lrpath, angle, *spec) tips[n - i - 1, :] = tip label_locations[n - i - 1, :] = label_location # Add the left-side inputs from the bottom upwards. has_left_input = False for i, (angle, is_input, spec) in enumerate( reversed( list( zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))))): if angle == RIGHT and is_input: if not has_left_input: # Make sure the lower path extends # at least as far as the upper one. if llpath[-1][1][0] > ulpath[-1][1][0]: llpath.append( (Path.LINETO, [ulpath[-1][1][0], llpath[-1][1][1]])) has_left_input = True tip, label_location = self._add_input(llpath, angle, *spec) tips[n - i - 1, :] = tip label_locations[n - i - 1, :] = label_location # Add the right-side outputs from the top downwards. has_right_output = False for i, (angle, is_input, spec) in enumerate( zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))): if angle == RIGHT and not is_input: if not has_right_output: # Make sure the upper path extends # at least as far as the lower one. if urpath[-1][1][0] < lrpath[-1][1][0]: urpath.append( (Path.LINETO, [lrpath[-1][1][0], urpath[-1][1][1]])) has_right_output = True tips[i, :], label_locations[i, :] = self._add_output( urpath, angle, *spec) # Trim any hanging vertices. if not has_left_input: ulpath.pop() llpath.pop() if not has_right_output: lrpath.pop() urpath.pop() # Concatenate the subpaths in the correct order (clockwise from top). path = (urpath + self._revert(lrpath) + llpath + self._revert(ulpath) + [(Path.CLOSEPOLY, urpath[0][1])]) # Create a patch with the Sankey outline. codes, vertices = list(zip(*path)) vertices = np.array(vertices) def _get_angle(a, r): if a is None: return None else: return a + r if prior is None: if rotation != 0: # By default, none of this is needed. angles = [_get_angle(angle, rotation) for angle in angles] rotate = Affine2D().rotate_deg(rotation * 90).transform_point tips = rotate(tips) label_locations = rotate(label_locations) vertices = rotate(vertices) text = self.ax.text(0, 0, s=patchlabel, ha='center', va='center') else: rotation = (self.diagrams[prior].angles[connect[0]] - angles[connect[1]]) angles = [_get_angle(angle, rotation) for angle in angles] rotate = Affine2D().rotate_deg(rotation * 90).transform_point tips = rotate(tips) offset = self.diagrams[prior].tips[connect[0]] - tips[connect[1]] translate = Affine2D().translate(*offset).transform_point tips = translate(tips) label_locations = translate(rotate(label_locations)) vertices = translate(rotate(vertices)) kwds = dict(s=patchlabel, ha='center', va='center') text = self.ax.text(*offset, **kwds) if False: # Debug print("llpath\n", llpath) print("ulpath\n", self._revert(ulpath)) print("urpath\n", urpath) print("lrpath\n", self._revert(lrpath)) xs, ys = list(zip(*vertices)) self.ax.plot(xs, ys, 'go-') patch = PathPatch( Path(vertices, codes), fc=kwargs.pop('fc', kwargs.pop('facecolor', '#bfd1d4')), # Custom defaults lw=kwargs.pop('lw', kwargs.pop('linewidth', 0.5)), **kwargs) self.ax.add_patch(patch) # Add the path labels. texts = [] for number, angle, label, location in zip(flows, angles, labels, label_locations): if label is None or angle is None: label = '' elif self.unit is not None: quantity = self.format % abs(number) + self.unit if label != '': label += "\n" label += quantity texts.append( self.ax.text(x=location[0], y=location[1], s=label, ha='center', va='center')) # Text objects are placed even they are empty (as long as the magnitude # of the corresponding flow is larger than the tolerance) in case the # user wants to provide labels later. # Expand the size of the diagram if necessary. self.extent = (min(np.min(vertices[:, 0]), np.min(label_locations[:, 0]), self.extent[0]), max(np.max(vertices[:, 0]), np.max(label_locations[:, 0]), self.extent[1]), min(np.min(vertices[:, 1]), np.min(label_locations[:, 1]), self.extent[2]), max(np.max(vertices[:, 1]), np.max(label_locations[:, 1]), self.extent[3])) # Include both vertices _and_ label locations in the extents; there are # where either could determine the margins (e.g., arrow shoulders). # Add this diagram as a subdiagram. self.diagrams.append( Bunch(patch=patch, flows=flows, angles=angles, tips=tips, text=text, texts=texts)) # Allow a daisy-chained call structure (see docstring for the class). return self
def bar3d(self, x, y, z, dx, dy, dz, color='b', zsort='average', *args, **kwargs): ''' Generate a 3D bar, or multiple bars. When generating multiple bars, x, y, z have to be arrays. dx, dy, dz can be arrays or scalars. *color* can be: - A single color value, to color all bars the same color. - An array of colors of length N bars, to color each bar independently. - An array of colors of length 6, to color the faces of the bars similarly. - An array of colors of length 6 * N bars, to color each face independently. When coloring the faces of the boxes specifically, this is the order of the coloring: 1. -Z (bottom of box) 2. +Z (top of box) 3. -Y 4. +Y 5. -X 6. +X Keyword arguments are passed onto :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` ''' had_data = self.has_data() if not cbook.iterable(x): x = [x] if not cbook.iterable(y): y = [y] if not cbook.iterable(z): z = [z] if not cbook.iterable(dx): dx = [dx] if not cbook.iterable(dy): dy = [dy] if not cbook.iterable(dz): dz = [dz] if len(dx) == 1: dx = dx * len(x) if len(dy) == 1: dy = dy * len(y) if len(dz) == 1: dz = dz * len(z) if len(x) != len(y) or len(x) != len(z): warnings.warn('x, y, and z must be the same length.') minx, miny, minz = 1e20, 1e20, 1e20 maxx, maxy, maxz = -1e20, -1e20, -1e20 polys = [] for xi, yi, zi, dxi, dyi, dzi in zip(x, y, z, dx, dy, dz): minx = min(xi, minx) maxx = max(xi + dxi, maxx) miny = min(yi, miny) maxy = max(yi + dyi, maxy) minz = min(zi, minz) maxz = max(zi + dzi, maxz) polys.extend([ ((xi, yi, zi), (xi + dxi, yi, zi), (xi + dxi, yi + dyi, zi), (xi, yi + dyi, zi)), ((xi, yi, zi + dzi), (xi + dxi, yi, zi + dzi), (xi + dxi, yi + dyi, zi + dzi), (xi, yi + dyi, zi + dzi)), ((xi, yi, zi), (xi + dxi, yi, zi), (xi + dxi, yi, zi + dzi), (xi, yi, zi + dzi)), ((xi, yi + dyi, zi), (xi + dxi, yi + dyi, zi), (xi + dxi, yi + dyi, zi + dzi), (xi, yi + dyi, zi + dzi)), ((xi, yi, zi), (xi, yi + dyi, zi), (xi, yi + dyi, zi + dzi), (xi, yi, zi + dzi)), ((xi + dxi, yi, zi), (xi + dxi, yi + dyi, zi), (xi + dxi, yi + dyi, zi + dzi), (xi + dxi, yi, zi + dzi)), ]) facecolors = [] if color is None: # no color specified facecolors = [None] * len(x) elif len(color) == len(x): # bar colors specified, need to expand to number of faces for c in color: facecolors.extend([c] * 6) else: # a single color specified, or face colors specified explicitly facecolors = list(colorConverter.to_rgba_array(color)) if len(facecolors) < len(x): facecolors *= (6 * len(x)) normals = self._generate_normals(polys) sfacecolors = self._shade_colors(facecolors, normals) col = art3d.Poly3DCollection(polys, zsort=zsort, facecolor=sfacecolors, *args, **kwargs) self.add_collection(col) self.auto_scale_xyz((minx, maxx), (miny, maxy), (minz, maxz), had_data)
def julian2num(j): 'convert a Julian date (or sequence) to a matplotlib date (or sequence)' if cbook.iterable(j): j = npy.asarray(j) return j + 1721425.5
def fetch_historical_yahoo(ticker, date1, date2, cachename=None, dividends=False): """ Fetch historical data for ticker between date1 and date2. date1 and date2 are date or datetime instances, or (year, month, day) sequences. Ex: fh = fetch_historical_yahoo('^GSPC', (2000, 1, 1), (2001, 12, 31)) cachename is the name of the local file cache. If None, will default to the md5 hash or the url (which incorporates the ticker and date range) set dividends=True to return dividends instead of price data. With this option set, parse functions will not work a file handle is returned """ ticker = ticker.upper() if iterable(date1): d1 = (date1[1] - 1, date1[2], date1[0]) else: d1 = (date1.month - 1, date1.day, date1.year) if iterable(date2): d2 = (date2[1] - 1, date2[2], date2[0]) else: d2 = (date2.month - 1, date2.day, date2.year) if dividends: g = 'v' verbose.report('Retrieving dividends instead of prices') else: g = 'd' urlFmt = 'http://ichart.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=%s&ignore=.csv' url = urlFmt % (d1[0], d1[1], d1[2], d2[0], d2[1], d2[2], ticker, g) # Cache the finance data if cachename is supplied, or there is a writable # cache directory. if cachename is None and cachedir is not None: cachename = os.path.join(cachedir, md5(url).hexdigest()) if cachename is not None: if os.path.exists(cachename): fh = open(cachename) verbose.report('Using cachefile %s for %s' % (cachename, ticker)) else: mkdirs(os.path.abspath(os.path.dirname(cachename))) with contextlib.closing(urlopen(url)) as urlfh: with open(cachename, 'wb') as fh: fh.write(urlfh.read()) verbose.report('Saved %s data to cache file %s' % (ticker, cachename)) fh = open(cachename, 'r') return fh else: return urlopen(url)
def num2julian(n): 'convert a matplotlib date (or seguence) to a Julian date (or sequence)' if cbook.iterable(n): n = npy.asarray(n) return n - 1721425.5
def draw_nx_tapered_edges(G, pos, edgelist=None, width=0.5, edge_color='k', style='solid', alpha=1.0, edge_cmap=None, edge_vmin=None, edge_vmax=None, ax=None, label=None, highlight=None, tapered=False, **kwds): """Draw the edges of the graph G. This draws only the edges of the graph G. Parameters ---------- G : graph A networkx graph pos : dictionary A dictionary with nodes as keys and positions as values. Positions should be sequences of length 2. edgelist : collection of edge tuples Draw only specified edges(default=G.edges()) width : float, or array of floats Line width of edges (default=1.0) edge_color : color string, or array of floats Edge color. Can be a single color format string (default='r'), or a sequence of colors with the same length as edgelist. If numeric values are specified they will be mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters. style : string Edge line style (default='solid') (solid|dashed|dotted,dashdot) alpha : float The edge transparency (default=1.0) edge_ cmap : Matplotlib colormap Colormap for mapping intensities of edges (default=None) edge_vmin,edge_vmax : floats Minimum and maximum for edge colormap scaling (default=None) ax : Matplotlib Axes object, optional Draw the graph in the specified Matplotlib axes. label : [None| string] Label for legend Returns ------- matplotlib.collection.LineCollection `LineCollection` of the edges Examples -------- >>> G=nx.dodecahedral_graph() >>> edges=nx.draw_networkx_edges(G,pos=nx.spring_layout(G)) Also see the NetworkX drawing examples at http://networkx.github.io/documentation/latest/gallery.html See Also -------- draw() draw_networkx() draw_networkx_nodes() draw_networkx_labels() draw_networkx_edge_labels() """ if ax is None: ax = plt.gca() if edgelist is None: edgelist = list(G.edges()) if not edgelist or len(edgelist) == 0: # no edges! return None if highlight is not None and (isinstance(edge_color, str) or not cb.iterable(edge_color)): idMap = {} nodes = G.nodes() for i in range(len(nodes)): idMap[nodes[i]] = i ecol = [edge_color] * len(edgelist) eHighlight = [ highlight[idMap[edge[0]]] or highlight[idMap[edge[1]]] for edge in edgelist ] for i in range(len(eHighlight)): if eHighlight[i]: ecol[i] = '0.0' edge_color = ecol # set edge positions if not np.iterable(width): lw = np.full(len(edgelist), width) else: lw = width edge_pos = [] wdScale = 0.01 for i in range(len(edgelist)): e = edgelist[i] w = wdScale * lw[i] / 2 p0 = pos[e[0]] p1 = pos[e[1]] dx = p1[0] - p0[0] dy = p1[1] - p0[1] l = math.sqrt(dx * dx + dy * dy) edge_pos.append( ((p0[0] + w * dy / l, p0[1] - w * dx / l), (p0[0] - w * dy / l, p0[1] + w * dx / l), (p1[0], p1[1]))) edge_vertices = np.asarray(edge_pos) if not isinstance(edge_color, str) \ and np.iterable(edge_color) \ and len(edge_color) == len(edge_vertices): if np.alltrue([isinstance(c, str) for c in edge_color]): # (should check ALL elements) # list of color letters such as ['k','r','k',...] edge_colors = tuple( [colorConverter.to_rgba(c, alpha) for c in edge_color]) elif np.alltrue([not isinstance(c, str) for c in edge_color]): # If color specs are given as (rgb) or (rgba) tuples, we're OK if np.alltrue( [cb.iterable(c) and len(c) in (3, 4) for c in edge_color]): edge_colors = tuple(edge_color) else: # numbers (which are going to be mapped with a colormap) edge_colors = None else: raise ValueError( 'edge_color must consist of either color names or numbers') else: if isinstance(edge_color, str) or len(edge_color) == 1: edge_colors = (colorConverter.to_rgba(edge_color, alpha), ) else: raise ValueError( 'edge_color must be a single color or list of exactly m colors where m is the number or edges' ) if tapered: edge_collection = PolyCollection( edge_vertices, facecolors=edge_colors, linewidths=0, antialiaseds=(1, ), transOffset=ax.transData, ) else: edge_collection = LineCollection( edge_pos, colors=edge_colors, linewidths=lw, antialiaseds=(1, ), linestyle=style, transOffset=ax.transData, ) edge_collection.set_zorder(1) # edges go behind nodes edge_collection.set_label(label) ax.add_collection(edge_collection) # Set alpha globally if provided as a scalar. if isinstance(alpha, numbers.Number): edge_collection.set_alpha(alpha) if edge_colors is None: if edge_cmap is not None: assert (isinstance(edge_cmap, Colormap)) edge_collection.set_array(np.asarray(edge_color)) edge_collection.set_cmap(edge_cmap) if edge_vmin is not None or edge_vmax is not None: edge_collection.set_clim(edge_vmin, edge_vmax) else: edge_collection.autoscale() # update view minx = np.amin(np.ravel(edge_vertices[:, :, 0])) maxx = np.amax(np.ravel(edge_vertices[:, :, 0])) miny = np.amin(np.ravel(edge_vertices[:, :, 1])) maxy = np.amax(np.ravel(edge_vertices[:, :, 1])) w = maxx - minx h = maxy - miny padx, pady = 0.05 * w, 0.05 * h corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady) ax.update_datalim(corners) ax.autoscale_view() return edge_collection
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 __init__(self, artists, tolerance=5, formatter=None, point_labels=None, display='one-per-axes', draggable=False, hover=False, props_override=None, keybindings=True, date_format='%x %X', display_button=1, hide_button=3, keep_inside=True, **kwargs): """Create the data cursor and connect it to the relevant figure. Parameters ----------- artists : a matplotlib artist or sequence of artists. The artists to make selectable and display information for. tolerance : number, optional The radius (in points) that the mouse click must be within to select the artist. formatter : function, optional A function that accepts arbitrary kwargs and returns a string that will be displayed with annotate. The `x`, `y`, `event`, `ind`, and `label` kwargs will always be present. See the ``mpldatacursor.datacursor`` function docstring for more information. point_labels : sequence or dict, optional Labels for "subitems" of an artist, passed to the formatter function as the `point_label` kwarg. May be either a single sequence (used for all artists) or a dict of artist:sequence pairs. display : {'one-per-axes', 'single', 'multiple'}, optional Controls whether more than one annotation box will be shown. draggable : boolean, optional Controls whether or not the annotation box will be interactively draggable to a new location after being displayed. Default: False. hover : boolean, optional If True, the datacursor will "pop up" when the mouse hovers over an artist. Defaults to False. Enabling hover also sets `display="single"` and `draggable=False`. props_override : function, optional If specified, this function customizes the parameters passed into the formatter function and the x, y location that the datacursor "pop up" "points" to. This is often useful to make the annotation "point" to a specific side or corner of an artist, regardless of the position clicked. The function is passed the same kwargs as the `formatter` function and is expected to return a dict with at least the keys "x" and "y" (and probably several others). Expected call signature: `props_dict = props_override(**kwargs)` keybindings : boolean or dict, optional By default, the keys "d" and "t" will be bound to hiding/showing all annotation boxes and toggling interactivity for datacursors, respectively. "<shift> + <right>" and "<shift> + <left>" will be bound to moving the datacursor to the next and previous item in the sequence for artists that support it. If keybindings is False, the ability to hide/toggle datacursors interactively will be disabled. Alternatively, a dict mapping "hide", "toggle", "next", and "previous" to matplotlib key specifications may specified to customize the keyboard shortcuts. Note that hitting the "hide" key once will hide datacursors, and hitting it again will show all of the hidden datacursors. date_format : string, optional The strftime-style formatting string for dates. Used only if the x or y axes have been set to display dates. Defaults to "%x %X". display_button: int, optional The mouse button that will triggers displaying an annotation box. Defaults to 1, for left-clicking. (Common options are 1:left-click, 2:middle-click, 3:right-click) hide_button: int or None, optional The mouse button that triggers hiding the selected annotation box. Defaults to 3, for right-clicking. (Common options are 1:left-click, 2:middle-click, 3:right-click, None:hiding disabled) keep_inside : boolean, optional Whether or not to adjust the x,y offset to keep the text box inside the figure. This option has no effect on draggable datacursors. Defaults to True. Note: Currently disabled on OSX and NbAgg/notebook backends. **kwargs : additional keyword arguments, optional Additional keyword arguments are passed on to annotate. """ def filter_artists(artists): """Replace ContourSets, etc with their constituent artists.""" output = [] for item in artists: if isinstance(item, ContourSet): output += item.collections elif isinstance(item, Container): children = item.get_children() for child in children: child._mpldatacursor_label = item.get_label() child._mpldatacursor_parent = item output += children else: output.append(item) return output if not cbook.iterable(artists): artists = [artists] #-- Deal with contour sets... ------------------------------------- # These are particularly difficult, as the original z-value array # is never associated with the ContourSet, and they're not "normal" # artists (they're not actually added to the axes). Not only that, but # the PatchCollections created by filled contours don't even fire a # pick event for points inside them, only on their edges. At any rate, # this is a somewhat hackish way of handling contours, but it works. self.artists = filter_artists(artists) self.contour_levels = {} for cs in [x for x in artists if isinstance(x, ContourSet)]: for z, artist in zip(cs.levels, cs.collections): self.contour_levels[artist] = z valid_display_options = ['single', 'one-per-axes', 'multiple'] if display in valid_display_options: self.display = display else: raise ValueError('"display" must be one of the following: '\ ', '.join(valid_display_options)) self.hover = hover if self.hover: self.display = 'single' self.draggable = False self.keep_inside = keep_inside self.tolerance = tolerance self.point_labels = point_labels self.draggable = draggable self.date_format = date_format self.props_override = props_override self.display_button = display_button self.hide_button = hide_button self.axes = tuple(set(art.axes for art in self.artists)) self.figures = tuple(set(ax.figure for ax in self.axes)) self._mplformatter = ScalarFormatter(useOffset=False, useMathText=True) self._hidden = False self._last_event = None self._last_annotation = None if self.draggable: # If we're dealing with draggable cursors, don't try to override # the x,y position. Otherwise, dragging the cursor outside the # figure will have unexpected consequences. self.keep_inside = False if formatter is None: self.formatter = self._formatter else: self.formatter = formatter self._annotation_kwargs = kwargs self.annotations = {} if self.display is not 'multiple': for ax in self.axes: self.annotations[ax] = self.annotate(ax, **kwargs) # Hide the annotation box until clicked... self.annotations[ax].set_visible(False) if keybindings: if keybindings is True: self.keybindings = self.default_keybindings else: self.keybindings = self.default_keybindings.copy() self.keybindings.update(keybindings) for fig in self.figures: fig.canvas.mpl_connect('key_press_event', self._on_keypress) self.enable() # We need to make sure the DataCursor isn't garbage collected until the # figure is. Matplotlib's weak references won't keep this DataCursor # instance alive in all cases. for fig in self.figures: try: fig._mpldatacursors.append(self) except AttributeError: fig._mpldatacursors = [self]
def __call__(self, value, clip=None): #read in parameters method = self.stretch exponent = self.exponent midpoint = self.midpoint # ORIGINAL MATPLOTLIB CODE if clip is None: clip = self.clip if cbook.iterable(value): vtype = 'array' val = ma.asarray(value).astype(np.float) else: vtype = 'scalar' val = ma.array([value]).astype(np.float) self.autoscale_None(val) vmin, vmax = self.vmin, self.vmax if vmin > vmax: raise ValueError("minvalue must be less than or equal to maxvalue") elif vmin == vmax: return 0.0 * val else: if clip: mask = ma.getmask(val) val = ma.array(np.clip(val.filled(vmax), vmin, vmax), mask=mask) result = (val - vmin) * (1.0 / (vmax - vmin)) # CUSTOM APLPY CODE # Keep track of negative values negative = result < 0. if self.stretch == 'linear': pass elif self.stretch == 'log': result = ma.log10(result * (self.midpoint - 1.) + 1.) \ / ma.log10(self.midpoint) elif self.stretch == 'sqrt': result = ma.sqrt(result) elif self.stretch == 'arcsinh': result = ma.arcsinh(result / self.midpoint) \ / ma.arcsinh(1. / self.midpoint) elif self.stretch == 'power': result = ma.power(result, exponent) else: raise Exception("Unknown stretch in APLpyNormalize: %s" % self.stretch) # Now set previously negative values to 0, as these are # different from true NaN values in the FITS image result[negative] = -np.inf if vtype == 'scalar': result = result[0] return result
def nyquist(self, ax=None, pair=(0, 0), label='nyquist', title="Nyquist plot", xlabel="Real axis", ylabel="Imaginary axis", labels=None, colors=['b', 'g', 'r', 'c', 'm', 'y', 'k'], leg_kwargs={}, **kwargs): r"""Plot the linearizations onto a single Nyquist diagram. This method calls :meth:`~LinRes.nyquist` from the included instances of :class:`LinRes`. **Parameters:** - *ax*: Axes onto which the Nyquist diagrams should be plotted If *ax* is not provided, then axes will be created in a new figure. - *pair*: Tuple of (input name or index, output name or index) for the transfer function to be chosen from each system (applied to all) This is ignored if the system is SISO. - *label*: Label for the figure (ignored if axes is provided) This is used as the base filename if the figure is saved using :func:`~modelicares.util.save` or :func:`~modelicares.util.saveall`. - *title*: Title for the figure - *xlabel*: x-axis label - *ylabel*: y-axis label - *labels*: Label or list of labels for the legends If *labels* is *None*, then no label will be used. If it is an empty string (''), then the base filenames will be used. - *colors*: Color or list of colors that will be used sequentially Each may be a character, grayscale, or rgb value. .. Seealso:: http://matplotlib.sourceforge.net/api/colors_api.html - *leg_kwargs*: Dictionary of keyword arguments for :func:`matplotlib.pyplot.legend` If *leg_kwargs* is *None*, then no legend will be shown. - *\*\*kwargs*: Additional plotting arguments: - *freqs*: List or frequencies or tuple of (min, max) frequencies over which to plot the system response. If *freqs* is *None*, then an appropriate range will be determined automatically. - *in_Hz*: If *True* (default), the frequencies (*freqs*) are in Hz and should be plotted in Hz (otherwise, rad/s) - *mark*: *True*, if the -1 point should be marked on the plot - *show_axes*: *True*, if the axes should be shown - *skip*: Mark every nth frequency on the plot with a dot If *skip* is 0 or *None*, then the frequencies are not marked. - *label_freq*: If *True*, if the marked frequencies should be labeled Other keyword arguments are passed to :func:`matplotlib.pyplot.plot`. **Returns:** 1. *ax*: Axes of the Nyquist plot **Example:** .. plot:: examples/PIDs-nyquist.py :alt: Nyquist plot of PID with varying parameters """ # Create axes if necessary. if not ax: fig = util.figure(label) ax = fig.add_subplot(111, aspect='equal') # Process the labels input. labels = self._get_labels(labels) # Set up the color(s). if not iterable(colors): # Use the single color for all plots. colors = (colors, ) n_colors = len(colors) # Create the plots. label_freq = kwargs.pop('label_freq', None) for i, (lin, label) in enumerate(zip(self, labels)): if lin.sys.inputs > 1 or lin.sys.outputs > 1: sys = lin.to_siso(pair[0], pair[1]) else: sys = lin.sys nyquist_plot( sys, mark=False, label=label, ax=ax, label_freq=(i == 0 if label_freq is None else label_freq), color=colors[np.mod(i, n_colors)], **kwargs) # Decorate and finish. ax.set_title(title) if xlabel: # Without this check, xlabel=None will give a label of "None". ax.set_xlabel(xlabel) if ylabel: # Same purpose ax.set_ylabel(ylabel) if leg_kwargs is not None: loc = leg_kwargs.pop('loc', 'best') ax.legend(loc=loc, **leg_kwargs) return ax
def num2julian(n): 'Convert a matplotlib date (or sequence) to a Julian date (or sequence).' if cbook.iterable(n): n = np.asarray(n) return n + 1721424.5
def set_3d_properties(self, verts, zs=0, zdir='z'): if not iterable(zs): zs = [zs] * len(verts) self._segment3d = [juggle_axes(x, y, z, zdir) \ for ((x, y), z) in zip(verts, zs)] self._facecolor3d = Patch.get_facecolor(self)
def setp(obj, *args, **kwargs): """ Set a property on an artist object. matplotlib supports the use of :func:`setp` ("set property") and :func:`getp` to set and get object properties, as well as to do introspection on the object. For example, to set the linestyle of a line to be dashed, you can do:: >>> line, = plot([1,2,3]) >>> setp(line, linestyle='--') If you want to know the valid types of arguments, you can provide the name of the property you want to set without a value:: >>> setp(line, 'linestyle') linestyle: [ '-' | '--' | '-.' | ':' | 'steps' | 'None' ] If you want to see all the properties that can be set, and their possible values, you can do:: >>> setp(line) ... long output listing omitted :func:`setp` operates on a single instance or a list of instances. If you are in query mode introspecting the possible values, only the first instance in the sequence is used. When actually setting values, all the instances will be set. e.g., suppose you have a list of two lines, the following will make both lines thicker and red:: >>> x = arange(0,1.0,0.01) >>> y1 = sin(2*pi*x) >>> y2 = sin(4*pi*x) >>> lines = plot(x, y1, x, y2) >>> setp(lines, linewidth=2, color='r') :func:`setp` works with the MATLAB style string/value pairs or with python kwargs. For example, the following are equivalent:: >>> setp(lines, 'linewidth', 2, 'color', 'r') # MATLAB style >>> setp(lines, linewidth=2, color='r') # python style """ insp = ArtistInspector(obj) if len(kwargs) == 0 and len(args) == 0: print('\n'.join(insp.pprint_setters())) return if len(kwargs) == 0 and len(args) == 1: print(insp.pprint_setters(prop=args[0])) return if not cbook.iterable(obj): objs = [obj] else: objs = cbook.flatten(obj) if len(args) % 2: raise ValueError('The set args must be string, value pairs') funcvals = [] for i in range(0, len(args) - 1, 2): funcvals.append((args[i], args[i + 1])) funcvals.extend(kwargs.items()) ret = [] for o in objs: for s, val in funcvals: s = s.lower() funcName = "set_%s" % s func = getattr(o, funcName) ret.extend([func(val)]) return [x for x in cbook.flatten(ret)]
def draw_networkx_edges(G, pos, edgelist=None, width=1.0, edge_color='k', style='solid', alpha=1.0, arrowstyle='-|>', arrowsize=10, edge_cmap=None, edge_vmin=None, edge_vmax=None, ax=None, arrows=True, label=None, node_size=300, nodelist=None, node_shape="o", **kwds): """Draw the edges of the graph G. This draws only the edges of the graph G. Parameters ---------- G : graph A networkx graph pos : dictionary A dictionary with nodes as keys and positions as values. Positions should be sequences of length 2. edgelist : collection of edge tuples Draw only specified edges(default=G.edges()) width : float, or array of floats Line width of edges (default=1.0) edge_color : color string, or array of floats Edge color. Can be a single color format string (default='r'), or a sequence of colors with the same length as edgelist. If numeric values are specified they will be mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters. style : string Edge line style (default='solid') (solid|dashed|dotted,dashdot) alpha : float The edge transparency (default=1.0) edge_ cmap : Matplotlib colormap Colormap for mapping intensities of edges (default=None) edge_vmin,edge_vmax : floats Minimum and maximum for edge colormap scaling (default=None) ax : Matplotlib Axes object, optional Draw the graph in the specified Matplotlib axes. arrows : bool, optional (default=True) For directed graphs, if True draw arrowheads. Note: Arrows will be the same color as edges. arrowstyle : str, optional (default='-|>') For directed graphs, choose the style of the arrow heads. See :py:class: `matplotlib.patches.ArrowStyle` for more options. arrowsize : int, optional (default=10) For directed graphs, choose the size of the arrow head head's length and width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute `mutation_scale` for more info. label : [None| string] Label for legend Returns ------- matplotlib.collection.LineCollection `LineCollection` of the edges list of matplotlib.patches.FancyArrowPatch `FancyArrowPatch` instances of the directed edges Depending whether the drawing includes arrows or not. Notes ----- For directed graphs, arrows are drawn at the head end. Arrows can be turned off with keyword arrows=False. Be sure to include `node_size` as a keyword argument; arrows are drawn considering the size of nodes. Examples -------- >>> G = nx.dodecahedral_graph() >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) >>> G = nx.DiGraph() >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)]) >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) >>> alphas = [0.3, 0.4, 0.5] >>> for i, arc in enumerate(arcs): # change alpha values of arcs ... arc.set_alpha(alphas[i]) Also see the NetworkX drawing examples at https://networkx.github.io/documentation/latest/auto_examples/index.html See Also -------- draw() draw_networkx() draw_networkx_nodes() draw_networkx_labels() draw_networkx_edge_labels() """ try: import matplotlib import matplotlib.pyplot as plt import matplotlib.cbook as cb from matplotlib.colors import colorConverter, Colormap, Normalize from matplotlib.collections import LineCollection from matplotlib.patches import FancyArrowPatch import numpy as np except ImportError: raise ImportError("Matplotlib required for draw()") except RuntimeError: print("Matplotlib unable to open display") raise if ax is None: ax = plt.gca() if edgelist is None: edgelist = list(G.edges()) if not edgelist or len(edgelist) == 0: # no edges! return None if nodelist is None: nodelist = list(G.nodes()) # set edge positions edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist]) if not cb.iterable(width): lw = (width, ) else: lw = width if not is_string_like(edge_color) \ and cb.iterable(edge_color) \ and len(edge_color) == len(edge_pos): if np.alltrue([is_string_like(c) for c in edge_color]): # (should check ALL elements) # list of color letters such as ['k','r','k',...] edge_colors = tuple( [colorConverter.to_rgba(c, alpha) for c in edge_color]) elif np.alltrue([not is_string_like(c) for c in edge_color]): # If color specs are given as (rgb) or (rgba) tuples, we're OK if np.alltrue( [cb.iterable(c) and len(c) in (3, 4) for c in edge_color]): edge_colors = tuple(edge_color) else: # numbers (which are going to be mapped with a colormap) edge_colors = None else: raise ValueError('edge_color must contain color names or numbers') else: if is_string_like(edge_color) or len(edge_color) == 1: edge_colors = (colorConverter.to_rgba(edge_color, alpha), ) else: msg = 'edge_color must be a color or list of one color per edge' raise ValueError(msg) if (not G.is_directed() or not arrows): edge_collection = LineCollection( edge_pos, colors=edge_colors, linewidths=lw, antialiaseds=(1, ), linestyle=style, transOffset=ax.transData, ) edge_collection.set_zorder(1) # edges go behind nodes edge_collection.set_label(label) ax.add_collection(edge_collection) # Note: there was a bug in mpl regarding the handling of alpha values # for each line in a LineCollection. It was fixed in matplotlib by # r7184 and r7189 (June 6 2009). We should then not set the alpha # value globally, since the user can instead provide per-edge alphas # now. Only set it globally if provided as a scalar. if cb.is_numlike(alpha): edge_collection.set_alpha(alpha) if edge_colors is None: if edge_cmap is not None: assert (isinstance(edge_cmap, Colormap)) edge_collection.set_array(np.asarray(edge_color)) edge_collection.set_cmap(edge_cmap) if edge_vmin is not None or edge_vmax is not None: edge_collection.set_clim(edge_vmin, edge_vmax) else: edge_collection.autoscale() return edge_collection arrow_collection = None if G.is_directed() and arrows: # Note: Waiting for someone to implement arrow to intersection with # marker. Meanwhile, this works well for polygons with more than 4 # sides and circle. def to_marker_edge(marker_size, marker): if marker in "s^>v<d": # `large` markers need extra space return np.sqrt(2 * marker_size) / 2 else: return np.sqrt(marker_size) / 2 # Draw arrows with `matplotlib.patches.FancyarrowPatch` arrow_collection = [] mutation_scale = arrowsize # scale factor of arrow head arrow_colors = edge_colors if arrow_colors is None: if edge_cmap is not None: assert (isinstance(edge_cmap, Colormap)) else: edge_cmap = plt.get_cmap() # default matplotlib colormap if edge_vmin is None: edge_vmin = min(edge_color) if edge_vmax is None: edge_vmax = max(edge_color) color_normal = Normalize(vmin=edge_vmin, vmax=edge_vmax) for i, (src, dst) in enumerate(edge_pos): x1, y1 = src x2, y2 = dst arrow_color = None line_width = None shrink_source = 0 # space from source to tail shrink_target = 0 # space from head to target if cb.iterable(node_size): # many node sizes src_node, dst_node = edgelist[i] index_node = nodelist.index(dst_node) marker_size = node_size[index_node] shrink_target = to_marker_edge(marker_size, node_shape) else: shrink_target = to_marker_edge(node_size, node_shape) if arrow_colors is None: arrow_color = edge_cmap(color_normal(edge_color[i])) elif len(arrow_colors) > 1: arrow_color = arrow_colors[i] else: arrow_color = arrow_colors[0] if len(lw) > 1: line_width = lw[i] else: line_width = lw[0] arrow = FancyArrowPatch((x1, y1), (x2, y2), arrowstyle=arrowstyle, shrinkA=shrink_source, shrinkB=shrink_target, mutation_scale=mutation_scale, color=arrow_color, linewidth=line_width, zorder=1) # arrows go behind nodes # There seems to be a bug in matplotlib to make collections of # FancyArrowPatch instances. Until fixed, the patches are added # individually to the axes instance. arrow_collection.append(arrow) ax.add_patch(arrow) # update view minx = np.amin(np.ravel(edge_pos[:, :, 0])) maxx = np.amax(np.ravel(edge_pos[:, :, 0])) miny = np.amin(np.ravel(edge_pos[:, :, 1])) maxy = np.amax(np.ravel(edge_pos[:, :, 1])) w = maxx - minx h = maxy - miny padx, pady = 0.05 * w, 0.05 * h corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady) ax.update_datalim(corners) ax.autoscale_view() return arrow_collection
def convert( value, unit, axis ): """: Convert value using unit to a float. If value is a sequence, return the converted sequence. = INPUT VARIABLES - axis The axis using this converter. - value The value or list of values that need to be converted. - unit The units to use for a axis with Epoch data. = RETURN VALUE - Returns the value parameter converted to floats. """ if ( units.ConversionInterface.is_numlike( value ) ): return value if ( value == [] ): return [] # we delay loading to make matplotlib happy ax = axis.axes if axis is ax.get_xaxis(): isXAxis = True else: isXAxis = False axis.get_major_ticks() ticks = axis.get_ticklocs() labels = axis.get_ticklabels() labels = [ l.get_text() for l in labels if l.get_text() ] if ( not labels ): ticks = [] labels = [] if ( not iterable( value ) ): value = [ value ] newValues = [] for v in value: if ( (v not in labels) and (v not in newValues) ): newValues.append( v ) for v in newValues: if ( labels ): labels.append( v ) else: labels = [ v ] #DISABLED: This is disabled because matplotlib bar plots do not #DISABLED: recalculate the unit conversion of the data values #DISABLED: this is due to design and is not really a bug. #DISABLED: If this gets changed, then we can activate the following #DISABLED: block of code. Note that this works for line plots. #DISABLED if ( unit ): #DISABLED if ( unit.find( "sorted" ) > -1 ): #DISABLED labels.sort() #DISABLED if ( unit.find( "inverted" ) > -1 ): #DISABLED labels = labels[ ::-1 ] # add padding (so they do not appear on the axes themselves) labels = [ '' ] + labels + [ '' ] ticks = range( len(labels) ) ticks[0] = 0.5 ticks[-1] = ticks[-1] - 0.5 axis.set_ticks( ticks ) axis.set_ticklabels( labels ) # we have to do the following lines to make ax.autoscale_view work loc = axis.get_major_locator() loc.set_bounds( ticks[0], ticks[-1] ) if ( isXAxis ): ax.set_xlim( ticks[0], ticks[-1] ) else: ax.set_ylim( ticks[0], ticks[-1] ) result = [] for v in value: # If v is not in labels then something went wrong with adding new # labels to the list of old labels. errmsg = "This is due to a logic error in the StrConverter class. " errmsg += "Please report this error and its message in bugzilla." assert ( v in labels ), errmsg result.append( ticks[ labels.index(v) ] ) ax.viewLim.ignore(-1) return result
def draw_networkx_edges(G, pos, edgelist=None, width=1.0, edge_color='k', style='solid', alpha=None, edge_cmap=None, edge_vmin=None, edge_vmax=None, ax=None, arrows=True, label=None, **kwds): """Draw the edges of the graph G. This draws only the edges of the graph G. Parameters ---------- G : graph A networkx graph pos : dictionary A dictionary with nodes as keys and positions as values. If not specified a spring layout positioning will be computed. See networkx.layout for functions that compute node positions. edgelist : collection of edge tuples Draw only specified edges(default=G.edges()) width : float Line width of edges (default =1.0) edge_color : color string, or array of floats Edge color. Can be a single color format string (default='r'), or a sequence of colors with the same length as edgelist. If numeric values are specified they will be mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters. style : string Edge line style (default='solid') (solid|dashed|dotted,dashdot) alpha : float The edge transparency (default=1.0) edge_ cmap : Matplotlib colormap Colormap for mapping intensities of edges (default=None) edge_vmin,edge_vmax : floats Minimum and maximum for edge colormap scaling (default=None) ax : Matplotlib Axes object, optional Draw the graph in the specified Matplotlib axes. arrows : bool, optional (default=True) For directed graphs, if True draw arrowheads. label : [None| string] Label for legend Notes ----- For directed graphs, "arrows" (actually just thicker stubs) are drawn at the head end. Arrows can be turned off with keyword arrows=False. Yes, it is ugly but drawing proper arrows with Matplotlib this way is tricky. Examples -------- >>> G=nx.dodecahedral_graph() >>> edges=nx.draw_networkx_edges(G,pos=nx.spring_layout(G)) Also see the NetworkX drawing examples at http://networkx.lanl.gov/gallery.html See Also -------- draw() draw_networkx() draw_networkx_nodes() draw_networkx_labels() draw_networkx_edge_labels() """ try: import matplotlib import matplotlib.pylab as pylab import matplotlib.cbook as cb from matplotlib.colors import colorConverter, Colormap from matplotlib.collections import LineCollection import numpy except ImportError: raise ImportError("Matplotlib required for draw()") except RuntimeError: print("Matplotlib unable to open display") raise if ax is None: ax = pylab.gca() if edgelist is None: edgelist = G.edges() if not edgelist or len(edgelist) == 0: # no edges! return None # set edge positions edge_pos = numpy.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist]) if not cb.iterable(width): lw = (width, ) else: lw = width if not cb.is_string_like(edge_color) \ and cb.iterable(edge_color) \ and len(edge_color)==len(edge_pos): if numpy.alltrue([cb.is_string_like(c) for c in edge_color]): # (should check ALL elements) # list of color letters such as ['k','r','k',...] edge_colors = tuple( [colorConverter.to_rgba(c, alpha) for c in edge_color]) elif numpy.alltrue([not cb.is_string_like(c) for c in edge_color]): # If color specs are given as (rgb) or (rgba) tuples, we're OK if numpy.alltrue( [cb.iterable(c) and len(c) in (3, 4) for c in edge_color]): edge_colors = tuple(edge_color) else: # numbers (which are going to be mapped with a colormap) edge_colors = None else: raise ValueError( 'edge_color must consist of either color names or numbers') else: if cb.is_string_like(edge_color) or len(edge_color) == 1: edge_colors = (colorConverter.to_rgba(edge_color, alpha), ) else: raise ValueError( 'edge_color must be a single color or list of exactly m colors where m is the number or edges' ) edge_collection = LineCollection( edge_pos, colors=edge_colors, linewidths=lw, antialiaseds=(1, ), linestyle=style, transOffset=ax.transData, ) edge_collection.set_zorder(1) # edges go behind nodes edge_collection.set_label(label) ax.add_collection(edge_collection) # Note: there was a bug in mpl regarding the handling of alpha values for # each line in a LineCollection. It was fixed in matplotlib in r7184 and # r7189 (June 6 2009). We should then not set the alpha value globally, # since the user can instead provide per-edge alphas now. Only set it # globally if provided as a scalar. if cb.is_numlike(alpha): edge_collection.set_alpha(alpha) if edge_colors is None: if edge_cmap is not None: assert (isinstance(edge_cmap, Colormap)) edge_collection.set_array(numpy.asarray(edge_color)) edge_collection.set_cmap(edge_cmap) if edge_vmin is not None or edge_vmax is not None: edge_collection.set_clim(edge_vmin, edge_vmax) else: edge_collection.autoscale() pylab.sci(edge_collection) arrow_collection = None if G.is_directed() and arrows: # a directed graph hack # draw thick line segments at head end of edge # waiting for someone else to implement arrows that will work arrow_colors = edge_colors a_pos = [] p = 1.0 - 0.25 # make head segment 25 percent of edge length for src, dst in edge_pos: x1, y1 = src x2, y2 = dst dx = x2 - x1 # x offset dy = y2 - y1 # y offset d = numpy.sqrt(float(dx**2 + dy**2)) # length of edge if d == 0: # source and target at same position continue if dx == 0: # vertical edge xa = x2 ya = dy * p + y1 if dy == 0: # horizontal edge ya = y2 xa = dx * p + x1 else: theta = numpy.arctan2(dy, dx) xa = p * d * numpy.cos(theta) + x1 ya = p * d * numpy.sin(theta) + y1 a_pos.append(((xa, ya), (x2, y2))) arrow_collection = LineCollection( a_pos, colors=arrow_colors, linewidths=[4 * ww for ww in lw], antialiaseds=(1, ), transOffset=ax.transData, ) arrow_collection.set_zorder(1) # edges go behind nodes arrow_collection.set_label(label) ax.add_collection(arrow_collection) # update view minx = numpy.amin(numpy.ravel(edge_pos[:, :, 0])) maxx = numpy.amax(numpy.ravel(edge_pos[:, :, 0])) miny = numpy.amin(numpy.ravel(edge_pos[:, :, 1])) maxy = numpy.amax(numpy.ravel(edge_pos[:, :, 1])) w = maxx - minx h = maxy - miny padx, pady = 0.05 * w, 0.05 * h corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady) ax.update_datalim(corners) ax.autoscale_view() # if arrow_collection: return edge_collection
def julian2num(j): 'Convert a Julian date (or sequence) to a matplotlib date (or sequence).' if cbook.iterable(j): j = np.asarray(j) return j - 1721424.5
def __init__( self, ax, cmap=None, norm=None, alpha=None, values=None, boundaries=None, orientation='vertical', ticklocation='auto', extend='neither', spacing='uniform', # uniform or proportional ticks=None, format=None, drawedges=False, filled=True, extendfrac=None, extendrect=False, label='', ): #: The axes that this colorbar lives in. self.ax = ax self._patch_ax() if cmap is None: cmap = cm.get_cmap() if norm is None: norm = colors.Normalize() self.alpha = alpha cm.ScalarMappable.__init__(self, cmap=cmap, norm=norm) self.values = values self.boundaries = boundaries self.extend = extend self._inside = self._slice_dict[extend] self.spacing = spacing self.orientation = orientation self.drawedges = drawedges self.filled = filled self.extendfrac = extendfrac self.extendrect = extendrect self.solids = None self.lines = list() self.outline = None self.patch = None self.dividers = None if ticklocation == 'auto': ticklocation = 'bottom' if orientation == 'horizontal' else 'right' self.ticklocation = ticklocation self.set_label(label) if cbook.iterable(ticks): self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) else: self.locator = ticks # Handle default in _ticker() if format is None: if isinstance(self.norm, colors.LogNorm): self.formatter = ticker.LogFormatterMathtext() else: self.formatter = ticker.ScalarFormatter() elif cbook.is_string_like(format): self.formatter = ticker.FormatStrFormatter(format) else: self.formatter = format # Assume it is a Formatter # The rest is in a method so we can recalculate when clim changes. self.config_axis() self.draw_all()
def bode(self, axes=None, pair=(0, 0), label='bode', title="Bode plot", labels=None, colors=['b', 'g', 'r', 'c', 'm', 'y', 'k'], styles=[(None, None), (3, 3), (1, 1), (3, 2, 1, 2)], leg_kwargs={}, **kwargs): r"""Plot the linearizations onto a single Bode diagram. This method calls :meth:`LinRes.bode` from the included instances of :class:`LinRes`. **Parameters:** - *axes*: Tuple (pair) of axes for the magnitude and phase plots If *axes* is not provided, then axes will be created in a new figure. - *pair*: Tuple of (input name or index, output name or index) for the transfer function to be chosen from each system (applied to all) This is ignored if the system is SISO. - *label*: Label for the figure (ignored if axes is provided) This is used as the base filename if the figure is saved using :func:`~modelicares.util.save` or :func:`~modelicares.util.saveall`. - *title*: Title for the figure - *labels*: Label or list of labels for the legends If *labels* is *None*, then no label will be used. If it is an empty string (''), then the base filenames will be used. - *colors*: Color or list of colors that will be used sequentially Each may be a character, grayscale, or rgb value. .. Seealso:: http://matplotlib.sourceforge.net/api/colors_api.html - *styles*: Line/dash style or list of line/dash styles that will be used sequentially Each style is a string representing a linestyle (e.g., '--') or a tuple of on/off lengths representing dashes. Use '' for no line and '-' for a solid line. .. Seealso:: http://matplotlib.sourceforge.net/api/collections_api.html - *leg_kwargs*: Dictionary of keyword arguments for :func:`matplotlib.pyplot.legend` If *leg_kwargs* is *None*, then no legend will be shown. - *\*\*kwargs*: Additional plotting arguments: - *freqs*: List or frequencies or tuple of (min, max) frequencies over which to plot the system response. If *freqs* is *None*, then an appropriate range will be determined automatically. - *in_Hz*: If *True* (default), the frequencies (*freqs*) are in Hz and should be plotted in Hz (otherwise, rad/s) - *in_dB*: If *True* (default), plot the magnitude in dB - *in_deg*: If *True* (default), plot the phase in degrees (otherwise, radians) Other keyword arguments are passed to :func:`matplotlib.pyplot.plot`. **Returns:** 1. *axes*: Tuple (pair) of axes for the magnitude and phase plots **Example:** .. plot:: examples/PIDs-bode.py :alt: Bode plot of PID with varying parameters """ # Create axes if necessary. if not axes: fig = util.figure(label) axes = (fig.add_subplot(211), fig.add_subplot(212)) # Process the labels input. labels = self._get_labels(labels) # Set up the color(s) and line style(s). if not iterable(colors): # Use the single color for all plots. colors = (colors, ) if not iterable(styles): # Use the single line style for all plots. styles = [styles] elif type(styles[0]) is int: # One dashes tuple has been provided; use its value for all plots. styles = [styles] n_colors = len(colors) n_styles = len(styles) # Create the plots. for i, (lin, label) in enumerate(zip(self, labels)): style = styles[np.mod(i, n_styles)] if isinstance(style, string_types): kwargs['linestyle'] = style kwargs.pop('dashes', None) else: kwargs['dashes'] = style kwargs.pop('linestyle', None) if lin.sys.inputs > 1 or lin.sys.outputs > 1: sys = lin.to_siso(pair[0], pair[1]) else: sys = lin.sys bode_plot(sys, label=label, color=colors[np.mod(i, n_colors)], axes=axes, **kwargs) # Decorate and finish. axes[0].set_title(title) if leg_kwargs is not None: loc = leg_kwargs.pop('loc', 'best') axes[0].legend(loc=loc, **leg_kwargs) axes[1].legend(loc=loc, **leg_kwargs) return axes