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.
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins