def _write_svgfonts(self): if not rcParams['svg.fonttype'] == 'svgfont': return writer = self.writer writer.start('defs') for font_fname, chars in six.iteritems(self._fonts): font = get_font(font_fname) font.set_size(72, 72) sfnt = font.get_sfnt() writer.start('font', id=sfnt[(1, 0, 0, 4)]) writer.element( 'font-face', attrib={ 'font-family': font.family_name, 'font-style': font.style_name.lower(), 'units-per-em': '72', 'bbox': ' '.join(six.text_type(x / 64.0) for x in font.bbox)}) for char in chars: glyph = font.load_char(char, flags=LOAD_NO_HINTING) verts, codes = font.get_path() path = Path(verts, codes) path_data = self._convert_path(path) # name = font.get_glyph_name(char) writer.element( 'glyph', d=path_data, attrib={ # 'glyph-name': name, 'unicode': unichr(char), 'horiz-adv-x': six.text_type(glyph.linearHoriAdvance / 65536.0)}) writer.end('font') writer.end('defs')
def print_figure(self, fname, *args, **kwargs): if fname: fname = QtCore.QUrl(fname).toLocalFile() # save dir for next time savefig_dir = os.path.dirname(six.text_type(fname)) matplotlib.rcParams['savefig.directory'] = savefig_dir fname = six.text_type(fname) FigureCanvasAgg.print_figure(self, fname, *args, **kwargs) self.draw()
def draw_path_collection(self, gc, master_transform, paths, all_transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds, urls, offset_position): # Is the optimization worth it? Rough calculation: # cost of emitting a path in-line is # (len_path + 5) * uses_per_path # cost of definition+use is # (len_path + 3) + 9 * uses_per_path len_path = len(paths[0].vertices) if len(paths) > 0 else 0 uses_per_path = self._iter_collection_uses_per_path( paths, all_transforms, offsets, facecolors, edgecolors) should_do_optimization = \ len_path + 9 * uses_per_path + 3 < (len_path + 5) * uses_per_path if not should_do_optimization: return RendererBase.draw_path_collection( self, gc, master_transform, paths, all_transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds, urls, offset_position) writer = self.writer path_codes = [] writer.start('defs') for i, (path, transform) in enumerate( self._iter_collection_raw_paths(master_transform, paths, all_transforms)): transform = Affine2D(transform.get_matrix()).scale(1.0, -1.0) d = self._convert_path(path, transform, simplify=False) oid = 'C%x_%x_%s' % (self._path_collection_id, i, self._make_id('', d)) writer.element('path', id=oid, d=d) path_codes.append(oid) writer.end('defs') for xo, yo, path_id, gc0, rgbFace in self._iter_collection( gc, master_transform, all_transforms, path_codes, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds, urls, offset_position): clipid = self._get_clip(gc0) url = gc0.get_url() if url is not None: writer.start('a', attrib={'xlink:href': url}) if clipid is not None: writer.start('g', attrib={'clip-path': 'url(#%s)' % clipid}) attrib = { 'xlink:href': '#%s' % path_id, 'x': six.text_type(xo), 'y': six.text_type(self.height - yo), 'style': self._get_style(gc0, rgbFace) } writer.element('use', attrib=attrib) if clipid is not None: writer.end('g') if url is not None: writer.end('a') self._path_collection_id += 1
def validate_stringlist(s): 'return a list' if isinstance(s, six.string_types): return [six.text_type(v.strip()) for v in s.split(',') if v.strip()] elif type(s) in (list, tuple): return [six.text_type(v) for v in s if v] else: msg = "'s' must be of type [ string | list | tuple ]" raise ValueError(msg)
def draw_path_collection(self, gc, master_transform, paths, all_transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds, urls, offset_position): # Is the optimization worth it? Rough calculation: # cost of emitting a path in-line is # (len_path + 5) * uses_per_path # cost of definition+use is # (len_path + 3) + 9 * uses_per_path len_path = len(paths[0].vertices) if len(paths) > 0 else 0 uses_per_path = self._iter_collection_uses_per_path( paths, all_transforms, offsets, facecolors, edgecolors) should_do_optimization = \ len_path + 9 * uses_per_path + 3 < (len_path + 5) * uses_per_path if not should_do_optimization: return RendererBase.draw_path_collection( self, gc, master_transform, paths, all_transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds, urls, offset_position) writer = self.writer path_codes = [] writer.start('defs') for i, (path, transform) in enumerate(self._iter_collection_raw_paths( master_transform, paths, all_transforms)): transform = Affine2D(transform.get_matrix()).scale(1.0, -1.0) d = self._convert_path(path, transform, simplify=False) oid = 'C%x_%x_%s' % (self._path_collection_id, i, self._make_id('', d)) writer.element('path', id=oid, d=d) path_codes.append(oid) writer.end('defs') for xo, yo, path_id, gc0, rgbFace in self._iter_collection( gc, master_transform, all_transforms, path_codes, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds, urls, offset_position): clipid = self._get_clip(gc0) url = gc0.get_url() if url is not None: writer.start('a', attrib={'xlink:href': url}) if clipid is not None: writer.start('g', attrib={'clip-path': 'url(#%s)' % clipid}) attrib = { 'xlink:href': '#%s' % path_id, 'x': six.text_type(xo), 'y': six.text_type(self.height - yo), 'style': self._get_style(gc0, rgbFace) } writer.element('use', attrib=attrib) if clipid is not None: writer.end('g') if url is not None: writer.end('a') self._path_collection_id += 1
def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): if not len(path.vertices): return writer = self.writer path_data = self._convert_path(marker_path, marker_trans + Affine2D().scale(1.0, -1.0), simplify=False) style = self._get_style_dict(gc, rgbFace) dictkey = (path_data, generate_css(style)) oid = self._markers.get(dictkey) for key in list(six.iterkeys(style)): if not key.startswith('stroke'): del style[key] style = generate_css(style) if oid is None: oid = self._make_id('m', dictkey) writer.start('defs') writer.element('path', id=oid, d=path_data, style=style) writer.end('defs') self._markers[dictkey] = oid attrib = {} clipid = self._get_clip(gc) if clipid is not None: attrib['clip-path'] = 'url(#%s)' % clipid writer.start('g', attrib=attrib) trans_and_flip = self._make_flip_transform(trans) attrib = {'xlink:href': '#%s' % oid} clip = (0, 0, self.width * 72, self.height * 72) for vertices, code in path.iter_segments(trans_and_flip, clip=clip, simplify=False): if len(vertices): x, y = vertices[-2:] attrib['x'] = six.text_type(x) attrib['y'] = six.text_type(y) attrib['style'] = self._get_style(gc, rgbFace) writer.element('use', attrib=attrib) writer.end('g')
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_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): # Note: x,y are device/display coords, not user-coords, unlike other # draw_* methods if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) if ismath: self._draw_mathtext(gc, x, y, s, prop, angle) else: ctx = gc.ctx ctx.new_path() ctx.move_to(x, y) ctx.select_font_face(prop.get_name(), self.fontangles[prop.get_style()], self.fontweights[prop.get_weight()]) size = prop.get_size_in_points() * self.dpi / 72.0 ctx.save() if angle: ctx.rotate(-angle * np.pi / 180) ctx.set_font_size(size) if HAS_CAIRO_CFFI: if not isinstance(s, six.text_type): s = six.text_type(s) else: if not six.PY3 and isinstance(s, six.text_type): s = s.encode("utf-8") ctx.show_text(s) ctx.restore()
def edit_parameters(self): allaxes = self.canvas.figure.get_axes() if not allaxes: QtWidgets.QMessageBox.warning( self.parent, "Error", "There are no axes to edit.") return if len(allaxes) == 1: axes = allaxes[0] else: titles = [] for axes in allaxes: name = (axes.get_title() or " - ".join(filter(None, [axes.get_xlabel(), axes.get_ylabel()])) or "<anonymous {} (id: {:#x})>".format( type(axes).__name__, id(axes))) titles.append(name) item, ok = QtWidgets.QInputDialog.getItem( self.parent, 'Customize', 'Select axes:', titles, 0, False) if ok: axes = allaxes[titles.index(six.text_type(item))] else: return figureoptions.figure_edit(axes, self)
def get_text_width_height_descent(self, s, prop, ismath): if ismath == 'TeX': # todo: handle props texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() w, h, d = texmanager.get_text_width_height_descent(s, fontsize, renderer=self) return w, h, d if ismath: ox, oy, width, height, descent, fonts, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) return width, height, descent family = prop.get_family() weight = prop.get_weight() # transform weight into string for the native backend if weight >= 700: weight = 'bold' else: weight = 'normal' style = prop.get_style() points = prop.get_size_in_points() size = self.points_to_pixels(points) width, height, descent = self.gc.get_text_width_height_descent( six.text_type(s), family, size, weight, style) return width, height, 0.0 * descent
def get(self): valuelist = [] for index, (label, value) in enumerate(self.data): field = self.widgets[index] if label is None: # Separator / Comment continue elif tuple_to_qfont(value) is not None: value = field.get_font() elif isinstance(value, six.string_types) or is_color_like(value): value = six.text_type(field.text()) elif isinstance(value, (list, tuple)): index = int(field.currentIndex()) if isinstance(value[0], (list, tuple)): value = value[index][0] else: value = value[index] elif isinstance(value, bool): value = field.checkState() == QtCore.Qt.Checked elif isinstance(value, float): value = float(str(field.text())) elif isinstance(value, int): value = int(field.value()) elif isinstance(value, datetime.datetime): value = field.dateTime().toPyDateTime() elif isinstance(value, datetime.date): value = field.date().toPyDate() else: value = eval(str(field.text())) valuelist.append(value) return valuelist
def get_fontconfig_fonts(fontext='ttf'): """ Grab a list of all the fonts that are being tracked by fontconfig by making a system call to ``fc-list``. This is an easy way to grab all of the fonts the user wants to be made available to applications, without needing knowing where all of them reside. """ fontext = get_fontext_synonyms(fontext) fontfiles = {} try: pipe = subprocess.Popen(['fc-list', '--format=%{file}\\n'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = pipe.communicate()[0] except (OSError, IOError): # Calling fc-list did not work, so we'll just return nothing return fontfiles if pipe.returncode == 0: # The line breaks between results are in ascii, but each entry # is in in sys.filesystemencoding(). for fname in output.split(b'\n'): try: fname = six.text_type(fname, sys.getfilesystemencoding()) except UnicodeDecodeError: continue if (os.path.splitext(fname)[1][1:] in fontext and os.path.exists(fname)): fontfiles[fname] = 1 return fontfiles
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): # Note: x,y are device/display coords, not user-coords, unlike other # draw_* methods if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name())) if ismath: self._draw_mathtext(gc, x, y, s, prop, angle) else: ctx = gc.ctx ctx.new_path() ctx.move_to (x, y) ctx.select_font_face (prop.get_name(), self.fontangles [prop.get_style()], self.fontweights[prop.get_weight()]) size = prop.get_size_in_points() * self.dpi / 72.0 ctx.save() if angle: ctx.rotate (-angle * np.pi / 180) ctx.set_font_size (size) if HAS_CAIRO_CFFI: if not isinstance(s, six.text_type): s = six.text_type(s) else: if not six.PY3 and isinstance(s, six.text_type): s = s.encode("utf-8") ctx.show_text(s) ctx.restore()
def edit_parameters(self): allaxes = self.canvas.figure.get_axes() if len(allaxes) == 1: axes = allaxes[0] else: titles = [] for axes in allaxes: title = axes.get_title() ylabel = axes.get_ylabel() label = axes.get_label() if title: fmt = "%(title)s" if ylabel: fmt += ": %(ylabel)s" fmt += " (%(axes_repr)s)" elif ylabel: fmt = "%(axes_repr)s (%(ylabel)s)" elif label: fmt = "%(axes_repr)s (%(label)s)" else: fmt = "%(axes_repr)s" titles.append(fmt % dict(title=title, ylabel=ylabel, label=label, axes_repr=repr(axes))) item, ok = QtWidgets.QInputDialog.getItem( self.parent, 'Customize', 'Select axes:', titles, 0, False) if ok: axes = allaxes[titles.index(six.text_type(item))] else: return figureoptions.figure_edit(axes, self)
def update_savefig_format(value): # The old savefig.extension could also have a value of "auto", but # the new savefig.format does not. We need to fix this here. value = six.text_type(value) if value == 'auto': value = 'png' return value
def edit_parameters(self): allaxes = self.canvas.figure.get_axes() if not allaxes: QtWidgets.QMessageBox.warning(self.parent, "Error", "There are no axes to edit.") return if len(allaxes) == 1: axes = allaxes[0] else: titles = [] for axes in allaxes: name = (axes.get_title() or " - ".join( filter(None, [axes.get_xlabel(), axes.get_ylabel()])) or "<anonymous {} (id: {:#x})>".format( type(axes).__name__, id(axes))) titles.append(name) item, ok = QtWidgets.QInputDialog.getItem( self.parent, 'Customize', 'Select axes:', titles, 0, False) if ok: axes = allaxes[titles.index(six.text_type(item))] else: return figureoptions.figure_edit(axes, self)
def get_text_width_height_descent(self, s, prop, ismath): if ismath=='TeX': # todo: handle props texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() w, h, d = texmanager.get_text_width_height_descent(s, fontsize, renderer=self) return w, h, d if ismath: ox, oy, width, height, descent, fonts, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) return width, height, descent family = prop.get_family() weight = prop.get_weight() # transform weight into string for the native backend if weight >= 700: weight = 'bold' else: weight = 'normal' style = prop.get_style() points = prop.get_size_in_points() size = self.points_to_pixels(points) width, height, descent = self.gc.get_text_width_height_descent( six.text_type(s), family, size, weight, style) return width, height, descent
def __init__(self): if self.texcache is None: raise RuntimeError( ('Cannot create TexManager, as there is no cache directory ' 'available')) mkdirs(self.texcache) ff = rcParams['font.family'] if len(ff) == 1 and ff[0].lower() in self.font_families: self.font_family = ff[0].lower() elif isinstance(ff, six.string_types) and ff.lower() in self.font_families: self.font_family = ff.lower() else: mpl.verbose.report( 'font.family must be one of (%s) when text.usetex is True. ' 'serif will be used by default.' % ', '.join(self.font_families), 'helpful') self.font_family = 'serif' fontconfig = [self.font_family] for font_family, font_family_attr in [(ff, ff.replace('-', '_')) for ff in self.font_families]: for font in rcParams['font.' + font_family]: if font.lower() in self.font_info: setattr(self, font_family_attr, self.font_info[font.lower()]) if DEBUG: print('family: %s, font: %s, info: %s' % (font_family, font, self.font_info[font.lower()])) break else: if DEBUG: print('$s font is not compatible with usetex') else: mpl.verbose.report('No LaTeX-compatible font found for the ' '%s font family in rcParams. Using ' 'default.' % ff, 'helpful') setattr(self, font_family_attr, self.font_info[font_family]) fontconfig.append(getattr(self, font_family_attr)[0]) # Add a hash of the latex preamble to self._fontconfig so that the # correct png is selected for strings rendered with same font and dpi # even if the latex preamble changes within the session preamble_bytes = six.text_type(self.get_custom_preamble()).encode('utf-8') fontconfig.append(md5(preamble_bytes).hexdigest()) self._fontconfig = ''.join(fontconfig) # The following packages and commands need to be included in the latex # file's preamble: cmd = [self.serif[1], self.sans_serif[1], self.monospace[1]] if self.font_family == 'cursive': cmd.append(self.cursive[1]) while '\\usepackage{type1cm}' in cmd: cmd.remove('\\usepackage{type1cm}') cmd = '\n'.join(cmd) self._font_preamble = '\n'.join(['\\usepackage{type1cm}', cmd, '\\usepackage{textcomp}'])
def get_basefile(self, tex, fontsize, dpi=None): """ returns a filename based on a hash of the string, fontsize, and dpi """ s = "".join([tex, self.get_font_config(), "%f" % fontsize, self.get_custom_preamble(), str(dpi or "")]) # make sure hash is consistent for all strings, regardless of encoding: bytes = six.text_type(s).encode("utf-8") return os.path.join(self.texcache, md5(bytes).hexdigest())
def validate_string_or_None(s): """convert s to string or raise""" if s is None: return None try: return six.text_type(s) except ValueError: raise ValueError('Could not convert "%s" to string' % s)
def _write_clips(self): if not len(self._clipd): return writer = self.writer writer.start('defs') for clip, oid in six.itervalues(self._clipd): writer.start('clipPath', id=oid) if len(clip) == 2: clippath, clippath_trans = clip path_data = self._convert_path(clippath, clippath_trans, simplify=False) writer.element('path', d=path_data) else: x, y, w, h = clip writer.element('rect', x=six.text_type(x), y=six.text_type(y), width=six.text_type(w), height=six.text_type(h)) writer.end('clipPath') writer.end('defs')
def _write_hatches(self): if not len(self._hatchd): return HATCH_SIZE = 72 writer = self.writer writer.start('defs') for ((path, face, stroke), oid) in six.itervalues(self._hatchd): writer.start('pattern', id=oid, patternUnits="userSpaceOnUse", x="0", y="0", width=six.text_type(HATCH_SIZE), height=six.text_type(HATCH_SIZE)) path_data = self._convert_path(path, Affine2D().scale(HATCH_SIZE).scale( 1.0, -1.0).translate(0, HATCH_SIZE), simplify=False) if face is None: fill = 'none' else: fill = rgb2hex(face) writer.element('rect', x="0", y="0", width=six.text_type(HATCH_SIZE + 1), height=six.text_type(HATCH_SIZE + 1), fill=fill) writer.element('path', d=path_data, style=generate_css({ 'fill': rgb2hex(stroke), 'stroke': rgb2hex(stroke), 'stroke-width': six.text_type(rcParams['hatch.linewidth']), 'stroke-linecap': 'butt', 'stroke-linejoin': 'miter' })) writer.end('pattern') writer.end('defs')
def get_basefile(self, tex, fontsize, dpi=None): """ returns a filename based on a hash of the string, fontsize, and dpi """ s = ''.join([tex, self.get_font_config(), '%f' % fontsize, self.get_custom_preamble(), str(dpi or '')]) # make sure hash is consistent for all strings, regardless of encoding: bytes = six.text_type(s).encode('utf-8') return os.path.join(self.texcache, md5(bytes).hexdigest())
def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): if not len(path.vertices): return writer = self.writer path_data = self._convert_path( marker_path, marker_trans + Affine2D().scale(1.0, -1.0), simplify=False) style = self._get_style_dict(gc, rgbFace) dictkey = (path_data, generate_css(style)) oid = self._markers.get(dictkey) for key in list(six.iterkeys(style)): if not key.startswith('stroke'): del style[key] style = generate_css(style) if oid is None: oid = self._make_id('m', dictkey) writer.start('defs') writer.element('path', id=oid, d=path_data, style=style) writer.end('defs') self._markers[dictkey] = oid attrib = {} clipid = self._get_clip(gc) if clipid is not None: attrib['clip-path'] = 'url(#%s)' % clipid writer.start('g', attrib=attrib) trans_and_flip = self._make_flip_transform(trans) attrib = {'xlink:href': '#%s' % oid} clip = (0, 0, self.width*72, self.height*72) for vertices, code in path.iter_segments( trans_and_flip, clip=clip, simplify=False): if len(vertices): x, y = vertices[-2:] attrib['x'] = six.text_type(x) attrib['y'] = six.text_type(y) attrib['style'] = self._get_style(gc, rgbFace) writer.element('use', attrib=attrib) writer.end('g')
def _write_svgfonts(self): if not rcParams['svg.fonttype'] == 'svgfont': return writer = self.writer writer.start('defs') for font_fname, chars in six.iteritems(self._fonts): font = get_font(font_fname) font.set_size(72, 72) sfnt = font.get_sfnt() writer.start('font', id=sfnt[(1, 0, 0, 4)]) writer.element('font-face', attrib={ 'font-family': font.family_name, 'font-style': font.style_name.lower(), 'units-per-em': '72', 'bbox': ' '.join( six.text_type(x / 64.0) for x in font.bbox) }) for char in chars: glyph = font.load_char(char, flags=LOAD_NO_HINTING) verts, codes = font.get_path() path = Path(verts, codes) path_data = self._convert_path(path) # name = font.get_glyph_name(char) writer.element( 'glyph', d=path_data, attrib={ # 'glyph-name': name, 'unicode': unichr(char), 'horiz-adv-x': six.text_type(glyph.linearHoriAdvance / 65536.0) }) writer.end('font') writer.end('defs')
def _print_bitmap(self, filename, *args, **kwargs): # In backend_bases.py, print_figure changes the dpi of the figure. # But since we are essentially redrawing the picture, we need the # original dpi. Pick it up from the renderer. dpi = kwargs['dpi'] old_dpi = self.figure.dpi self.figure.dpi = self.renderer.dpi width, height = self.figure.get_size_inches() width, height = width * dpi, height * dpi filename = six.text_type(filename) self.write_bitmap(filename, width, height, dpi) self.figure.dpi = old_dpi
def __init__(self): if self.texcache is None: raise RuntimeError(("Cannot create TexManager, as there is no cache directory " "available")) mkdirs(self.texcache) ff = rcParams["font.family"] if len(ff) == 1 and ff[0].lower() in self.font_families: self.font_family = ff[0].lower() elif isinstance(ff, six.string_types) and ff.lower() in self.font_families: self.font_family = ff.lower() else: mpl.verbose.report( "font.family must be one of (%s) when text.usetex is True. " "serif will be used by default." % ", ".join(self.font_families), "helpful", ) self.font_family = "serif" fontconfig = [self.font_family] for font_family, font_family_attr in [(ff, ff.replace("-", "_")) for ff in self.font_families]: for font in rcParams["font." + font_family]: if font.lower() in self.font_info: setattr(self, font_family_attr, self.font_info[font.lower()]) if DEBUG: print("family: %s, font: %s, info: %s" % (font_family, font, self.font_info[font.lower()])) break else: if DEBUG: print("$s font is not compatible with usetex") else: mpl.verbose.report( "No LaTeX-compatible font found for the " "%s font family in rcParams. Using " "default." % ff, "helpful", ) setattr(self, font_family_attr, self.font_info[font_family]) fontconfig.append(getattr(self, font_family_attr)[0]) # Add a hash of the latex preamble to self._fontconfig so that the # correct png is selected for strings rendered with same font and dpi # even if the latex preamble changes within the session preamble_bytes = six.text_type(self.get_custom_preamble()).encode("utf-8") fontconfig.append(md5(preamble_bytes).hexdigest()) self._fontconfig = "".join(fontconfig) # The following packages and commands need to be included in the latex # file's preamble: cmd = [self.serif[1], self.sans_serif[1], self.monospace[1]] if self.font_family == "cursive": cmd.append(self.cursive[1]) while "\\usepackage{type1cm}" in cmd: cmd.remove("\\usepackage{type1cm}") cmd = "\n".join(cmd) self._font_preamble = "\n".join(["\\usepackage{type1cm}", cmd, "\\usepackage{textcomp}"])
def _print_bitmap(self, filename, *args, **kwargs): # In backend_bases.py, print_figure changes the dpi of the figure. # But since we are essentially redrawing the picture, we need the # original dpi. Pick it up from the renderer. dpi = kwargs['dpi'] old_dpi = self.figure.dpi self.figure.dpi = self.renderer.dpi width, height = self.figure.get_size_inches() width, height = width*dpi, height*dpi filename = six.text_type(filename) self.write_bitmap(filename, width, height, dpi) self.figure.dpi = old_dpi
def test_dviread(): dir = os.path.join(os.path.dirname(__file__), 'baseline_images', 'dviread') with open(os.path.join(dir, 'test.json')) as f: correct = json.load(f) with dr.Dvi(os.path.join(dir, 'test.dvi'), None) as dvi: data = [{'text': [[t.x, t.y, six.unichr(t.glyph), six.text_type(t.font.texname), round(t.font.size, 2)] for t in page.text], 'boxes': [[b.x, b.y, b.height, b.width] for b in page.boxes]} for page in dvi] assert_equal(data, correct)
def _write_hatches(self): if not len(self._hatchd): return HATCH_SIZE = 72 writer = self.writer writer.start('defs') for ((path, face, stroke), oid) in six.itervalues(self._hatchd): writer.start( 'pattern', id=oid, patternUnits="userSpaceOnUse", x="0", y="0", width=six.text_type(HATCH_SIZE), height=six.text_type(HATCH_SIZE)) path_data = self._convert_path( path, Affine2D().scale(HATCH_SIZE).scale(1.0, -1.0).translate(0, HATCH_SIZE), simplify=False) if face is None: fill = 'none' else: fill = rgb2hex(face) writer.element( 'rect', x="0", y="0", width=six.text_type(HATCH_SIZE+1), height=six.text_type(HATCH_SIZE+1), fill=fill) writer.element( 'path', d=path_data, style=generate_css({ 'fill': rgb2hex(stroke), 'stroke': rgb2hex(stroke), 'stroke-width': '1.0', 'stroke-linecap': 'butt', 'stroke-linejoin': 'miter' }) ) writer.end('pattern') writer.end('defs')
def save_figure(self, *args): filetypes = self.canvas.get_supported_filetypes_grouped() sorted_filetypes = list(six.iteritems(filetypes)) sorted_filetypes.sort() default_filetype = self.canvas.get_default_filetype() startpath = matplotlib.rcParams.get("savefig.directory", "") startpath = os.path.expanduser(startpath) start = os.path.join(startpath, self.canvas.get_default_filename()) filters = [] selectedFilter = None for name, exts in sorted_filetypes: exts_list = " ".join(["*.%s" % ext for ext in exts]) filter = "%s (%s)" % (name, exts_list) if default_filetype in exts: selectedFilter = filter filters.append(filter) filters = ";;".join(filters) fname, filter = _getSaveFileName(self.parent, "Choose a filename to save to", start, filters, selectedFilter) if fname: if startpath == "": # explicitly missing key or empty str signals to use cwd matplotlib.rcParams["savefig.directory"] = startpath else: # save dir for next time savefig_dir = os.path.dirname(six.text_type(fname)) matplotlib.rcParams["savefig.directory"] = savefig_dir try: self.canvas.print_figure(six.text_type(fname)) except Exception as e: QtWidgets.QMessageBox.critical( self, "Error saving file", six.text_type(e), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton, )
def trigger(self, *args): from matplotlib.externals.six.moves import tkinter_tkfiledialog, tkinter_messagebox filetypes = self.figure.canvas.get_supported_filetypes().copy() default_filetype = self.figure.canvas.get_default_filetype() # Tk doesn't provide a way to choose a default filetype, # so we just have to put it first default_filetype_name = filetypes[default_filetype] del filetypes[default_filetype] sorted_filetypes = list(six.iteritems(filetypes)) sorted_filetypes.sort() sorted_filetypes.insert(0, (default_filetype, default_filetype_name)) tk_filetypes = [ (name, '*.%s' % ext) for (ext, name) in sorted_filetypes] # adding a default extension seems to break the # asksaveasfilename dialog when you choose various save types # from the dropdown. Passing in the empty string seems to # work - JDH! # defaultextension = self.figure.canvas.get_default_filetype() defaultextension = '' initialdir = rcParams.get('savefig.directory', '') initialdir = os.path.expanduser(initialdir) initialfile = self.figure.canvas.get_default_filename() fname = tkinter_tkfiledialog.asksaveasfilename( master=self.figure.canvas.manager.window, title='Save the figure', filetypes=tk_filetypes, defaultextension=defaultextension, initialdir=initialdir, initialfile=initialfile, ) if fname == "" or fname == (): return else: if initialdir == '': # explicitly missing key or empty str signals to use cwd rcParams['savefig.directory'] = initialdir else: # save dir for next time rcParams['savefig.directory'] = os.path.dirname( six.text_type(fname)) try: # This method will handle the delegation to the correct type self.figure.canvas.print_figure(fname) except Exception as e: tkinter_messagebox.showerror("Error saving file", str(e))
def save_figure(self, *args): filetypes = self.canvas.get_supported_filetypes_grouped() sorted_filetypes = list(six.iteritems(filetypes)) sorted_filetypes.sort() default_filetype = self.canvas.get_default_filetype() startpath = matplotlib.rcParams.get('savefig.directory', '') startpath = os.path.expanduser(startpath) start = os.path.join(startpath, self.canvas.get_default_filename()) filters = [] selectedFilter = None for name, exts in sorted_filetypes: exts_list = " ".join(['*.%s' % ext for ext in exts]) filter = '%s (%s)' % (name, exts_list) if default_filetype in exts: selectedFilter = filter filters.append(filter) filters = ';;'.join(filters) fname, filter = _getSaveFileName(self.parent, "Choose a filename to save to", start, filters, selectedFilter) if fname: if startpath == '': # explicitly missing key or empty str signals to use cwd matplotlib.rcParams['savefig.directory'] = startpath else: # save dir for next time savefig_dir = os.path.dirname(six.text_type(fname)) matplotlib.rcParams['savefig.directory'] = savefig_dir try: self.canvas.print_figure(six.text_type(fname)) except Exception as e: QtWidgets.QMessageBox.critical(self, "Error saving file", six.text_type(e), QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton)
def exception_handler(type, value, tb): """Handle uncaught exceptions It does not catch SystemExit """ msg = '' # get the filename attribute if available (for IOError) if hasattr(value, 'filename') and value.filename is not None: msg = value.filename + ': ' if hasattr(value, 'strerror') and value.strerror is not None: msg += value.strerror else: msg += six.text_type(value) if len(msg): error_msg_qt(msg)
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): if ismath: self._draw_mathtext(gc, x, y, s, prop, angle) else: family = prop.get_family() weight = prop.get_weight() # transform weight into string for the native backend if weight >= 700: weight = 'bold' else: weight = 'normal' style = prop.get_style() points = prop.get_size_in_points() size = self.points_to_pixels(points) gc.draw_text(x, y, six.text_type(s), family, size, weight, style, angle)
def save_figure(self, *args): chooser = self.get_filechooser() fname, format = chooser.get_filename_from_user() chooser.destroy() if fname: startpath = os.path.expanduser(rcParams.get('savefig.directory', '')) if startpath == '': # explicitly missing key or empty str signals to use cwd rcParams['savefig.directory'] = startpath else: # save dir for next time rcParams['savefig.directory'] = os.path.dirname(six.text_type(fname)) try: self.canvas.print_figure(fname, format=format) except Exception as e: error_msg_gtk(str(e), parent=self)
def _get_style_dict(self, gc, rgbFace): """ return the style string. style is generated from the GraphicsContext and rgbFace """ attrib = {} forced_alpha = gc.get_forced_alpha() if gc.get_hatch() is not None: attrib['fill'] = "url(#%s)" % self._get_hatch(gc, rgbFace) if rgbFace is not None and len( rgbFace) == 4 and rgbFace[3] != 1.0 and not forced_alpha: attrib['fill-opacity'] = str(rgbFace[3]) else: if rgbFace is None: attrib['fill'] = 'none' else: if tuple(rgbFace[:3]) != (0, 0, 0): attrib['fill'] = rgb2hex(rgbFace) if len(rgbFace ) == 4 and rgbFace[3] != 1.0 and not forced_alpha: attrib['fill-opacity'] = str(rgbFace[3]) if forced_alpha and gc.get_alpha() != 1.0: attrib['opacity'] = str(gc.get_alpha()) offset, seq = gc.get_dashes() if seq is not None: attrib['stroke-dasharray'] = ','.join(['%f' % val for val in seq]) attrib['stroke-dashoffset'] = six.text_type(float(offset)) linewidth = gc.get_linewidth() if linewidth: rgb = gc.get_rgb() attrib['stroke'] = rgb2hex(rgb) if not forced_alpha and rgb[3] != 1.0: attrib['stroke-opacity'] = str(rgb[3]) if linewidth != 1.0: attrib['stroke-width'] = str(linewidth) if gc.get_joinstyle() != 'round': attrib['stroke-linejoin'] = gc.get_joinstyle() if gc.get_capstyle() != 'butt': attrib['stroke-linecap'] = _capstyle_d[gc.get_capstyle()] return attrib
def _get_style_dict(self, gc, rgbFace): """ return the style string. style is generated from the GraphicsContext and rgbFace """ attrib = {} forced_alpha = gc.get_forced_alpha() if gc.get_hatch() is not None: attrib['fill'] = "url(#%s)" % self._get_hatch(gc, rgbFace) if rgbFace is not None and len(rgbFace) == 4 and rgbFace[3] != 1.0 and not forced_alpha: attrib['fill-opacity'] = str(rgbFace[3]) else: if rgbFace is None: attrib['fill'] = 'none' else: if tuple(rgbFace[:3]) != (0, 0, 0): attrib['fill'] = rgb2hex(rgbFace) if len(rgbFace) == 4 and rgbFace[3] != 1.0 and not forced_alpha: attrib['fill-opacity'] = str(rgbFace[3]) if forced_alpha and gc.get_alpha() != 1.0: attrib['opacity'] = str(gc.get_alpha()) offset, seq = gc.get_dashes() if seq is not None: attrib['stroke-dasharray'] = ','.join(['%f' % val for val in seq]) attrib['stroke-dashoffset'] = six.text_type(float(offset)) linewidth = gc.get_linewidth() if linewidth: rgb = gc.get_rgb() attrib['stroke'] = rgb2hex(rgb) if not forced_alpha and rgb[3] != 1.0: attrib['stroke-opacity'] = str(rgb[3]) if linewidth != 1.0: attrib['stroke-width'] = str(linewidth) if gc.get_joinstyle() != 'round': attrib['stroke-linejoin'] = gc.get_joinstyle() if gc.get_capstyle() != 'butt': attrib['stroke-linecap'] = _capstyle_d[gc.get_capstyle()] return attrib
def _create_qApp(): """ Only one qApp can exist at a time, so check before creating one. """ global qApp if qApp is None: if DEBUG: print("Starting up QApplication") app = QtWidgets.QApplication.instance() if app is None: # check for DISPLAY env variable on X11 build of Qt if hasattr(QtGui, "QX11Info"): display = os.environ.get('DISPLAY') if display is None or not re.search(':\d', display): raise RuntimeError('Invalid DISPLAY variable') qApp = QtWidgets.QApplication([six.text_type(" ")]) qApp.lastWindowClosed.connect(qApp.quit) else: qApp = app
def fc_match(pattern, fontext): fontexts = get_fontext_synonyms(fontext) ext = "." + fontext try: pipe = subprocess.Popen( ["fc-match", "-s", "--format=%{file}\\n", pattern], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) output = pipe.communicate()[0] except (OSError, IOError): return None # The bulk of the output from fc-list is ascii, so we keep the # result in bytes and parse it as bytes, until we extract the # filename, which is in sys.filesystemencoding(). if pipe.returncode == 0: for fname in output.split(b"\n"): try: fname = six.text_type(fname, sys.getfilesystemencoding()) except UnicodeDecodeError: continue if os.path.splitext(fname)[1][1:] in fontexts: return fname return None
def fc_match(pattern, fontext): fontexts = get_fontext_synonyms(fontext) ext = "." + fontext try: pipe = subprocess.Popen( ['fc-match', '-s', '--format=%{file}\\n', pattern], stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = pipe.communicate()[0] except (OSError, IOError): return None # The bulk of the output from fc-list is ascii, so we keep the # result in bytes and parse it as bytes, until we extract the # filename, which is in sys.filesystemencoding(). if pipe.returncode == 0: for fname in output.split(b'\n'): try: fname = six.text_type(fname, sys.getfilesystemencoding()) except UnicodeDecodeError: continue if os.path.splitext(fname)[1][1:] in fontexts: return fname return None
def get_window_title(self): return six.text_type(self.window.windowTitle())
def run_code(code, code_path, ns=None, function_name=None): """ Import a Python module from a path, and run the function given by name, if function_name is not None. """ # Change the working directory to the directory of the example, so # it can get at its data files, if any. Add its path to sys.path # so it can import any helper modules sitting beside it. if six.PY2: pwd = os.getcwdu() else: pwd = os.getcwd() old_sys_path = list(sys.path) if setup.config.plot_working_directory is not None: try: os.chdir(setup.config.plot_working_directory) except OSError as err: raise OSError(str(err) + '\n`plot_working_directory` option in' 'Sphinx configuration file must be a valid ' 'directory path') except TypeError as err: raise TypeError(str(err) + '\n`plot_working_directory` option in ' 'Sphinx configuration file must be a string or ' 'None') sys.path.insert(0, setup.config.plot_working_directory) elif code_path is not None: dirname = os.path.abspath(os.path.dirname(code_path)) os.chdir(dirname) sys.path.insert(0, dirname) # Reset sys.argv old_sys_argv = sys.argv sys.argv = [code_path] # Redirect stdout stdout = sys.stdout if six.PY3: sys.stdout = io.StringIO() else: sys.stdout = cStringIO.StringIO() # Assign a do-nothing print function to the namespace. There # doesn't seem to be any other way to provide a way to (not) print # that works correctly across Python 2 and 3. def _dummy_print(*arg, **kwarg): pass try: try: code = unescape_doctest(code) if ns is None: ns = {} if not ns: if setup.config.plot_pre_code is None: six.exec_(six.text_type("import numpy as np\n" + "from matplotlib import pyplot as plt\n"), ns) else: six.exec_(six.text_type(setup.config.plot_pre_code), ns) ns['print'] = _dummy_print if "__main__" in code: six.exec_("__name__ = '__main__'", ns) code = remove_coding(code) six.exec_(code, ns) if function_name is not None: six.exec_(function_name + "()", ns) except (Exception, SystemExit) as err: raise PlotError(traceback.format_exc()) finally: os.chdir(pwd) sys.argv = old_sys_argv sys.path[:] = old_sys_path sys.stdout = stdout return ns