From: <md...@us...> - 2008-11-07 14:52:19
|
Revision: 6372 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6372&view=rev Author: mdboom Date: 2008-11-07 14:52:04 +0000 (Fri, 07 Nov 2008) Log Message: ----------- Committed Andrew Straw's patch to support hyperlinks. Currently only the SVG backend, but the infrastructure is there for other backends to support it. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/artist.py trunk/matplotlib/lib/matplotlib/axes.py trunk/matplotlib/lib/matplotlib/backend_bases.py trunk/matplotlib/lib/matplotlib/backends/backend_ps.py trunk/matplotlib/lib/matplotlib/backends/backend_svg.py trunk/matplotlib/lib/matplotlib/collections.py trunk/matplotlib/lib/matplotlib/image.py trunk/matplotlib/lib/matplotlib/patches.py trunk/matplotlib/lib/matplotlib/text.py trunk/matplotlib/src/_backend_agg.cpp Added Paths: ----------- trunk/matplotlib/examples/pylab_examples/hyperlinks.py Added: trunk/matplotlib/examples/pylab_examples/hyperlinks.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/hyperlinks.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/hyperlinks.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- noplot -*- + +""" +This example demonstrates how to set a hyperlinks on various kinds of elements. + +This currently only works with the SVG backend. +""" + +import numpy as np +import matplotlib.cm as cm +import matplotlib.mlab as mlab +import matplotlib.pyplot as plt + +f = plt.figure() +s = plt.scatter([1,2,3],[4,5,6]) +s.set_urls(['http://www.bbc.co.uk/news','http://www.google.com',None]) +f.canvas.print_figure('scatter.svg') + +f = plt.figure() +delta = 0.025 +x = y = np.arange(-3.0, 3.0, delta) +X, Y = np.meshgrid(x, y) +Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) +Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) +Z = Z2-Z1 # difference of Gaussians + +im = plt.imshow(Z, interpolation='bilinear', cmap=cm.gray, + origin='lower', extent=[-3,3,-3,3]) + +im.set_url('http://www.google.com') +f.canvas.print_figure('image.svg') + Modified: trunk/matplotlib/lib/matplotlib/artist.py =================================================================== --- trunk/matplotlib/lib/matplotlib/artist.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/artist.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -50,6 +50,7 @@ self._propobservers = {} # a dict from oids to funcs self.axes = None self._remove_method = None + self._url = None def remove(self): """ @@ -313,6 +314,18 @@ """ return self.figure is not None + def get_url(self): + """ + Returns the url + """ + return self._url + + def set_url(self, url): + """ + Sets the url for the artist + """ + self._url = url + def get_figure(self): """ Return the :class:`~matplotlib.figure.Figure` instance the Modified: trunk/matplotlib/lib/matplotlib/axes.py =================================================================== --- trunk/matplotlib/lib/matplotlib/axes.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/axes.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -5480,7 +5480,7 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, interpolation=None, alpha=1.0, vmin=None, vmax=None, origin=None, extent=None, shape=None, filternorm=1, - filterrad=4.0, imlim=None, resample=None, **kwargs): + filterrad=4.0, imlim=None, resample=None, url=None, **kwargs): """ call signature:: @@ -5601,6 +5601,7 @@ im.set_clim(vmin, vmax) else: im.autoscale_None() + im.set_url(url) xmin, xmax, ymin, ymax = im.get_extent() Modified: trunk/matplotlib/lib/matplotlib/backend_bases.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backend_bases.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/backend_bases.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -107,7 +107,7 @@ def draw_path_collection(self, master_transform, cliprect, clippath, clippath_trans, paths, all_transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, - linestyles, antialiaseds): + linestyles, antialiaseds, urls): """ Draws a collection of paths, selecting drawing properties from the lists *facecolors*, *edgecolors*, *linewidths*, @@ -136,7 +136,7 @@ for xo, yo, path_id, gc, rgbFace in self._iter_collection( path_ids, cliprect, clippath, clippath_trans, offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds): + linewidths, linestyles, antialiaseds, urls): path, transform = path_id transform = transforms.Affine2D(transform.get_matrix()).translate(xo, yo) self.draw_path(gc, path, transform, rgbFace) @@ -164,7 +164,7 @@ return self.draw_path_collection( master_transform, cliprect, clippath, clippath_trans, paths, [], offsets, offsetTrans, facecolors, edgecolors, - linewidths, [], [antialiased]) + linewidths, [], [antialiased], [None]) def _iter_collection_raw_paths(self, master_transform, paths, all_transforms): """ @@ -198,7 +198,7 @@ def _iter_collection(self, path_ids, cliprect, clippath, clippath_trans, offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds): + linewidths, linestyles, antialiaseds, urls): """ This is a helper method (along with :meth:`_iter_collection_raw_paths`) to make it easier to write @@ -232,6 +232,7 @@ Nlinewidths = len(linewidths) Nlinestyles = len(linestyles) Naa = len(antialiaseds) + Nurls = len(urls) if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0: return @@ -268,6 +269,9 @@ gc.set_alpha(rgbFace[-1]) rgbFace = rgbFace[:3] gc.set_antialiased(antialiaseds[i % Naa]) + + if Nurls: + gc.set_url(urls[i % Nurls]) yield xo, yo, path_id, gc, rgbFace @@ -433,6 +437,7 @@ self._linewidth = 1 self._rgb = (0.0, 0.0, 0.0) self._hatch = None + self._url = None def copy_properties(self, gc): 'Copy properties from gc to self' @@ -447,6 +452,7 @@ self._linewidth = gc._linewidth self._rgb = gc._rgb self._hatch = gc._hatch + self._url = gc._url def get_alpha(self): """ @@ -521,6 +527,12 @@ matlab format string, a html hex color string, or a rgb tuple """ return self._rgb + + def get_url(self): + """ + returns a url if one is set, None otherwise + """ + return self._url def set_alpha(self, alpha): """ @@ -621,6 +633,12 @@ raise ValueError('Unrecognized linestyle: %s' % style) self._linestyle = style self.set_dashes(offset, dashes) + + def set_url(self, url): + """ + Sets the url for links in compatible backends + """ + self._url = url def set_hatch(self, hatch): """ Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -531,7 +531,7 @@ def draw_path_collection(self, master_transform, cliprect, clippath, clippath_trans, paths, all_transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, - linestyles, antialiaseds): + linestyles, antialiaseds, urls): write = self._pswriter.write path_codes = [] @@ -548,7 +548,7 @@ for xo, yo, path_id, gc, rgbFace in self._iter_collection( path_codes, cliprect, clippath, clippath_trans, offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds): + linewidths, linestyles, antialiaseds, urls): ps = "%g %g %s" % (xo, yo, path_id) self._draw_ps(ps, gc, rgbFace) Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -67,9 +67,13 @@ else: clippath = 'clip-path="url(#%s)"' % clipid + if gc.get_url() is not None: + self._svgwriter.write('<a xlink:href="%s">' % gc.get_url()) style = self._get_style(gc, rgbFace) self._svgwriter.write ('<%s style="%s" %s %s/>\n' % ( element, style, clippath, details)) + if gc.get_url() is not None: + self._svgwriter.write('</a>') def _get_font(self, prop): key = hash(prop) @@ -224,7 +228,7 @@ def draw_path_collection(self, master_transform, cliprect, clippath, clippath_trans, paths, all_transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, - linestyles, antialiaseds): + linestyles, antialiaseds, urls): write = self._svgwriter.write path_codes = [] @@ -242,8 +246,11 @@ for xo, yo, path_id, gc, rgbFace in self._iter_collection( path_codes, cliprect, clippath, clippath_trans, offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds): + linewidths, linestyles, antialiaseds, urls): clipid = self._get_gc_clip_svg(gc) + url = gc.get_url() + if url is not None: + self._svgwriter.write('<a xlink:href="%s">' % url) if clipid is not None: write('<g clip-path="url(#%s)">' % clipid) details = 'xlink:href="#%s" x="%f" y="%f"' % (path_id, xo, self.height - yo) @@ -251,6 +258,8 @@ self._svgwriter.write ('<use style="%s" %s/>\n' % (style, details)) if clipid is not None: write('</g>') + if url is not None: + self._svgwriter.write('</a>') self._path_collection_id += 1 @@ -274,6 +283,9 @@ h,w = im.get_size_out() + url = getattr(im, '_url', None) + if url is not None: + self._svgwriter.write('<a xlink:href="%s">' % url) self._svgwriter.write ( '<image x="%f" y="%f" width="%f" height="%f" ' '%s xlink:href="'%(x/trans[0], (self.height-y)/trans[3]-h, w, h, transstr) @@ -298,6 +310,8 @@ self._svgwriter.write(filename) self._svgwriter.write('"/>\n') + if url is not None: + self._svgwriter.write('</a>') def draw_text(self, gc, x, y, s, prop, angle, ismath): if ismath: Modified: trunk/matplotlib/lib/matplotlib/collections.py =================================================================== --- trunk/matplotlib/lib/matplotlib/collections.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/collections.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -71,6 +71,7 @@ norm = None, # optional for ScalarMappable cmap = None, # ditto pickradius = 5.0, + urls = None, **kwargs ): """ @@ -86,6 +87,7 @@ self.set_linewidth(linewidths) self.set_linestyle(linestyles) self.set_antialiased(antialiaseds) + self.set_urls(urls) self._uniform_offsets = None self._offsets = np.array([], np.float_) @@ -203,7 +205,7 @@ paths, self.get_transforms(), offsets, transOffset, self.get_facecolor(), self.get_edgecolor(), self._linewidths, - self._linestyles, self._antialiaseds) + self._linestyles, self._antialiaseds, self._urls) renderer.close_group(self.__class__.__name__) def contains(self, mouseevent): @@ -227,6 +229,14 @@ def set_pickradius(self,pickradius): self.pickradius = 5 def get_pickradius(self): return self.pickradius + def set_urls(self, urls): + if urls is None: + self._urls = [None,] + else: + self._urls = urls + + def get_urls(self): return self._urls + def set_offsets(self, offsets): """ Set the offsets for the collection. *offsets* can be a scalar Modified: trunk/matplotlib/lib/matplotlib/image.py =================================================================== --- trunk/matplotlib/lib/matplotlib/image.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/image.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -88,13 +88,10 @@ self.set_filterrad(filterrad) self._filterrad = filterrad - - self.set_interpolation(interpolation) self.set_resample(resample) self.axes = ax - self._imcache = None self.update(kwargs) @@ -234,9 +231,11 @@ self.axes.get_yscale() != 'linear'): warnings.warn("Images are not supported on non-linear axes.") im = self.make_image(renderer.get_image_magnification()) + im._url = self.get_url() l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds + clippath, affine = self.get_transformed_clip_path_and_affine() renderer.draw_image(round(l), round(b), im, self.axes.bbox.frozen(), - *self.get_transformed_clip_path_and_affine()) + clippath, affine) def contains(self, mouseevent): """Test whether the mouse event occured within the image. Modified: trunk/matplotlib/lib/matplotlib/patches.py =================================================================== --- trunk/matplotlib/lib/matplotlib/patches.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/patches.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -278,6 +278,7 @@ gc.set_antialiased(self._antialiased) self._set_gc_clip(gc) gc.set_capstyle('projecting') + gc.set_url(self._url) if (not self.fill or self._facecolor is None or (cbook.is_string_like(self._facecolor) and self._facecolor.lower()=='none')): Modified: trunk/matplotlib/lib/matplotlib/text.py =================================================================== --- trunk/matplotlib/lib/matplotlib/text.py 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/lib/matplotlib/text.py 2008-11-07 14:52:04 UTC (rev 6372) @@ -464,6 +464,7 @@ gc = renderer.new_gc() gc.set_foreground(self._color) gc.set_alpha(self._alpha) + gc.set_url(self._url) if self.get_clip_on(): gc.set_clip_rectangle(self.clipbox) Modified: trunk/matplotlib/src/_backend_agg.cpp =================================================================== --- trunk/matplotlib/src/_backend_agg.cpp 2008-11-07 13:31:25 UTC (rev 6371) +++ trunk/matplotlib/src/_backend_agg.cpp 2008-11-07 14:52:04 UTC (rev 6372) @@ -1154,7 +1154,7 @@ Py::Object RendererAgg::draw_path_collection(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_path_collection"); - args.verify_length(13); + args.verify_length(14); //segments, trans, clipbox, colors, linewidths, antialiaseds agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); @@ -1170,7 +1170,8 @@ Py::SeqBase<Py::Float> linewidths = args[10]; Py::SeqBase<Py::Object> linestyles_obj = args[11]; Py::SeqBase<Py::Int> antialiaseds = args[12]; - + // We don't actually care about urls for Agg, so just ignore it. + // Py::SeqBase<Py::Object> urls = args[13]; PathListGenerator path_generator(paths); try { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |