def _get_line_tups(*args): """ Helper func to parse input to plot() """ # Assume all args are either data or format strings, plt.plot will # deal with raising exceptions. # A line's arguments consist of [x], y, [fmt] lines = [] while args: fmt = '' y = Q_(args[0]) if len(args) > 1: if is_string_like(args[1]): fmt = args[1] x = Q_(np.arange(y.shape[0], dtype=float)) args = args[2:] else: x = y y = Q_(args[1]) if len(args) > 2 and is_string_like(args[2]): fmt = args[2] args = args[3:] else: args = args[2:] else: x = Q_(np.arange(y.shape[0], dtype=float)) args = args[1:] lines.append((x, y, fmt)) return lines
def set_linestyles(self, ls): """ Set the linestyles(s) for the collection. ACCEPTS: ['solid' | 'dashed', 'dashdot', 'dotted' | (offset, on-off-dash-seq) ] """ try: if cbook.is_string_like(ls): dashes = [backend_bases.GraphicsContextBase.dashd[ls]] elif cbook.iterable(ls): try: dashes = [] for x in ls: if cbook.is_string_like(x): dashes.append(backend_bases.GraphicsContextBase.dashd[ls]) elif cbook.iterator(x) and len(x) == 2: dashes.append(x) else: raise ValueError() except ValueError: if len(ls)==2: dashes = ls else: raise ValueError() else: raise ValueError() except ValueError: raise ValueError('Do not know how to convert %s to dashes'%ls) self._linestyles = dashes
def draw(self, renderer): if not self.get_visible(): return #renderer.open_group('patch') gc = renderer.new_gc() if cbook.is_string_like(self._edgecolor) and self._edgecolor.lower()=='none': gc.set_linewidth(0) else: gc.set_foreground(self._edgecolor) gc.set_linewidth(self._linewidth) gc.set_alpha(self._alpha) gc.set_antialiased(self._antialiased) self._set_gc_clip(gc) gc.set_capstyle('projecting') if (not self.fill or self._facecolor is None or (cbook.is_string_like(self._facecolor) and self._facecolor.lower()=='none')): rgbFace = None else: rgbFace = colors.colorConverter.to_rgb(self._facecolor) if self._hatch: gc.set_hatch(self._hatch ) verts = self.get_verts() tverts = self.get_transform().seq_xy_tups(verts) renderer.draw_polygon(gc, rgbFace, tverts)
def draw(self, renderer): if not self.get_visible(): return #renderer.open_group('patch') gc = renderer.new_gc() if cbook.is_string_like(self._edgecolor) and self._edgecolor.lower()=='none': gc.set_linewidth(0) else: gc.set_foreground(self._edgecolor) gc.set_linewidth(self._linewidth) gc.set_alpha(self._alpha) gc.set_antialiased(self._antialiased) self._set_gc_clip(gc) gc.set_capstyle('projecting') if (not self.fill or self._facecolor is None or (cbook.is_string_like(self._facecolor) and self._facecolor.lower()=='none')): rgbFace = None else: rgbFace = colors.colorConverter.to_rgb(self._facecolor) if self._hatch: gc.set_hatch(self._hatch ) path = self.get_path() transform = self.get_transform() tpath = transform.transform_path_non_affine(path) affine = transform.get_affine() renderer.draw_path(gc, tpath, affine, rgbFace)
def imread(fname, format=None): """ Return image file in *fname* as :class:`numpy.array`. *fname* may be a string path or a Python file-like object. If using a file object, it must be opened in binary mode. If *format* is provided, will try to read file of that type, otherwise the format is deduced from the filename. If nothing can be deduced, PNG is tried. Return value is a :class:`numpy.array`. For grayscale images, the return array is MxN. For RGB images, the return value is MxNx3. For RGBA images the return value is MxNx4. matplotlib can only read PNGs natively, but if `PIL <http://www.pythonware.com/products/pil/>`_ is installed, it will use it to load the image and return an array (if possible) which can be used with :func:`~matplotlib.pyplot.imshow`. """ def pilread(): "try to load the image with PIL or return None" try: from PIL import Image except ImportError: return None image = Image.open(fname) return pil_to_array(image) handlers = {"png": _png.read_png} if format is None: if cbook.is_string_like(fname): basename, ext = os.path.splitext(fname) ext = ext.lower()[1:] else: ext = "png" else: ext = format if ext not in handlers.iterkeys(): im = pilread() if im is None: raise ValueError( "Only know how to handle extensions: %s; with PIL installed matplotlib can handle more images" % handlers.keys() ) return im handler = handlers[ext] # To handle Unicode filenames, we pass a file object to the PNG # reader extension, since Python handles them quite well, but it's # tricky in C. if cbook.is_string_like(fname): fname = open(fname, "rb") return handler(fname)
def test_is_string_like(): y = np.arange( 10 ) assert_equal( cbook.is_string_like( y ), False ) y.shape = 10, 1 assert_equal( cbook.is_string_like( y ), False ) y.shape = 1, 10 assert_equal( cbook.is_string_like( y ), False ) assert cbook.is_string_like( "hello world" ) assert_equal( cbook.is_string_like(10), False )
def test_is_string_like( self ): """Test the 'is_string_like cookbook' function.""" y = npy.arange( 10 ) self.failUnless( cbook.is_string_like( y ) == False ) y.shape = 10, 1 self.failUnless( cbook.is_string_like( y ) == False ) y.shape = 1, 10 self.failUnless( cbook.is_string_like( y ) == False ) self.failUnless( cbook.is_string_like( "hello world" ) ) self.failUnless( cbook.is_string_like(10) == False )
def use(style): """Use matplotlib style settings from a style specification. The style name of 'default' is reserved for reverting back to the default style settings. Parameters ---------- style : str, dict, or list A style specification. Valid options are: +------+-------------------------------------------------------------+ | str | The name of a style or a path/URL to a style file. For a | | | list of available style names, see `style.available`. | +------+-------------------------------------------------------------+ | dict | Dictionary with valid key/value pairs for | | | `matplotlib.rcParams`. | +------+-------------------------------------------------------------+ | list | A list of style specifiers (str or dict) applied from first | | | to last in the list. | +------+-------------------------------------------------------------+ """ if cbook.is_string_like(style) or hasattr(style, "keys"): # If name is a single str or dict, make it a single element list. styles = [style] else: styles = style for style in styles: if not cbook.is_string_like(style): mpl.rcParams.update(style) continue elif style == "default": mpl.rcdefaults() continue if style in library: mpl.rcParams.update(library[style]) else: try: rc = rc_params_from_file(style, use_default_template=False) mpl.rcParams.update(rc) except IOError: msg = ( "'%s' not found in the style library and input is " "not a valid URL or path. See `style.available` for " "list of available styles." ) raise IOError(msg % style)
def is_sequence_of_strings(obj): """ Returns true if *obj* is iterable and contains strings """ # Note: cbook.is_sequence_of_strings has a bug because # a numpy array of strings is recognized as being # string_like and therefore not a sequence of strings if not cbook.iterable(obj): return False if not isinstance(obj, np.ndarray) and cbook.is_string_like(obj): return False for o in obj: if not cbook.is_string_like(o): return False return True
def set_family(self, family): """ Change the font family. May be either an alias (generic name is CSS parlance), such as: 'serif', 'sans-serif', 'cursive', 'fantasy', or 'monospace', a real font name or a list of real font names. Real font names are not supported when `text.usetex` is `True`. """ if family is None: family = rcParams['font.family'] if is_string_like(family): family = [six.text_type(family)] elif (not is_string_like(family) and isinstance(family, Iterable)): family = [six.text_type(f) for f in family] self._family = family
def draw(self, renderer): if not self.get_visible(): return renderer.open_group('polycollection') transform = self.get_transform() if hasattr(self, 'get_transoffset'): transoffset = self.get_transoffset() #matplotlib 0.91.2 else: transoffset = getattr(self, '_transOffset', None) #matplotlib 0.98.3 transform.freeze() transoffset.freeze() self.update_scalarmappable() if cbook.is_string_like(self._edgecolors) and self._edgecolors[:2] == 'No': self._linewidths = (0,) #self._edgecolors = self._facecolors renderer.draw_poly_collection( self._verts, transform, self.clipbox, self._facecolors, self._edgecolors, self._linewidths, self._antialiaseds, self._offsets, transoffset) self.update_scalarmappable() #print 'calling renderer draw line collection' offsets = self._offsets renderer.draw_line_collection( self._segments, transform, self.clipbox, self._colors, self._lw, self._ls, self._aa, offsets, transoffset) transform.thaw() transoffset.thaw() renderer.close_group('polycollection')
def __init__(self, x=0, y=0, text='', color=None, # defaults to rc params verticalalignment='bottom', horizontalalignment='left', multialignment=None, fontproperties=None, # defaults to FontProperties() rotation=None, linespacing=None, **kwargs ): Artist.__init__(self) if color is None: colors= rcParams['text.color'] if fontproperties is None: fontproperties = FontProperties() elif is_string_like(fontproperties): fontproperties = FontProperties(fontproperties) self._animated = False # if is_string_like(text): # text = [text] self._textobjs = [Text(x[ind], y[ind], text[ind], color, verticalalignment, horizontalalignment, multialignment, fontproperties, rotation, linespacing, **kwargs) for ind in xrange(len(x))] self.update(kwargs)
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 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): self.ax.xaxis.set_scale("log") self.ax.yaxis.set_scale("log") self.ax._update_transScale() self.cbar_axis.set_minor_locator(ticker.NullLocator()) formatter = ticker.LogFormatter() else: formatter = None elif cbook.is_string_like(format): 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 draw_labels(self, G, pos, sizes=None, labels=None, font_family='sans-serif'): ax = plt.gca() i = 0 for n, label in labels.items(): (x, y) = pos[n] y += 0.015 + 0.03 * math.sqrt(sizes[i])/3.14/10.0 if not cb.is_string_like(label): label = str(label) # this will cause "1" and 1 to be labeled the same font_size = 8 font_color = 'white' font_weight = 'normal' if sizes[i] > 50: font_size = 12 font_weight = 'semibold' if sizes[i] > 120: font_color = 'yellow' if sizes[i] > 10: t = ax.text(x, y, label, size = font_size, color = font_color, family = font_family, weight = font_weight, style = 'italic', horizontalalignment = 'center', verticalalignment = 'center', transform=ax.transData, clip_on=True, ) i += 1 return
def print_figure(self, filename, dpi=150, facecolor='w', edgecolor='w', orientation='portrait'): """ Render the figure to hardcopy using self.renderer as the renderer if neccessary filename can be a string filename or writable file instance """ origDPI = self.figure.dpi.get() origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() self.figure.dpi.set(dpi) self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) im = self.draw() if is_string_like(filename): basename, ext = os.path.splitext(filename) if not len(ext): filename += '.png' im.writePng( filename ) self.figure.dpi.set(origDPI) self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor)
def print_png(self, filename_or_obj, *args, **kwargs): FigureCanvasAgg.draw(self) renderer = self.get_renderer() original_dpi = renderer.dpi renderer.dpi = self.figure.dpi if is_string_like(filename_or_obj): filename_or_obj = open(filename_or_obj, 'wb') close = True else: close = False version_str = 'matplotlib version ' + __version__ + \ ', http://matplotlib.org/' metadata = OrderedDict({'Software': version_str}) user_metadata = kwargs.pop("metadata", None) if user_metadata is not None: metadata.update(user_metadata) try: _png.write_png(renderer._renderer, filename_or_obj, self.figure.dpi, metadata=metadata) finally: if close: filename_or_obj.close() renderer.dpi = original_dpi
def make_option_menu( names, func=None ): """ Make an option menu with list of names in names. Return value is a optMenu, itemDict tuple, where optMenu is the option menu and itemDict is a dictionary mapping menu items to labels. Eg optmenu, menud = make_option_menu( ('Bill', 'Ted', 'Fred') ) ...set up dialog ... if response==gtk.RESPONSE_OK: item = optmenu.get_menu().get_active() print menud[item] # this is the selected name if func is not None, call func with label when selected """ optmenu = gtk.OptionMenu() optmenu.show() menu = gtk.Menu() menu.show() d = {} for label in names: if not is_string_like(label): continue item = gtk.MenuItem(label) menu.append(item) item.show() d[item] = label if func is not None: item.connect("activate", func, label) optmenu.set_menu(menu) return optmenu, d
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 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 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 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 _print_image(self, filename, format): if self.flags() & gtk.REALIZED == 0: # for self.window(for pixmap) and has a side effect of altering # figure width,height (via configure-event?) gtk.DrawingArea.realize(self) width, height = self.get_width_height() pixmap = gdk.Pixmap (self.window, width, height) self._renderer.set_pixmap (pixmap) self._render_figure(pixmap, width, height) # jpg colors don't match the display very well, png colors match # better pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height) if is_string_like(filename): try: pixbuf.save(filename, format) except gobject.GError as exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) elif is_writable_file_like(filename): if hasattr(pixbuf, 'save_to_callback'): def save_callback(buf, data=None): data.write(buf) try: pixbuf.save_to_callback(save_callback, format, user_data=filename) except gobject.GError as exc: error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) else: raise ValueError("Saving to a Python file-like object is only supported by PyGTK >= 2.8") else: raise ValueError("filename must be a path or a file-like object")
def __init__(self, colors, name = 'from_list', N = None): """ Make a colormap from a list of colors. colors is a list of matplotlib color specifications, or an equivalent Nx3 floating point array (N rgb values) name is a string to identify the colormap N is the number of entries in the map. The default is None, in which case there is one colormap entry for each element in the list of colors. If N < len(colors) the list will be truncated at N. If N > len(colors), the list will be extended by repetition. """ self.colors = colors self.monochrome = False # True only if all colors in map are identical; # needed for contouring. if N is None: N = len(self.colors) else: if cbook.is_string_like(self.colors): self.colors = [self.colors] * N self.monochrome = True elif cbook.iterable(self.colors): self.colors = list(self.colors) # in case it was a tuple if len(self.colors) == 1: self.monochrome = True if len(self.colors) < N: self.colors = list(self.colors) * N del(self.colors[N:]) else: try: gray = float(self.colors) except TypeError: pass else: self.colors = [gray] * N self.monochrome = True Colormap.__init__(self, name, N)
def register_cmap(name=None, cmap=None, data=None, lut=None): """ Add a colormap to the set recognized by :func:`get_cmap`. It can be used in two ways:: register_cmap(name='swirly', cmap=swirly_cmap) register_cmap(name='choppy', data=choppydata, lut=128) In the first case, *cmap* must be a :class:`colors.Colormap` instance. The *name* is optional; if absent, the name will be the :attr:`name` attribute of the *cmap*. In the second case, the three arguments are passed to the :class:`colors.LinearSegmentedColormap` initializer, and the resulting colormap is registered. """ if name is None: try: name = cmap.name except AttributeError: raise ValueError("Arguments must include a name or a Colormap") if not cbook.is_string_like(name): raise ValueError("Colormap name must be a string") if isinstance(cmap, colors.Colormap): cmap_d[name] = cmap return if lut is None: lut = mpl.rcParams['image.lut'] cmap = colors.LinearSegmentedColormap(name, data, lut) cmap_d[name] = cmap
def print_svg(self, filename, *args, **kwargs): if is_string_like(filename): with io.open(filename, 'w', encoding='utf-8') as svgwriter: return self._print_svg(filename, svgwriter, **kwargs) if not is_writable_file_like(filename): raise ValueError("filename must be a path or a file-like object") svgwriter = filename filename = getattr(svgwriter, 'name', '') if not isinstance(filename, six.string_types): filename = '' if not isinstance(svgwriter, io.TextIOBase): if six.PY3: svgwriter = io.TextIOWrapper(svgwriter, 'utf-8') else: svgwriter = codecs.getwriter('utf-8')(svgwriter) detach = True else: detach = False result = self._print_svg(filename, svgwriter, **kwargs) # Detach underlying stream from wrapper so that it remains open in the # caller. if detach: if six.PY3: svgwriter.detach() else: svgwriter.reset() svgwriter.stream = io.BytesIO() return result
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`. In addition, if *arg* is "none" (case-insensitive), then (0,0,0,0) will be returned. If *arg* is an *RGBA* sequence and *alpha* is not *None*, *alpha* will replace the original *A*. """ try: if arg.lower() == "none": return (0.0, 0.0, 0.0, 0.0) except AttributeError: pass 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)]: 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], 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 use(name): """Use matplotlib style settings from a known style sheet or from a file. Parameters ---------- name : str or list of str Name of style or path/URL to a style file. For a list of available style names, see `style.available`. If given a list, each style is applied from first to last in the list. """ if cbook.is_string_like(name): name = [name] for style in name: if style in library: mpl.rcParams.update(library[style]) else: try: rc = rc_params_from_file(style, use_default_template=False) mpl.rcParams.update(rc) except: msg = ("'%s' not found in the style library and input is " "not a valid URL or path. See `style.available` for " "list of available styles.") raise ValueError(msg % style)
def _process_attributes(attrs, source, agr, prefix=''): for attr, attr_dict in attrs.items(): attr_type = attr_dict['type'] if 'static' in attr_type: value = '' elif 'function' in attr_type: value = attr_dict['function'](source) else: value = getattr(source, 'get_{}'.format(attr))() if 'condition' in attr_dict: if not attr_dict['condition'](value): continue if is_string_like(value): value = latex_to_xmgrace(value) if 'index' in attr_type: attr_list = agr_attr_lists[attr_dict.get('maplist', attr)] index = indexed(attr_list)(value) if index is None: if 'map' in attr_type: attr_list.append(value) index = attr_list.index(value) else: index = 1 value = index agr.writeline(prefix + attr_dict['fmt'], attr=attr, value=value)
def get_label_width(self, lev, fmt, fsize): "get the width of the label in points" if cbook.is_string_like(lev): lw = (len(lev)) * fsize else: lw = (len(self.get_text(lev,fmt))) * fsize return lw
def draw_networkx_labels( G, pos, labels=None, font_size=12, font_color="k", font_family="sans-serif", font_weight="normal", alpha=1.0, ax=None, **kwds ): """Draw node labels on 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. labels is an optional dictionary keyed by vertex with node labels as the values. If provided only labels for the keys in the dictionary are drawn. See draw_networkx for the list of other optional parameters. """ try: import matplotlib.pylab as pylab import matplotlib.cbook as cb except ImportError: raise ImportError, "Matplotlib required for draw()" except RuntimeError: pass # unable to open display if ax is None: ax = pylab.gca() if labels is None: labels = dict(zip(G.nodes(), G.nodes())) text_items = {} # there is no text collection so we'll fake one for (n, label) in labels.items(): (x, y) = pos[n] if not cb.is_string_like(label): label = str(label) # this will cause "1" and 1 to be labeled the same t = ax.text( x, y, label, size=font_size, color=font_color, family=font_family, weight=font_weight, horizontalalignment="center", verticalalignment="center", transform=ax.transData, ) text_items[n] = t return text_items
class DialogLineprops(object): """ A GUI dialog for controlling lineprops """ signals = ( 'on_combobox_lineprops_changed', 'on_combobox_linestyle_changed', 'on_combobox_marker_changed', 'on_colorbutton_linestyle_color_set', 'on_colorbutton_markerface_color_set', 'on_dialog_lineprops_okbutton_clicked', 'on_dialog_lineprops_cancelbutton_clicked', ) linestyles = [ls for ls in lines.Line2D.lineStyles if ls.strip()] linestyled = dict([(s, i) for i, s in enumerate(linestyles)]) markers = [m for m in lines.Line2D.markers if cbook.is_string_like(m)] markerd = dict([(s, i) for i, s in enumerate(markers)]) def __init__(self, lines): import Gtk.glade datadir = matplotlib.get_data_path() gladefile = os.path.join(datadir, 'lineprops.glade') if not os.path.exists(gladefile): raise IOError('Could not find gladefile lineprops.glade in %s' % datadir) self._inited = False self._updateson = True # suppress updates when setting widgets manually self.wtree = Gtk.glade.XML(gladefile, 'dialog_lineprops') self.wtree.signal_autoconnect( dict([(s, getattr(self, s)) for s in self.signals])) self.dlg = self.wtree.get_widget('dialog_lineprops') self.lines = lines cbox = self.wtree.get_widget('combobox_lineprops') cbox.set_active(0) self.cbox_lineprops = cbox cbox = self.wtree.get_widget('combobox_linestyles') for ls in self.linestyles: cbox.append_text(ls) cbox.set_active(0) self.cbox_linestyles = cbox cbox = self.wtree.get_widget('combobox_markers') for m in self.markers: cbox.append_text(m) cbox.set_active(0) self.cbox_markers = cbox self._lastcnt = 0 self._inited = True def show(self): 'populate the combo box' self._updateson = False # flush the old cbox = self.cbox_lineprops for i in range(self._lastcnt - 1, -1, -1): cbox.remove_text(i) # add the new for line in self.lines: cbox.append_text(line.get_label()) cbox.set_active(0) self._updateson = True self._lastcnt = len(self.lines) self.dlg.show() def get_active_line(self): 'get the active line' ind = self.cbox_lineprops.get_active() line = self.lines[ind] return line def get_active_linestyle(self): 'get the active lineinestyle' ind = self.cbox_linestyles.get_active() ls = self.linestyles[ind] return ls def get_active_marker(self): 'get the active lineinestyle' ind = self.cbox_markers.get_active() m = self.markers[ind] return m def _update(self): 'update the active line props from the widgets' if not self._inited or not self._updateson: return line = self.get_active_line() ls = self.get_active_linestyle() marker = self.get_active_marker() line.set_linestyle(ls) line.set_marker(marker) button = self.wtree.get_widget('colorbutton_linestyle') color = button.get_color() r, g, b = [ val / 65535. for val in (color.red, color.green, color.blue) ] line.set_color((r, g, b)) button = self.wtree.get_widget('colorbutton_markerface') color = button.get_color() r, g, b = [ val / 65535. for val in (color.red, color.green, color.blue) ] line.set_markerfacecolor((r, g, b)) line.figure.canvas.draw() def on_combobox_lineprops_changed(self, item): 'update the widgets from the active line' if not self._inited: return self._updateson = False line = self.get_active_line() ls = line.get_linestyle() if ls is None: ls = 'None' self.cbox_linestyles.set_active(self.linestyled[ls]) marker = line.get_marker() if marker is None: marker = 'None' self.cbox_markers.set_active(self.markerd[marker]) r, g, b = colorConverter.to_rgb(line.get_color()) color = Gdk.Color(*[int(val * 65535) for val in (r, g, b)]) button = self.wtree.get_widget('colorbutton_linestyle') button.set_color(color) r, g, b = colorConverter.to_rgb(line.get_markerfacecolor()) color = Gdk.Color(*[int(val * 65535) for val in (r, g, b)]) button = self.wtree.get_widget('colorbutton_markerface') button.set_color(color) self._updateson = True def on_combobox_linestyle_changed(self, item): self._update() def on_combobox_marker_changed(self, item): self._update() def on_colorbutton_linestyle_color_set(self, button): self._update() def on_colorbutton_markerface_color_set(self, button): 'called colorbutton marker clicked' self._update() def on_dialog_lineprops_okbutton_clicked(self, button): self._update() self.dlg.hide() def on_dialog_lineprops_cancelbutton_clicked(self, button): self.dlg.hide()
def _save(self, fo, format, **kwargs): # save PDF/PS/SVG orientation = kwargs.get('orientation', 'portrait') dpi = 72 self.figure.dpi = dpi w_in, h_in = self.figure.get_size_inches() width_in_points, height_in_points = w_in * dpi, h_in * dpi if orientation == 'landscape': width_in_points, height_in_points = (height_in_points, width_in_points) if format == 'ps': if not hasattr(cairo, 'PSSurface'): raise RuntimeError('cairo has not been compiled with PS ' 'support enabled') surface = cairo.PSSurface(fo, width_in_points, height_in_points) elif format == 'pdf': if not hasattr(cairo, 'PDFSurface'): raise RuntimeError('cairo has not been compiled with PDF ' 'support enabled') surface = cairo.PDFSurface(fo, width_in_points, height_in_points) elif format in ('svg', 'svgz'): if not hasattr(cairo, 'SVGSurface'): raise RuntimeError('cairo has not been compiled with SVG ' 'support enabled') if format == 'svgz': if is_string_like(fo): fo = gzip.GzipFile(fo, 'wb') else: fo = gzip.GzipFile(None, 'wb', fileobj=fo) surface = cairo.SVGSurface(fo, width_in_points, height_in_points) else: warnings.warn("unknown format: %s" % format) return # surface.set_dpi() can be used renderer = RendererCairo(self.figure.dpi) renderer.set_width_height(width_in_points, height_in_points) renderer.set_ctx_from_surface(surface) ctx = renderer.gc.ctx if orientation == 'landscape': ctx.rotate(np.pi / 2) ctx.translate(0, -height_in_points) # cairo/src/cairo_ps_surface.c # '%%Orientation: Portrait' is always written to the file header # '%%Orientation: Landscape' would possibly cause problems # since some printers would rotate again ? # TODO: # add portrait/landscape checkbox to FileChooser self.figure.draw(renderer) show_fig_border = False # for testing figure orientation and scaling if show_fig_border: ctx.new_path() ctx.rectangle(0, 0, width_in_points, height_in_points) ctx.set_line_width(4.0) ctx.set_source_rgb(1, 0, 0) ctx.stroke() ctx.move_to(30, 30) ctx.select_font_face('sans-serif') ctx.set_font_size(20) ctx.show_text('Origin corner') ctx.show_page() surface.finish() if format == 'svgz': fo.close()
def rec2excel(r, ws, formatd=None, rownum=0, colnum=0, nanstr='NaN', infstr='Inf'): """ save record array r to excel pyExcelerator worksheet ws starting at rownum. if ws is string like, assume it is a filename and save to it start writing at rownum, colnum formatd is a dictionary mapping dtype name -> mlab.Format instances nanstr is the string that mpl will put into excel for np.nan value The next rownum after writing is returned """ autosave = False if cbook.is_string_like(ws): filename = ws wb = excel.Workbook() ws = wb.add_sheet('worksheet') autosave = True if formatd is None: formatd = dict() formats = [] font = excel.Font() font.bold = True stylehdr = excel.XFStyle() stylehdr.font = font for i, name in enumerate(r.dtype.names): dt = r.dtype[name] format = formatd.get(name) if format is None: format = mlab.defaultformatd.get(dt.type, mlab.FormatObj()) format = xlformat_factory(format) ws.write(rownum, colnum + i, name, stylehdr) formats.append(format) rownum += 1 ind = np.arange(len(r.dtype.names)) for row in r: for i in ind: val = row[i] format = formats[i] val = format.toval(val) if mlab.safe_isnan(val): ws.write(rownum, colnum + i, nanstr) elif mlab.safe_isinf(val): sgn = np.sign(val) if sgn < 0: s = infstr else: s = '-%s' % infstr ws.write(rownum, colnum + i, s) elif format.xlstyle is None: ws.write(rownum, colnum + i, val) else: ws.write(rownum, colnum + i, val, format.xlstyle) rownum += 1 if autosave: wb.save(filename) return rownum
def to_rgb(self, arg): """ Returns an *RGB* tuple of three floats from 0-1. *arg* can be an *RGB* or *RGBA* sequence or a string in any of several forms: 1) a letter from the set 'rgbcmykw' 2) a hex color string, like '#00FFFF' 3) a standard name, like 'aqua' 4) a float, like '0.4', indicating gray on a 0-1 scale if *arg* is *RGBA*, the *A* will simply be discarded. """ try: return self.cache[arg] except KeyError: pass except TypeError: # could be unhashable rgb seq arg = tuple(arg) try: return self.cache[arg] except KeyError: pass except TypeError: raise ValueError( 'to_rgb: arg "%s" is unhashable even inside a tuple' % (str(arg), )) try: if cbook.is_string_like(arg): argl = arg.lower() color = self.colors.get(argl, None) if color is None: str1 = cnames.get(argl, argl) if str1.startswith('#'): color = hex2color(str1) else: fl = float(argl) if fl < 0 or fl > 1: raise ValueError( 'gray (string) must be in range 0-1') color = tuple([fl] * 3) elif cbook.iterable(arg): if len(arg) > 4 or len(arg) < 3: raise ValueError('sequence length is %d; must be 3 or 4' % len(arg)) color = tuple(arg[:3]) if [x for x in color if (float(x) < 0) or (x > 1)]: # This will raise TypeError if x is not a number. raise ValueError( 'number in rbg sequence outside 0-1 range') else: raise ValueError('cannot convert argument to rgb sequence') self.cache[arg] = color except (KeyError, ValueError, TypeError) as exc: raise ValueError('to_rgb: Invalid rgb arg "%s"\n%s' % (str(arg), exc)) # Error messages could be improved by handling TypeError # separately; but this should be rare and not too hard # for the user to figure out as-is. return color
def save(self, filename, writer=None, fps=None, dpi=None, codec=None, bitrate=None, extra_args=None, metadata=None, extra_anim=None, savefig_kwargs=None): ''' Saves a movie file by drawing every frame. *filename* is the output filename, e.g., :file:`mymovie.mp4` *writer* is either an instance of :class:`MovieWriter` or a string key that identifies a class to use, such as 'ffmpeg' or 'mencoder'. If nothing is passed, the value of the rcparam `animation.writer` is used. *fps* is the frames per second in the movie. Defaults to None, which will use the animation's specified interval to set the frames per second. *dpi* controls the dots per inch for the movie frames. This combined with the figure's size in inches controls the size of the movie. *codec* is the video codec to be used. Not all codecs are supported by a given :class:`MovieWriter`. If none is given, this defaults to the value specified by the rcparam `animation.codec`. *bitrate* specifies the amount of bits used per second in the compressed movie, in kilobits per second. A higher number means a higher quality movie, but at the cost of increased file size. If no value is given, this defaults to the value given by the rcparam `animation.bitrate`. *extra_args* is a list of extra string arguments to be passed to the underlying movie utiltiy. The default is None, which passes the additional argurments in the 'animation.extra_args' rcParam. *metadata* is a dictionary of keys and values for metadata to include in the output file. Some keys that may be of use include: title, artist, genre, subject, copyright, srcform, comment. *extra_anim* is a list of additional `Animation` objects that should be included in the saved movie file. These need to be from the same `matplotlib.Figure` instance. Also, animation frames will just be simply combined, so there should be a 1:1 correspondence between the frames from the different animations. *savefig_kwargs* is a dictionary containing keyword arguments to be passed on to the 'savefig' command which is called repeatedly to save the individual frames. This can be used to set tight bounding boxes, for example. ''' if savefig_kwargs is None: savefig_kwargs = {} # FIXME: Using 'bbox_inches' doesn't currently work with # writers that pipe the data to the command because this # requires a fixed frame size (see Ryan May's reply in this # thread: [1]). Thus we drop the 'bbox_inches' argument if it # exists in savefig_kwargs. # # [1] (http://matplotlib.1069221.n5.nabble.com/ # Animation-class-let-save-accept-kwargs-which- # are-passed-on-to-savefig-td39627.html) # if 'bbox_inches' in savefig_kwargs: if not (writer in ['ffmpeg_file', 'mencoder_file'] or isinstance(writer, (FFMpegFileWriter, MencoderFileWriter))): print( "Warning: discarding the 'bbox_inches' argument in " "'savefig_kwargs' as it is only currently supported " "with the writers 'ffmpeg_file' and 'mencoder_file' " "(writer used: " "'{0}').".format( writer if isinstance(writer, six.string_types ) else writer.__class__.__name__)) savefig_kwargs.pop('bbox_inches') # Need to disconnect the first draw callback, since we'll be doing # draws. Otherwise, we'll end up starting the animation. if self._first_draw_id is not None: self._fig.canvas.mpl_disconnect(self._first_draw_id) reconnect_first_draw = True else: reconnect_first_draw = False if fps is None and hasattr(self, '_interval'): # Convert interval in ms to frames per second fps = 1000. / self._interval # If the writer is None, use the rc param to find the name of the one # to use if writer is None: writer = rcParams['animation.writer'] # Re-use the savefig DPI for ours if none is given if dpi is None: dpi = rcParams['savefig.dpi'] if dpi == 'figure': dpi = self._fig.dpi if codec is None: codec = rcParams['animation.codec'] if bitrate is None: bitrate = rcParams['animation.bitrate'] all_anim = [self] if extra_anim is not None: all_anim.extend(anim for anim in extra_anim if anim._fig is self._fig) # If we have the name of a writer, instantiate an instance of the # registered class. if is_string_like(writer): if writer in writers.avail: writer = writers[writer](fps, codec, bitrate, extra_args=extra_args, metadata=metadata) else: import warnings warnings.warn("MovieWriter %s unavailable" % writer) try: writer = writers[writers.list()[0]](fps, codec, bitrate, extra_args=extra_args, metadata=metadata) except IndexError: raise ValueError("Cannot save animation: no writers are " "available. Please install mencoder or " "ffmpeg to save animations.") verbose.report('Animation.save using %s' % type(writer), level='helpful') # Create a new sequence of frames for saved data. This is different # from new_frame_seq() to give the ability to save 'live' generated # frame information to be saved later. # TODO: Right now, after closing the figure, saving a movie won't work # since GUI widgets are gone. Either need to remove extra code to # allow for this non-existant use case or find a way to make it work. with writer.saving(self._fig, filename, dpi): for anim in all_anim: # Clear the initial frame anim._init_draw() for data in zip(*[a.new_saved_frame_seq() for a in all_anim]): for anim, d in zip(all_anim, data): # TODO: Need to see if turning off blit is really necessary anim._draw_next_frame(d, blit=False) writer.grab_frame(**savefig_kwargs) # Reconnect signal for first draw if necessary if reconnect_first_draw: self._first_draw_id = self._fig.canvas.mpl_connect( 'draw_event', self._start)
def findfont(self, prop, fontext='ttf'): """ Search the font list for the font that most closely matches the :class:`FontProperties` *prop*. :meth:`findfont` performs a nearest neighbor search. Each font is given a similarity score to the target font properties. The first font with the highest score is returned. If no matches below a certain threshold are found, the default font (usually Vera Sans) is returned. The result is cached, so subsequent lookups don't have to perform the O(n) nearest neighbor search. See the `W3C Cascading Style Sheet, Level 1 <http://www.w3.org/TR/1998/REC-CSS2-19980512/>`_ documentation for a description of the font finding algorithm. """ debug = False if prop is None: return self.defaultFont if is_string_like(prop): prop = FontProperties(prop) fname = prop.get_file() if fname is not None: verbose.report('findfont returning %s' % fname, 'debug') return fname if fontext == 'afm': font_cache = self.afm_lookup_cache fontlist = self.afmlist else: font_cache = self.ttf_lookup_cache fontlist = self.ttflist cached = font_cache.get(hash(prop)) if cached: return cached best_score = 1e64 best_font = None for font in fontlist: # Matching family should have highest priority, so it is multiplied # by 10.0 score = \ self.score_family(prop.get_family(), font.name) * 10.0 + \ self.score_style(prop.get_style(), font.style) + \ self.score_variant(prop.get_variant(), font.variant) + \ self.score_weight(prop.get_weight(), font.weight) + \ self.score_stretch(prop.get_stretch(), font.stretch) + \ self.score_size(prop.get_size(), font.size) if score < best_score: best_score = score best_font = font if score == 0: break if best_font is None or best_score >= 10.0: verbose.report('findfont: Could not match %s. Returning %s' % (prop, self.defaultFont)) result = self.defaultFont else: verbose.report( 'findfont: Matching %s to %s (%s) with score of %f' % (prop, best_font.name, best_font.fname, best_score)) result = best_font.fname font_cache[hash(prop)] = result return result
def __init__( self, fig, rect, nrows_ncols, ngrids=None, direction="row", axes_pad=0.02, add_all=True, share_all=False, aspect=True, label_mode="L", cbar_mode=None, cbar_location="right", cbar_pad=None, cbar_size="5%", cbar_set_cax=True, axes_class=None, ): """ Build an :class:`ImageGrid` instance with a grid nrows*ncols :class:`~matplotlib.axes.Axes` in :class:`~matplotlib.figure.Figure` *fig* with *rect=[left, bottom, width, height]* (in :class:`~matplotlib.figure.Figure` coordinates) or the subplot position code (e.g., "121"). Optional keyword arguments: ================ ======== ========================================= Keyword Default Description ================ ======== ========================================= direction "row" [ "row" | "column" ] axes_pad 0.02 float| pad between axes given in inches add_all True [ True | False ] share_all False [ True | False ] aspect True [ True | False ] label_mode "L" [ "L" | "1" | "all" ] cbar_mode None [ "each" | "single" | "edge" ] cbar_location "right" [ "left" | "right" | "bottom" | "top" ] cbar_pad None cbar_size "5%" cbar_set_cax True [ True | False ] axes_class None a type object which must be a subclass of :class:`~matplotlib.axes.Axes` ================ ======== ========================================= *cbar_set_cax* : if True, each axes in the grid has a cax attribute that is bind to associated cbar_axes. """ self._nrows, self._ncols = nrows_ncols if ngrids is None: ngrids = self._nrows * self._ncols else: if (ngrids > self._nrows * self._ncols) or (ngrids <= 0): raise Exception("") self.ngrids = ngrids self._axes_pad = axes_pad self._colorbar_mode = cbar_mode self._colorbar_location = cbar_location if cbar_pad is None: self._colorbar_pad = axes_pad else: self._colorbar_pad = cbar_pad self._colorbar_size = cbar_size self._init_axes_pad(axes_pad) if direction not in ["column", "row"]: raise Exception("") self._direction = direction if axes_class is None: axes_class = self._defaultLocatableAxesClass axes_class_args = {} else: if isinstance(axes_class, maxes.Axes): axes_class_args = {} else: axes_class, axes_class_args = axes_class self.axes_all = [] self.axes_column = [[] for i in range(self._ncols)] self.axes_row = [[] for i in range(self._nrows)] self.cbar_axes = [] h = [] v = [] if cbook.is_string_like(rect) or cbook.is_numlike(rect): self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, aspect=aspect) elif isinstance(rect, SubplotSpec): self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, aspect=aspect) elif len(rect) == 3: kw = dict(horizontal=h, vertical=v, aspect=aspect) self._divider = SubplotDivider(fig, *rect, **kw) elif len(rect) == 4: self._divider = Divider(fig, rect, horizontal=h, vertical=v, aspect=aspect) else: raise Exception("") rect = self._divider.get_position() # reference axes self._column_refax = [None for i in range(self._ncols)] self._row_refax = [None for i in range(self._nrows)] self._refax = None for i in range(self.ngrids): col, row = self._get_col_row(i) if share_all: sharex = self._refax sharey = self._refax else: sharex = self._column_refax[col] sharey = self._row_refax[row] ax = axes_class(fig, rect, sharex=sharex, sharey=sharey, **axes_class_args) if share_all: if self._refax is None: self._refax = ax else: if sharex is None: self._column_refax[col] = ax if sharey is None: self._row_refax[row] = ax self.axes_all.append(ax) self.axes_column[col].append(ax) self.axes_row[row].append(ax) cax = self._defaultCbarAxesClass( fig, rect, orientation=self._colorbar_location) self.cbar_axes.append(cax) self.axes_llc = self.axes_column[0][-1] self._update_locators() if add_all: for ax in self.axes_all + self.cbar_axes: fig.add_axes(ax) if cbar_set_cax: if self._colorbar_mode == "single": for ax in self.axes_all: ax.cax = self.cbar_axes[0] else: for ax, cax in zip(self.axes_all, self.cbar_axes): ax.cax = cax self.set_label_mode(label_mode)
def __init__( self, fig, rect, nrows_ncols, ngrids=None, direction="row", axes_pad=0.02, add_all=True, share_all=False, share_x=True, share_y=True, #aspect=True, label_mode="L", axes_class=None, ): """ Build an :class:`Grid` instance with a grid nrows*ncols :class:`~matplotlib.axes.Axes` in :class:`~matplotlib.figure.Figure` *fig* with *rect=[left, bottom, width, height]* (in :class:`~matplotlib.figure.Figure` coordinates) or the subplot position code (e.g., "121"). Optional keyword arguments: ================ ======== ========================================= Keyword Default Description ================ ======== ========================================= direction "row" [ "row" | "column" ] axes_pad 0.02 float| pad between axes given in inches add_all True [ True | False ] share_all False [ True | False ] share_x True [ True | False ] share_y True [ True | False ] label_mode "L" [ "L" | "1" | "all" ] axes_class None a type object which must be a subclass of :class:`~matplotlib.axes.Axes` ================ ======== ========================================= """ self._nrows, self._ncols = nrows_ncols if ngrids is None: ngrids = self._nrows * self._ncols else: if (ngrids > self._nrows * self._ncols) or (ngrids <= 0): raise Exception("") self.ngrids = ngrids self._init_axes_pad(axes_pad) if direction not in ["column", "row"]: raise Exception("") self._direction = direction if axes_class is None: axes_class = self._defaultLocatableAxesClass axes_class_args = {} else: if (type(axes_class)) == type and \ issubclass(axes_class, self._defaultLocatableAxesClass.Axes): axes_class_args = {} else: axes_class, axes_class_args = axes_class self.axes_all = [] self.axes_column = [[] for i in range(self._ncols)] self.axes_row = [[] for i in range(self._nrows)] h = [] v = [] if cbook.is_string_like(rect) or cbook.is_numlike(rect): self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, aspect=False) elif isinstance(rect, SubplotSpec): self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v, aspect=False) elif len(rect) == 3: kw = dict(horizontal=h, vertical=v, aspect=False) self._divider = SubplotDivider(fig, *rect, **kw) elif len(rect) == 4: self._divider = Divider(fig, rect, horizontal=h, vertical=v, aspect=False) else: raise Exception("") rect = self._divider.get_position() # reference axes self._column_refax = [None for i in range(self._ncols)] self._row_refax = [None for i in range(self._nrows)] self._refax = None for i in range(self.ngrids): col, row = self._get_col_row(i) if share_all: sharex = self._refax sharey = self._refax else: if share_x: sharex = self._column_refax[col] else: sharex = None if share_y: sharey = self._row_refax[row] else: sharey = None ax = axes_class(fig, rect, sharex=sharex, sharey=sharey, **axes_class_args) if share_all: if self._refax is None: self._refax = ax else: if sharex is None: self._column_refax[col] = ax if sharey is None: self._row_refax[row] = ax self.axes_all.append(ax) self.axes_column[col].append(ax) self.axes_row[row].append(ax) self.axes_llc = self.axes_column[0][-1] self._update_locators() if add_all: for ax in self.axes_all: fig.add_axes(ax) self.set_label_mode(label_mode)
def _calc_offset_transform(self): """calculate the offset transform performed by the spine""" self._ensure_position_is_set() position = self._position if cbook.is_string_like(position): if position == 'center': position = ('axes', 0.5) elif position == 'zero': position = ('data', 0) assert len(position) == 2, "position should be 2-tuple" position_type, amount = position assert position_type in ('axes', 'outward', 'data') if position_type == 'outward': if amount == 0: # short circuit commonest case self._spine_transform = ('identity', mtransforms.IdentityTransform()) elif self.spine_type in ['left', 'right', 'top', 'bottom']: offset_vec = {'left': (-1, 0), 'right': (1, 0), 'bottom': (0, -1), 'top': (0, 1), }[self.spine_type] # calculate x and y offset in dots offset_x = amount * offset_vec[0] / 72.0 offset_y = amount * offset_vec[1] / 72.0 self._spine_transform = ('post', mtransforms.ScaledTranslation( offset_x, offset_y, self.figure.dpi_scale_trans)) else: warnings.warn('unknown spine type "%s": no spine ' 'offset performed' % self.spine_type) self._spine_transform = ('identity', mtransforms.IdentityTransform()) elif position_type == 'axes': if self.spine_type in ('left', 'right'): self._spine_transform = ('pre', mtransforms.Affine2D.from_values( # keep y unchanged, fix x at # amount 0, 0, 0, 1, amount, 0)) elif self.spine_type in ('bottom', 'top'): self._spine_transform = ('pre', mtransforms.Affine2D.from_values( # keep x unchanged, fix y at # amount 1, 0, 0, 0, 0, amount)) else: warnings.warn('unknown spine type "%s": no spine ' 'offset performed' % self.spine_type) self._spine_transform = ('identity', mtransforms.IdentityTransform()) elif position_type == 'data': if self.spine_type in ('left', 'right'): self._spine_transform = ('data', mtransforms.Affine2D().translate( amount, 0)) elif self.spine_type in ('bottom', 'top'): self._spine_transform = ('data', mtransforms.Affine2D().translate( 0, amount)) else: warnings.warn('unknown spine type "%s": no spine ' 'offset performed' % self.spine_type) self._spine_transform = ('identity', mtransforms.IdentityTransform())
def imread(fname, format=None): """ Read an image from a file into an array. *fname* may be a string path or a Python file-like object. If using a file object, it must be opened in binary mode. If *format* is provided, will try to read file of that type, otherwise the format is deduced from the filename. If nothing can be deduced, PNG is tried. Return value is a :class:`numpy.array`. For grayscale images, the return array is MxN. For RGB images, the return value is MxNx3. For RGBA images the return value is MxNx4. matplotlib can only read PNGs natively, but if `PIL <http://www.pythonware.com/products/pil/>`_ is installed, it will use it to load the image and return an array (if possible) which can be used with :func:`~matplotlib.pyplot.imshow`. """ def pilread(fname): """try to load the image with PIL or return None""" try: from PIL import Image except ImportError: return None if cbook.is_string_like(fname): # force close the file after reading the image with open(fname, "rb") as fh: image = Image.open(fh) return pil_to_array(image) else: image = Image.open(fname) return pil_to_array(image) handlers = { 'png': _png.read_png, } if format is None: if cbook.is_string_like(fname): basename, ext = os.path.splitext(fname) ext = ext.lower()[1:] elif hasattr(fname, 'name'): basename, ext = os.path.splitext(fname.name) ext = ext.lower()[1:] else: ext = 'png' else: ext = format if ext not in handlers.iterkeys(): im = pilread(fname) if im is None: raise ValueError('Only know how to handle extensions: %s; ' 'with PIL installed matplotlib can handle ' 'more images' % handlers.keys()) return im handler = handlers[ext] # To handle Unicode filenames, we pass a file object to the PNG # reader extension, since Python handles them quite well, but it's # tricky in C. if cbook.is_string_like(fname): with open(fname, 'rb') as fd: return handler(fd) else: return handler(fname)
def __init__( self, parent, handles, labels, loc=None, numpoints=None, # the number of points in the legend line markerscale=None, # the relative size of legend markers # vs. original markerfirst=True, # controls ordering (left-to-right) of # legend marker and label scatterpoints=None, # number of scatter points scatteryoffsets=None, scatter_uni_size=None, # set scatter plot to have uniform # handle size prop=None, # properties for the legend texts fontsize=None, # keyword to set font size directly # spacing & pad defined as a fraction of the font-size borderpad=None, # the whitespace inside the legend border labelspacing=None, # the vertical space between the legend # entries handlelength=None, # the length of the legend handles handleheight=None, # the height of the legend handles handletextpad=None, # the pad between the legend handle # and text borderaxespad=None, # the pad between the axes and legend # border columnspacing=None, # spacing between columns ncol=1, # number of columns mode=None, # mode for horizontal distribution of columns. # None, "expand" fancybox=None, # True use a fancy box, false use a rounded # box, none use rc shadow=None, title=None, # set a title for the legend framealpha=None, # set frame alpha bbox_to_anchor=None, # bbox that the legend will be anchored. bbox_transform=None, # transform for the bbox frameon=None, # draw frame handler_map=None, ): """ - *parent*: the artist that contains the legend - *handles*: a list of artists (lines, patches) to be added to the legend - *labels*: a list of strings to label the legend Optional keyword arguments: ================ ==================================================== Keyword Description ================ ==================================================== loc a location code prop the font property fontsize the font size (used only if prop is not specified) markerscale the relative size of legend markers vs. original markerfirst If true, place legend marker to left of label If false, place legend marker to right of label numpoints the number of points in the legend for line scatterpoints the number of points in the legend for scatter plot scatteryoffsets a list of yoffsets for scatter symbols in legend scatter_uni_size Set the legend handles for satter plots to be of uniform size. frameon if True, draw a frame around the legend. If None, use rc fancybox if True, draw a frame with a round fancybox. If None, use rc shadow if True, draw a shadow behind legend framealpha If not None, alpha channel for the frame. ncol number of columns borderpad the fractional whitespace inside the legend border labelspacing the vertical space between the legend entries handlelength the length of the legend handles handleheight the height of the legend handles handletextpad the pad between the legend handle and text borderaxespad the pad between the axes and legend border columnspacing the spacing between columns title the legend title bbox_to_anchor the bbox that the legend will be anchored. bbox_transform the transform for the bbox. transAxes if None. ================ ==================================================== The pad and spacing parameters are measured in font-size units. e.g., a fontsize of 10 points and a handlelength=5 implies a handlelength of 50 points. Values from rcParams will be used if None. Users can specify any arbitrary location for the legend using the *bbox_to_anchor* keyword argument. bbox_to_anchor can be an instance of BboxBase(or its derivatives) or a tuple of 2 or 4 floats. See :meth:`set_bbox_to_anchor` for more detail. The legend location can be specified by setting *loc* with a tuple of 2 floats, which is interpreted as the lower-left corner of the legend in the normalized axes coordinate. """ # local import only to avoid circularity from matplotlib.axes import Axes from matplotlib.figure import Figure Artist.__init__(self) if prop is None: if fontsize is not None: self.prop = FontProperties(size=fontsize) else: self.prop = FontProperties(size=rcParams["legend.fontsize"]) elif isinstance(prop, dict): self.prop = FontProperties(**prop) if "size" not in prop: self.prop.set_size(rcParams["legend.fontsize"]) else: self.prop = prop self._fontsize = self.prop.get_size_in_points() self.texts = [] self.legendHandles = [] self._legend_title_box = None #: A dictionary with the extra handler mappings for this Legend #: instance. self._custom_handler_map = handler_map locals_view = locals() for name in [ "numpoints", "markerscale", "shadow", "columnspacing", "scatterpoints", "handleheight", 'borderpad', 'labelspacing', 'handlelength', 'handletextpad', 'borderaxespad' ]: if locals_view[name] is None: value = rcParams["legend." + name] else: value = locals_view[name] setattr(self, name, value) del locals_view # If scatter_uni_size is set, use a custom handler with set size. if scatter_uni_size: # See if custom handler has been provided for PathCollection if (self._custom_handler_map is not None and PathCollection in self._custom_handler_map): warnings.warn("'scatter_uni_size' was set, but custom " + "handler was provided. The former will " + "be ignored.") else: # Initialize _custom_handler_map if None. if self._custom_handler_map is None: self._custom_handler_map = {} # Add entry to custom handler to custom mapping to specify # uniform size. self._custom_handler_map.update({ PathCollection: legend_handler.HandlerPathCollection( sizes=[scatter_uni_size] * 3) }) handles = list(handles) if len(handles) < 2: ncol = 1 self._ncol = ncol if self.numpoints <= 0: raise ValueError("numpoints must be > 0; it was %d" % numpoints) # introduce y-offset for handles of the scatter plot if scatteryoffsets is None: self._scatteryoffsets = np.array([3. / 8., 4. / 8., 2.5 / 8.]) else: self._scatteryoffsets = np.asarray(scatteryoffsets) reps = int(self.scatterpoints / len(self._scatteryoffsets)) + 1 self._scatteryoffsets = np.tile(self._scatteryoffsets, reps)[:self.scatterpoints] # _legend_box is an OffsetBox instance that contains all # legend items and will be initialized from _init_legend_box() # method. self._legend_box = None if isinstance(parent, Axes): self.isaxes = True self.axes = parent self.set_figure(parent.figure) elif isinstance(parent, Figure): self.isaxes = False self.set_figure(parent) else: raise TypeError("Legend needs either Axes or Figure as parent") self.parent = parent if loc is None: loc = rcParams["legend.loc"] if not self.isaxes and loc in [0, 'best']: loc = 'upper right' if is_string_like(loc): if loc not in self.codes: if self.isaxes: warnings.warn('Unrecognized location "%s". Falling back ' 'on "best"; valid locations are\n\t%s\n' % (loc, '\n\t'.join(six.iterkeys(self.codes)))) loc = 0 else: warnings.warn('Unrecognized location "%s". Falling back ' 'on "upper right"; ' 'valid locations are\n\t%s\n' % (loc, '\n\t'.join(six.iterkeys(self.codes)))) loc = 1 else: loc = self.codes[loc] if not self.isaxes and loc == 0: warnings.warn('Automatic legend placement (loc="best") not ' 'implemented for figure legend. ' 'Falling back on "upper right".') loc = 1 self._mode = mode self.set_bbox_to_anchor(bbox_to_anchor, bbox_transform) # We use FancyBboxPatch to draw a legend frame. The location # and size of the box will be updated during the drawing time. self.legendPatch = FancyBboxPatch(xy=(0.0, 0.0), width=1., height=1., facecolor=rcParams["axes.facecolor"], edgecolor=rcParams["axes.edgecolor"], mutation_scale=self._fontsize, snap=True) # The width and height of the legendPatch will be set (in the # draw()) to the length that includes the padding. Thus we set # pad=0 here. if fancybox is None: fancybox = rcParams["legend.fancybox"] if fancybox: self.legendPatch.set_boxstyle("round", pad=0, rounding_size=0.2) else: self.legendPatch.set_boxstyle("square", pad=0) self._set_artist_props(self.legendPatch) self._drawFrame = frameon if frameon is None: self._drawFrame = rcParams["legend.frameon"] # init with null renderer self._init_legend_box(handles, labels, markerfirst) if framealpha is None: self.get_frame().set_alpha(rcParams["legend.framealpha"]) else: self.get_frame().set_alpha(framealpha) self._loc = loc self.set_title(title) self._last_fontsize_points = self._fontsize self._draggable = None
def print_figure(self, filename, dpi=150, facecolor='w', edgecolor='w', orientation='portrait'): """ Render the figure to hardcopy. Set the figure patch face and edge colors. This is useful because some of the GUIs have a gray figure face color background and you'll probably want to override this on hardcopy If the extension matches PNG, write a PNG file If the extension matches BMP or RAW, write an RGBA bitmap file If filename is a fileobject, write png to file object (thus you can, for example, write the png to stdout """ if __debug__: verbose.report('FigureCanvasAgg.print_figure', 'debug-annoying') # store the orig figure dpi, color and size information so we # can restore them later. For image creation alone, this is # not important since after the print the figure is done. But # backend_agg may be used as a renderer for a GUI figure, and # restoring figure props will be important in that case. # TODO: move most of this functionality into backend_bases origDPI = self.figure.dpi.get() origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() self.figure.dpi.set(dpi) self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) # render the printed figure self.draw() if not is_string_like(filename): # assume png and write to fileobject self.renderer._renderer.write_png(filename) #pass else: # take a look at the extension and choose the print handler basename, ext = os.path.splitext(filename) if not len(ext): ext = '.png' filename += ext ext = ext.lower() if (ext.find('rgb') >= 0 or ext.find('raw') >= 0 or ext.find('bmp') >= 0): # agg doesn't handle unicode yet self.renderer._renderer.write_rgba(str(filename)) elif ext.find('png') >= 0: # agg doesn't handle unicode yet self.renderer._renderer.write_png(str(filename)) #pass elif ext.find('svg') >= 0: from backend_svg import FigureCanvasSVG svg = self.switch_backends(FigureCanvasSVG) svg.print_figure(filename, dpi, facecolor, edgecolor, orientation) elif ext.find('ps') >= 0 or ext.find('ep') >= 0: from backend_ps import FigureCanvasPS # lazy import ps = self.switch_backends(FigureCanvasPS) ps.print_figure(filename, dpi, facecolor, edgecolor, orientation) else: raise IOError('Do not know know to handle extension *%s' % ext) # restore the original figure properties self.figure.dpi.set(origDPI) self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor) self.figure.set_canvas(self)
def rc(group, **kwargs): """ Set the current rc params. Group is the grouping for the rc, e.g., for ``lines.linewidth`` the group is ``lines``, for ``axes.facecolor``, the group is ``axes``, and so on. Group may also be a list or tuple of group names, e.g., (*xtick*, *ytick*). *kwargs* is a dictionary attribute name/value pairs, eg:: rc('lines', linewidth=2, color='r') sets the current rc params and is equivalent to:: rcParams['lines.linewidth'] = 2 rcParams['lines.color'] = 'r' The following aliases are available to save typing for interactive users: ===== ================= Alias Property ===== ================= 'lw' 'linewidth' 'ls' 'linestyle' 'c' 'color' 'fc' 'facecolor' 'ec' 'edgecolor' 'mew' 'markeredgewidth' 'aa' 'antialiased' ===== ================= Thus you could abbreviate the above rc command as:: rc('lines', lw=2, c='r') Note you can use python's kwargs dictionary facility to store dictionaries of default parameters. e.g., you can customize the font rc as follows:: font = {'family' : 'monospace', 'weight' : 'bold', 'size' : 'larger'} rc('font', **font) # pass in the font dict as kwargs This enables you to easily switch between several configurations. Use :func:`~matplotlib.pyplot.rcdefaults` to restore the default rc params after changes. """ aliases = { 'lw' : 'linewidth', 'ls' : 'linestyle', 'c' : 'color', 'fc' : 'facecolor', 'ec' : 'edgecolor', 'mew' : 'markeredgewidth', 'aa' : 'antialiased', } if is_string_like(group): group = (group,) for g in group: for k, v in six.iteritems(kwargs): name = aliases.get(k) or k key = '%s.%s' % (g, name) try: rcParams[key] = v except KeyError: raise KeyError('Unrecognized key "%s" for group "%s" and name "%s"' % (key, g, name))
def raise_msg_to_str(msg): """msg is a return arg from a raise. Join with new lines""" if not is_string_like(msg): msg = '\n'.join(map(str, msg)) return msg
def _normalize_font_family(family): if is_string_like(family): family = [six.text_type(family)] elif isinstance(family, Iterable): family = [six.text_type(f) for f in family] return family
def __init__( self, parent, handles, labels, loc=None, numpoints=None, # the number of points in the legend line markerscale=None, # the relative size of legend markers # vs. original scatterpoints=3, # TODO: may be an rcParam scatteryoffsets=None, prop=None, # properties for the legend texts fontsize=None, # keyword to set font size directly # the following dimensions are in axes coords pad=None, # deprecated; use borderpad labelsep=None, # deprecated; use labelspacing handlelen=None, # deprecated; use handlelength handletextsep=None, # deprecated; use handletextpad axespad=None, # deprecated; use borderaxespad # spacing & pad defined as a fraction of the font-size borderpad=None, # the whitespace inside the legend border labelspacing=None, # the vertical space between the legend # entries handlelength=None, # the length of the legend handles handleheight=None, # the height of the legend handles handletextpad=None, # the pad between the legend handle # and text borderaxespad=None, # the pad between the axes and legend # border columnspacing=None, # spacing between columns ncol=1, # number of columns mode=None, # mode for horizontal distribution of columns. # None, "expand" fancybox=None, # True use a fancy box, false use a rounded # box, none use rc shadow=None, title=None, # set a title for the legend bbox_to_anchor=None, # bbox that the legend will be anchored. bbox_transform=None, # transform for the bbox frameon=None, # draw frame handler_map=None, ): """ - *parent*: the artist that contains the legend - *handles*: a list of artists (lines, patches) to be added to the legend - *labels*: a list of strings to label the legend Optional keyword arguments: ================ ==================================================== Keyword Description ================ ==================================================== loc a location code prop the font property fontsize the font size (used only if prop is not specified) markerscale the relative size of legend markers vs. original numpoints the number of points in the legend for line scatterpoints the number of points in the legend for scatter plot scatteryoffsets a list of yoffsets for scatter symbols in legend frameon if True, draw a frame around the legend. If None, use rc fancybox if True, draw a frame with a round fancybox. If None, use rc shadow if True, draw a shadow behind legend ncol number of columns borderpad the fractional whitespace inside the legend border labelspacing the vertical space between the legend entries handlelength the length of the legend handles handleheight the length of the legend handles handletextpad the pad between the legend handle and text borderaxespad the pad between the axes and legend border columnspacing the spacing between columns title the legend title bbox_to_anchor the bbox that the legend will be anchored. bbox_transform the transform for the bbox. transAxes if None. ================ ==================================================== The pad and spacing parameters are measured in font-size units. E.g., a fontsize of 10 points and a handlelength=5 implies a handlelength of 50 points. Values from rcParams will be used if None. Users can specify any arbitrary location for the legend using the *bbox_to_anchor* keyword argument. bbox_to_anchor can be an instance of BboxBase(or its derivatives) or a tuple of 2 or 4 floats. See :meth:`set_bbox_to_anchor` for more detail. The legend location can be specified by setting *loc* with a tuple of 2 floats, which is interpreted as the lower-left corner of the legend in the normalized axes coordinate. """ # local import only to avoid circularity from matplotlib.axes import Axes from matplotlib.figure import Figure Artist.__init__(self) if prop is None: if fontsize is not None: self.prop = FontProperties(size=fontsize) else: self.prop = FontProperties(size=rcParams["legend.fontsize"]) elif isinstance(prop, dict): self.prop = FontProperties(**prop) if "size" not in prop: self.prop.set_size(rcParams["legend.fontsize"]) else: self.prop = prop self._fontsize = self.prop.get_size_in_points() propnames = [ "numpoints", "markerscale", "shadow", "columnspacing", "scatterpoints", "handleheight" ] self.texts = [] self.legendHandles = [] self._legend_title_box = None self._handler_map = handler_map localdict = locals() for name in propnames: if localdict[name] is None: value = rcParams["legend." + name] else: value = localdict[name] setattr(self, name, value) # Take care the deprecated keywords deprecated_kwds = { "pad": "borderpad", "labelsep": "labelspacing", "handlelen": "handlelength", "handletextsep": "handletextpad", "axespad": "borderaxespad" } # convert values of deprecated keywords (ginve in axes coords) # to new vaules in a fraction of the font size # conversion factor bbox = parent.bbox axessize_fontsize = min(bbox.width, bbox.height) / self._fontsize for k, v in deprecated_kwds.iteritems(): # use deprecated value if not None and if their newer # counter part is None. if localdict[k] is not None and localdict[v] is None: warnings.warn("Use '%s' instead of '%s'." % (v, k), DeprecationWarning) setattr(self, v, localdict[k] * axessize_fontsize) continue # Otherwise, use new keywords if localdict[v] is None: setattr(self, v, rcParams["legend." + v]) else: setattr(self, v, localdict[v]) del localdict handles = list(handles) if len(handles) < 2: ncol = 1 self._ncol = ncol if self.numpoints <= 0: raise ValueError("numpoints must be > 0; it was %d" % numpoints) # introduce y-offset for handles of the scatter plot if scatteryoffsets is None: self._scatteryoffsets = np.array([3. / 8., 4. / 8., 2.5 / 8.]) else: self._scatteryoffsets = np.asarray(scatteryoffsets) reps = int(self.scatterpoints / len(self._scatteryoffsets)) + 1 self._scatteryoffsets = np.tile(self._scatteryoffsets, reps)[:self.scatterpoints] # _legend_box is an OffsetBox instance that contains all # legend items and will be initialized from _init_legend_box() # method. self._legend_box = None if isinstance(parent, Axes): self.isaxes = True self.set_axes(parent) self.set_figure(parent.figure) elif isinstance(parent, Figure): self.isaxes = False self.set_figure(parent) else: raise TypeError("Legend needs either Axes or Figure as parent") self.parent = parent if loc is None: loc = rcParams["legend.loc"] if not self.isaxes and loc in [0, 'best']: loc = 'upper right' if is_string_like(loc): if loc not in self.codes: if self.isaxes: warnings.warn('Unrecognized location "%s". Falling back ' 'on "best"; valid locations are\n\t%s\n' % (loc, '\n\t'.join(self.codes.iterkeys()))) loc = 0 else: warnings.warn('Unrecognized location "%s". Falling back ' 'on "upper right"; ' 'valid locations are\n\t%s\n' % (loc, '\n\t'.join(self.codes.iterkeys()))) loc = 1 else: loc = self.codes[loc] if not self.isaxes and loc == 0: warnings.warn('Automatic legend placement (loc="best") not ' 'implemented for figure legend. ' 'Falling back on "upper right".') loc = 1 self._mode = mode self.set_bbox_to_anchor(bbox_to_anchor, bbox_transform) # We use FancyBboxPatch to draw a legend frame. The location # and size of the box will be updated during the drawing time. self.legendPatch = FancyBboxPatch(xy=(0.0, 0.0), width=1., height=1., facecolor=rcParams["axes.facecolor"], edgecolor=rcParams["axes.edgecolor"], mutation_scale=self._fontsize, snap=True) # The width and height of the legendPatch will be set (in the # draw()) to the length that includes the padding. Thus we set # pad=0 here. if fancybox is None: fancybox = rcParams["legend.fancybox"] if fancybox: self.legendPatch.set_boxstyle("round", pad=0, rounding_size=0.2) else: self.legendPatch.set_boxstyle("square", pad=0) self._set_artist_props(self.legendPatch) self._drawFrame = frameon if frameon is None: self._drawFrame = rcParams["legend.frameon"] # init with null renderer self._init_legend_box(handles, labels) self._loc = loc self.set_title(title) self._last_fontsize_points = self._fontsize self._draggable = None
def save(self, filename, writer=None, fps=None, dpi=None, codec=None, bitrate=None, extra_args=None, metadata=None, extra_anim=None): ''' Saves a movie file by drawing every frame. *filename* is the output filename, eg :file:`mymovie.mp4` *writer* is either an instance of :class:`MovieWriter` or a string key that identifies a class to use, such as 'ffmpeg' or 'mencoder'. If nothing is passed, the value of the rcparam `animation.writer` is used. *fps* is the frames per second in the movie. Defaults to None, which will use the animation's specified interval to set the frames per second. *dpi* controls the dots per inch for the movie frames. This combined with the figure's size in inches controls the size of the movie. *codec* is the video codec to be used. Not all codecs are supported by a given :class:`MovieWriter`. If none is given, this defaults to the value specified by the rcparam `animation.codec`. *bitrate* specifies the amount of bits used per second in the compressed movie, in kilobits per second. A higher number means a higher quality movie, but at the cost of increased file size. If no value is given, this defaults to the value given by the rcparam `animation.bitrate`. *extra_args* is a list of extra string arguments to be passed to the underlying movie utiltiy. The default is None, which passes the additional argurments in the 'animation.extra_args' rcParam. *metadata* is a dictionary of keys and values for metadata to include in the output file. Some keys that may be of use include: title, artist, genre, subject, copyright, srcform, comment. *extra_anim* is a list of additional `Animation` objects that should be included in the saved movie file. These need to be from the same `matplotlib.Figure` instance. Also, animation frames will just be simply combined, so there should be a 1:1 correspondence between the frames from the different animations. ''' # Need to disconnect the first draw callback, since we'll be doing # draws. Otherwise, we'll end up starting the animation. if self._first_draw_id is not None: self._fig.canvas.mpl_disconnect(self._first_draw_id) reconnect_first_draw = True else: reconnect_first_draw = False if fps is None and hasattr(self, '_interval'): # Convert interval in ms to frames per second fps = 1000. / self._interval # If the writer is None, use the rc param to find the name of the one # to use if writer is None: writer = rcParams['animation.writer'] # Re-use the savefig DPI for ours if none is given if dpi is None: dpi = rcParams['savefig.dpi'] if codec is None: codec = rcParams['animation.codec'] if bitrate is None: bitrate = rcParams['animation.bitrate'] all_anim = [self] if not extra_anim is None: all_anim.extend(anim for anim in extra_anim if anim._fig is self._fig) # If we have the name of a writer, instantiate an instance of the # registered class. if is_string_like(writer): if writer in writers.avail: writer = writers[writer](fps, codec, bitrate, extra_args=extra_args, metadata=metadata) else: import warnings warnings.warn("MovieWriter %s unavailable" % writer) writer = writers.list()[0] verbose.report('Animation.save using %s' % type(writer), level='helpful') # Create a new sequence of frames for saved data. This is different # from new_frame_seq() to give the ability to save 'live' generated # frame information to be saved later. # TODO: Right now, after closing the figure, saving a movie won't # work since GUI widgets are gone. Either need to remove extra code # to allow for this non-existant use case or find a way to make it work. with writer.saving(self._fig, filename, dpi): for data in itertools.izip( *[a.new_saved_frame_seq() for a in all_anim]): for anim, d in zip(all_anim, data): #TODO: Need to see if turning off blit is really necessary anim._draw_next_frame(d, blit=False) writer.grab_frame() # Reconnect signal for first draw if necessary if reconnect_first_draw: self._first_draw_id = self._fig.canvas.mpl_connect( 'draw_event', self._start)
def pie(self, explode=None, colors=None, autopct=None, pctdistance=0.6, shadow=False): start = time.time() labels = self.pdata.getLabels() if labels[0][0] == "NoLabels": try: self.pdata.initialize(key_type='string') self.pdata.sortLabels() labels = self.pdata.getLabels() nLabels = self.pdata.getNumberOfLabels() explode = [0.] * nLabels if nLabels > 0: explode[0] = 0.1 except Exception as x: print("PieGraph Error: can not interpret data for the plot") # labels.reverse() values = [l[1] for l in labels] x = numpy.array(values, numpy.float64) self.legendData = labels sx = float(numpy.sum(x)) if sx > 1: x = numpy.divide(x, sx) labels = [l[0] for l in labels] if explode is None: explode = [0] * len(x) assert (len(x) == len(labels)) assert (len(x) == len(explode)) plot_axis_labels = self.prefs.get('plot_axis_labels', True) center = 0, 0 radius = 1.1 theta1 = 0 i = 0 texts = [] slices = [] autotexts = [] for frac, label, expl in zip(x, labels, explode): x, y = center theta2 = theta1 + frac thetam = 2 * math.pi * 0.5 * (theta1 + theta2) x += expl * math.cos(thetam) y += expl * math.sin(thetam) color = self.palette.getColor(label) w = Wedge((x, y), radius, 360. * theta1, 360. * theta2, facecolor=color, lw=pixelToPoint(0.5, self.dpi), edgecolor='#999999') slices.append(w) self.ax.add_patch(w) w.set_label(label) if shadow: # make sure to add a shadow after the call to # add_patch so the figure and transform props will be # set shad = Shadow( w, -0.02, -0.02, # props={'facecolor':w.get_facecolor()} ) shad.set_zorder(0.9 * w.get_zorder()) self.ax.add_patch(shad) if plot_axis_labels: if frac > 0.03: xt = x + 1.05 * radius * math.cos(thetam) yt = y + 1.05 * radius * math.sin(thetam) thetam %= 2 * math.pi if 0 < thetam and thetam < math.pi: valign = 'bottom' elif thetam == 0 or thetam == math.pi: valign = 'center' else: valign = 'top' if thetam > math.pi / 2.0 and thetam < 3.0 * math.pi / 2.0: halign = 'right' elif thetam == math.pi / 2.0 or thetam == 3.0 * math.pi / 2.0: halign = 'center' else: halign = 'left' t = self.ax.text(xt, yt, label, size=pixelToPoint( self.prefs['subtitle_size'], self.dpi), horizontalalignment=halign, verticalalignment=valign) t.set_family(self.prefs['font_family']) t.set_fontname(self.prefs['font']) t.set_size(pixelToPoint(self.prefs['text_size'], self.dpi)) texts.append(t) if autopct is not None: xt = x + pctdistance * radius * math.cos(thetam) yt = y + pctdistance * radius * math.sin(thetam) if is_string_like(autopct): s = autopct % (100. * frac) elif callable(autopct): s = autopct(100. * frac) else: raise TypeError( 'autopct must be callable or a format string') t = self.ax.text(xt, yt, s, horizontalalignment='center', verticalalignment='center') t.set_family(self.prefs['font_family']) t.set_fontname(self.prefs['font']) t.set_size(pixelToPoint(self.prefs['text_size'], self.dpi)) autotexts.append(t) theta1 = theta2 i += 1 self.legendData.reverse() self.ax.set_xlim((-1.25, 1.25)) self.ax.set_ylim((-1.25, 1.25)) self.ax.set_axis_off() if autopct is None: return slices, texts else: return slices, texts, autotexts
def draw_mtg_labels(G, pos, nodelist=None, labels=None, font_size=12, font_color='k', font_family='sans-serif', font_weight='normal', alpha=1.0, ax=None, **kwds): """Draw node labels on the graph G. Parameters ---------- G : graph A MTG graph pos : dictionary, optional A dictionary with nodes as keys and positions as values. If not specified a spring layout positioning will be computed. See mtg.layout for functions that compute node positions. labels : dictionary, optional (default=None) Node labels in a dictionary keyed by node of text labels font_size : int Font size for text labels (default=12) font_color : string Font color string (default='k' black) font_family : string Font family (default='sans-serif') font_weight : string Font weight (default='normal') alpha : float The text transparency (default=1.0) ax : Matplotlib Axes object, optional Draw the graph in the specified Matplotlib axes. Examples -------- >>> G=om.dodecahedral_graph() >>> labels=om.draw_mtg_labels(G,pos=om.spring_layout(G)) Also see the MTG drawing examples at gallery.html See Also -------- draw() draw_mtg() draw_mtg_vertices() draw_mtg_edges() draw_mtg_labels() draw_mtg_edge_labels() """ try: import matplotlib.pyplot as plt import matplotlib.cbook as cb 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 labels is None: if nodelist is None: nodelist = G.vertices(scale=G.max_scale()) labels = dict((n, n) for n in nodelist) # set optional alignment horizontalalignment = kwds.get('horizontalalignment', 'center') verticalalignment = kwds.get('verticalalignment', 'center') text_items = {} # there is no text collection so we'll fake one for n, label in labels.items(): (x, y) = pos[n] if not cb.is_string_like(label): label = str( label) # this will cause "1" and 1 to be labeled the same t = ax.text( x, y, label, size=font_size, color=font_color, family=font_family, weight=font_weight, horizontalalignment=horizontalalignment, verticalalignment=verticalalignment, transform=ax.transData, clip_on=True, ) text_items[n] = t return text_items
def _is_list_like(obj): """Returns whether the obj is iterable and not a string""" return not is_string_like(obj) and iterable(obj)
def draw_mtg_vertices(g, pos, nodelist=None, node_size=300, node_color='r', node_shape='o', alpha=1.0, cmap=None, vmin=None, vmax=None, ax=None, linewidths=None, label=None, **kwds): """Draw the nodes of the graph G. This draws only the nodes of the graph G. Parameters ---------- G : graph A MTG graph pos : dictionary A dictionary with nodes as keys and positions as values. Positions should be sequences of length 2. ax : Matplotlib Axes object, optional Draw the graph in the specified Matplotlib axes. nodelist : list, optional Draw only specified nodes (default G.nodes()) node_size : scalar or array Size of nodes (default=300). If an array is specified it must be the same length as nodelist. node_color : color string, or array of floats Node color. Can be a single color format string (default='r'), or a sequence of colors with the same length as nodelist. If numeric values are specified they will be mapped to colors using the cmap and vmin,vmax parameters. See matplotlib.scatter for more details. node_shape : string The shape of the node. Specification is as matplotlib.scatter marker, one of 'so^>v<dph8' (default='o'). alpha : float The node transparency (default=1.0) cmap : Matplotlib colormap Colormap for mapping intensities of nodes (default=None) vmin,vmax : floats Minimum and maximum for node colormap scaling (default=None) linewidths : [None | scalar | sequence] Line width of symbol border (default =1.0) label : [None| string] Label for legend Returns ------- matplotlib.collections.PathCollection `PathCollection` of the nodes. Examples -------- >>> g = MTG() >>> vid = g.add_component(g.root) >>> random_tree(g, vid) >>> nodes=om.draw_mtg_vertices(G,pos=om.spring_layout(G)) See Also -------- draw() draw_mtg_vertices() draw_mtg_edges() draw_mtg_labels() draw_mtg_edge_labels() """ try: import matplotlib.pyplot as plt import matplotlib.cbook as cb import numpy 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 nodelist is None: nodelist = g.vertices(scale=g.max_scale()) if not nodelist or len(nodelist) == 0: # empty nodelist, no drawing return None if not cb.is_string_like(node_shape) and cb.iterable(node_shape): shapes = list(set(node_shape)) for sh in shapes: sh_index = [i for i, nsh in enumerate(node_shape) if nsh == sh] sh_nodelist = [nodelist[i] for i in sh_index] sh_node_color = node_color if not cb.is_string_like(sh_node_color) and cb.iterable( sh_node_color): sh_node_color = [sh_node_color[i] for i in sh_index] sh_node_size = node_size if not cb.is_string_like(sh_node_size) and cb.iterable( sh_node_size): sh_node_size = [sh_node_size[i] for i in sh_index] xy = numpy.asarray([pos[v] for v in sh_nodelist]) node_collection = ax.scatter(xy[:, 0], xy[:, 1], s=sh_node_size, c=sh_node_color, marker=sh, cmap=cmap, vmin=vmin, vmax=vmax, alpha=alpha, linewidths=linewidths, label=label) node_collection.set_zorder(2) return node_collection # else try: xy = numpy.asarray([pos[v] for v in nodelist]) except KeyError as e: raise Exception('Node %s has no position.' % e) except ValueError: raise Exception('Bad value in node positions.') node_collection = ax.scatter(xy[:, 0], xy[:, 1], s=node_size, c=node_color, marker=node_shape, cmap=cmap, vmin=vmin, vmax=vmax, alpha=alpha, linewidths=linewidths, label=label) node_collection.set_zorder(2) return node_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.xaxis.set_scale("log") self.ax.yaxis.set_scale("log") self.ax._update_transScale() self.cbar_axis.set_minor_locator(ticker.NullLocator()) formatter = ticker.LogFormatter() else: formatter = None elif cbook.is_string_like(format): 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 __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 imread(fname, format=None): """ Read an image from a file into an array. *fname* may be a string path, a valid URL, or a Python file-like object. If using a file object, it must be opened in binary mode. If *format* is provided, will try to read file of that type, otherwise the format is deduced from the filename. If nothing can be deduced, PNG is tried. Return value is a :class:`numpy.array`. For grayscale images, the return array is MxN. For RGB images, the return value is MxNx3. For RGBA images the return value is MxNx4. matplotlib can only read PNGs natively, but if `PIL <http://www.pythonware.com/products/pil/>`_ is installed, it will use it to load the image and return an array (if possible) which can be used with :func:`~matplotlib.pyplot.imshow`. Note, URL strings may not be compatible with PIL. Check the PIL documentation for more information. """ def pilread(fname): """try to load the image with PIL or return None""" try: from PIL import Image except ImportError: return None with Image.open(fname) as image: return pil_to_array(image) handlers = { 'png': _png.read_png, } if format is None: if cbook.is_string_like(fname): parsed = urlparse(fname) # If the string is a URL, assume png if len(parsed.scheme) > 1: ext = 'png' else: basename, ext = os.path.splitext(fname) ext = ext.lower()[1:] elif hasattr(fname, 'name'): basename, ext = os.path.splitext(fname.name) ext = ext.lower()[1:] else: ext = 'png' else: ext = format if ext not in handlers: im = pilread(fname) if im is None: raise ValueError('Only know how to handle extensions: %s; ' 'with Pillow installed matplotlib can handle ' 'more images' % list(handlers)) return im handler = handlers[ext] # To handle Unicode filenames, we pass a file object to the PNG # reader extension, since Python handles them quite well, but it's # tricky in C. if cbook.is_string_like(fname): parsed = urlparse(fname) # If fname is a URL, download the data if len(parsed.scheme) > 1: fd = BytesIO(urlopen(fname).read()) return handler(fd) else: with open(fname, 'rb') as fd: return handler(fd) else: return handler(fname)
def set_location(self, loc): if is_string_like(loc): if loc not in self._LOCATIONS: raise ValueError('Unknown location code: %s' % loc) loc = self._LOCATIONS[loc] self._location = loc
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. Positions should be sequences of length 2. 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 Returns ------- matplotlib.collection.LineCollection `LineCollection` of the edges 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.github.io/documentation/latest/gallery.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 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 = plt.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() 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 draw_networkx_labels(G, pos, labels=None, font_size=12, font_color='k', font_family='sans-serif', font_weight='normal', alpha=1.0, ax=None, **kwds): """Draw node labels on 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. labels : dictionary, optional (default=None) Node labels in a dictionary keyed by node of text labels font_size : int Font size for text labels (default=12) font_color : string Font color string (default='k' black) font_family : string Font family (default='sans-serif') font_weight : string Font weight (default='normal') alpha : float The text transparency (default=1.0) ax : Matplotlib Axes object, optional Draw the graph in the specified Matplotlib axes. Returns ------- dict `dict` of labels keyed on the nodes Examples -------- >>> G=nx.dodecahedral_graph() >>> labels=nx.draw_networkx_labels(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_edges() draw_networkx_edge_labels() """ try: import matplotlib.pyplot as plt import matplotlib.cbook as cb 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 labels is None: labels = dict((n, n) for n in G.nodes()) # set optional alignment horizontalalignment = kwds.get('horizontalalignment', 'center') verticalalignment = kwds.get('verticalalignment', 'center') text_items = {} # there is no text collection so we'll fake one for n, label in labels.items(): (x, y) = pos[n] if not cb.is_string_like(label): label = str( label) # this will cause "1" and 1 to be labeled the same t = ax.text( x, y, label, size=font_size, color=font_color, family=font_family, weight=font_weight, horizontalalignment=horizontalalignment, verticalalignment=verticalalignment, transform=ax.transData, clip_on=True, ) text_items[n] = t return text_items
def draw_networkx_edge_labels(G, pos, edge_labels=None, label_pos=0.5, font_size=10, font_color='k', font_family='sans-serif', font_weight='normal', alpha=1.0, bbox=None, ax=None, rotate=True, **kwds): """Draw edge labels. 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. ax : Matplotlib Axes object, optional Draw the graph in the specified Matplotlib axes. alpha : float The text transparency (default=1.0) edge_labels : dictionary Edge labels in a dictionary keyed by edge two-tuple of text labels (default=None). Only labels for the keys in the dictionary are drawn. label_pos : float Position of edge label along edge (0=head, 0.5=center, 1=tail) font_size : int Font size for text labels (default=12) font_color : string Font color string (default='k' black) font_weight : string Font weight (default='normal') font_family : string Font family (default='sans-serif') bbox : Matplotlib bbox Specify text box shape and colors. clip_on : bool Turn on clipping at axis boundaries (default=True) Returns ------- dict `dict` of labels keyed on the edges Examples -------- >>> G=nx.dodecahedral_graph() >>> edge_labels=nx.draw_networkx_edge_labels(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_edges() draw_networkx_labels() """ try: import matplotlib.pyplot as plt import matplotlib.cbook as cb import numpy 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 edge_labels is None: labels = dict(((u, v), d) for u, v, d in G.edges(data=True)) else: labels = edge_labels text_items = {} for (n1, n2), label in labels.items(): (x1, y1) = pos[n1] (x2, y2) = pos[n2] (x, y) = (x1 * label_pos + x2 * (1.0 - label_pos), y1 * label_pos + y2 * (1.0 - label_pos)) if rotate: angle = numpy.arctan2(y2 - y1, x2 - x1) / (2.0 * numpy.pi) * 360 # degrees # make label orientation "right-side-up" if angle > 90: angle -= 180 if angle < -90: angle += 180 # transform data coordinate angle to screen coordinate angle xy = numpy.array((x, y)) trans_angle = ax.transData.transform_angles( numpy.array((angle, )), xy.reshape((1, 2)))[0] else: trans_angle = 0.0 # use default box of white with white border if bbox is None: bbox = dict( boxstyle='round', ec=(1.0, 1.0, 1.0), fc=(1.0, 1.0, 1.0), ) if not cb.is_string_like(label): label = str( label) # this will cause "1" and 1 to be labeled the same # set optional alignment horizontalalignment = kwds.get('horizontalalignment', 'center') verticalalignment = kwds.get('verticalalignment', 'center') t = ax.text( x, y, label, size=font_size, color=font_color, family=font_family, weight=font_weight, horizontalalignment=horizontalalignment, verticalalignment=verticalalignment, rotation=trans_angle, transform=ax.transData, bbox=bbox, zorder=1, clip_on=True, ) text_items[(n1, n2)] = t return text_items
def error_msg_qt(msg, parent=None): if not is_string_like(msg): msg = ','.join(map(str, msg)) QtWidgets.QMessageBox.warning(None, "Matplotlib", msg, QtGui.QMessageBox.Ok)
def get_text(self, lev, fmt): "get the text of the label" if cbook.is_string_like(lev): return lev else: return fmt%lev