Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add a "sketch" path filter #1329

Merged
merged 13 commits into from
@mdboom
Owner

Based on the mailing list thread "XKCD style graphs", this adds a sketchy line path filter to matplotlib.

This PR is not complete, but I thought I'd get something up early so we can hack on it together.

To play with this, set the rcParam['path.sketch'] to a tuple (scale, length, randomness), for example (1.0, 128., 16.).

          * *scale*: The amplitude of the wiggle perpendicular to the
            source line, in pixels.

          * *length*: The length of the wiggle along the line, in
             pixels (default 128.0)

          * *randomness*: The scale factor by which the length is
            shrunken or expanded (default 16.0)

This currently only works with the Agg and PDF backends, though it should be easy enough to add to other vector backends by following the same procedure as the PDF backend. The Mac OS-X backend will require more care, but should be possible as it's been added to path_cleanup.cpp.

Beyond this, it would be nice to add a convenience function xkcd_style, or some such, that thickens the lines, removes the north and east spines, possibly changes the font, etc.

@mdboom
Owner

Also, I invented my own wiggliness algorithm here based on a randomly progressing sine wave. I think Juergen Hasch's filtered noise approach looks better -- we should probably change this to do that.

@pwuertz
Collaborator

Haha, looks great :)
mpl-xkcd

@mdboom
Owner

That image seems to be a broken link, maybe? No worries -- just curious what you've decided to do with it.

@pwuertz
Collaborator

Oops, my bad. I better put it on github...

@WeatherGod
Collaborator
@mdboom
Owner

Very cool.

@dmcdougall
Collaborator

Amazing. Unfortunately, this won't make it in 1.2; it's not a bug fix.

:)

@dmcdougall
Collaborator

This is actually great for doing schematic 'big-picture' plots in a talk where a clean looking plot looks 'too scientific'.

lib/matplotlib/rcsetup.py
@@ -337,7 +337,16 @@ def validate_bbox(s):
return None
raise ValueError("bbox should be 'tight' or 'standard'")
-
+def validate_sketch(s):
+ if s == 'None' or s is None:
@NelleV Collaborator
NelleV added a note

s isn't a very explicit variable name. I'm not sure what the matplotlib's coding convention are regarding to this, but I think the code would gain in readibility with a longer variable name such as sketch.

@efiring Owner
efiring added a note

In cases like this, however, I think using a short variable name is fine. "def validate_sketch(sketch)" looks worse to my eye.

@NelleV Collaborator
NelleV added a note

Dunno... Reading the code as a "not matplotlib expert", it didn't seem obvious what s was. I have for rule not to use one letter variables as they are often confusing for beginners, and I want my code to be easily read and modified by anyone. Explicit is better than implicit.

@efiring Owner
efiring added a note

Your suggestion for a name, "sketch" would not help--it is no more descriptive of what "s" is than "s". "s" is not a sketch, it is an argument of unknown type being checked to see if it takes one of several valid forms.

@dmcdougall Collaborator

@NelleV @efiring I understand you both have your opinions. They are also both valid opinions. That being said, it seems as though the best course of action here is to agree to disagree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@WeatherGod
Collaborator

Probably should make it clear in any documentation that this parameter has to be set prior to any plotting calls, much like with setting font sizes and such.

@WeatherGod
Collaborator

sweet! add the plt.rc('path', sketch=(1.0, 128.0, 16.0)) towards the beginning of the animate_decay.py example for some fun!

http://youtu.be/PRRRvIRWk9M

@WeatherGod
Collaborator

And doing it to the subplots.py example is really neat!

http://youtu.be/jx4D2NGqkd0

And it also works for 3D plots as well:
Lorenz Sketch

@certik

I don't have time to test this now, but I just want to say that I like this a lot!

@glyg

That's really nice! Now fetch the Ipython crew so we have a whole xkcd python notebook

@WeatherGod
Collaborator

Ok, some bugs:
1. The GraphicsContextBase doesn't copy the ._sketch attribute when creating a copy of itself.
2. Artist.update_from() doesn't copy the ._sketch attribute (as well as some others...) (side note, some of the setters in Artist should probably be calling pchanged()).
3. Even after these changes, I still can not seem to get various collection objects to sketch, so somewhere in chain, the sketch params are not getting propagated.

@takluyver

@glyg: A notebook for you: view | download

(Not my doing - I just saw a link to it)

@jakevdp

Another notebook with some stabs in this direction (though done at the patch level in matplotlib):
http://nbviewer.ipython.org/url/jakevdp.github.com/downloads/notebooks/XKCD_plots.ipynb
Would it be possible for the sketch filter to automatically add a white background line so that there's the bit of space between line crossings?

@WeatherGod
Collaborator
@Nikratio

@WeatherGod: In your animation examples, even lines that are not being changed (e.g. x and y axis) are constantly wobbling around. Did you do that deliberately, or is that an unintended side effect? To me it looks very irritating.

@WeatherGod
Collaborator
@Tillsten

Any reason not to merge this?

@mdboom
Owner

The api for using this is horrible. It needs to have proper kwarg or rcparam access before its mergeable. I've sort of dropped the ball on this one.

@WeatherGod
Collaborator

Also note the bugs that I have pointed out earlier. I think this was a great and innovative proof-of-concept, but it is probably best to re-work this.

A thought I did have about a possible way to address @Nikratio 's concerns (and would enable proper unit-testing) is an ability to cache a seed number for a path. That way, the random seed would be re-used at each re-draw, resulting in the same sketch every time. This seed could be automatically determined and/or explicitly set.

@pelson
Collaborator

FWIW, if my memory serves me, I have a pretty good implementation of this which uses transforms only (with just a couple of bug fixes and if I remember correctly, a single monkey patch). The path filter stuff sounds very useful in this case, but it also sounds like a lot of work and I wonder how widely used it would really be?

@certik
@pelson
Collaborator

Thanks for the info Ondrej.

I think that a lot of people were waiting for this to get in.

Is it purely for XKCD style plots which show data in a less clinical, semantic form, or are there other usecases which make use of the path filter functionality?

@mdboom mdboom was assigned
@mdboom
Owner

Trying to revive this PR in time for 1.3.0. I've added a top-level function xkcd() which tweaks a bunch of rcParams to make this work more-or-less automatically in most cases. I've run this over all of the gallery examples and it does a reasonable job in most cases.

It would be nice to ship the "Humor Sans" font, but I can't figure out what the license on it is. Anyone know?

And for your amusement: http://matplotlib.org/xkcd/ :wink:

@mdboom
Owner

I should add: this PR now incorporates #1909.

@certik

This is awesome!

@mdboom
Owner

@pelson: to address your question about the path filter: I implemented it this way because if one were to use a transform, it would also have to interpolate along the straight line segments in order to apply the random walk. Since one wants the interpolation to happen at the scale of one pixel, regardless of the data transformation, it's rather hard to do that in numpy, since the size of the input and outputs are not the same and hard to estimate up front.

@takluyver

The only licensing information I can see is the sentence "He [the creator] invites you all to use the font and spread it all around for free..." The intention seems pretty clear, but I doubt that complies with the DFSG. You could contact the creator to ask for an explicit license. Though if it's assembled from letters taken from XKCD comics, then the CC-BY-NC license on XKCD poses a problem, as the non-commercial clause would be considered non-free.

@WeatherGod
Collaborator
doc/users/whats_new.rst
@@ -21,6 +21,18 @@ revision, see the :ref:`github-stats`.
new in matplotlib-1.3
=====================
+`xkcd`-style sketch plotting
+----------------------------
+
+To gives your plots a sense of authority that they may be missing,
@pelson Collaborator
pelson added a note

"gives" typo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
doc/users/whats_new.rst
@@ -21,6 +21,18 @@ revision, see the :ref:`github-stats`.
new in matplotlib-1.3
=====================
+`xkcd`-style sketch plotting
+----------------------------
+
+To gives your plots a sense of authority that they may be missing,
+Michael Droettboom (inspired by the work of many others in `issue
+#1329 <https://github.com/matplotlib/matplotlib/pull/1329>`_) has
@pelson Collaborator
pelson added a note

We have a role to make the linking easier (ghissue I think) - see doc/sphinxext/github.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
examples/showcase/xkcd.py
@@ -0,0 +1,40 @@
+from matplotlib import pyplot as plt
@pelson Collaborator
pelson added a note

It'd be nice to reference the XKCD chart that is being reproduced.

@pelson Collaborator
pelson added a note

Picky: its fewer characters (and more consistent?) to type import matplotlib.pyplot as plt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
doc/users/whats_new.rst
@@ -21,6 +21,18 @@ revision, see the :ref:`github-stats`.
new in matplotlib-1.3
=====================
+`xkcd`-style sketch plotting
+----------------------------
+
+To gives your plots a sense of authority that they may be missing,
+Michael Droettboom (inspired by the work of many others in `issue
+#1329 <https://github.com/matplotlib/matplotlib/pull/1329>`_) has
+added an `xkcd-style <xkcd.com>`_ sketch plotting mode. To use it,
@pelson Collaborator
pelson added a note

This link is local - so results in a 404.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
doc/users/whats_new.rst
@@ -21,6 +21,18 @@ revision, see the :ref:`github-stats`.
new in matplotlib-1.3
@pelson Collaborator
pelson added a note

Path effects on lines deserves to go in here too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
examples/pylab_examples/patheffect_demo.py
((11 lines not shown))
ax2 = plt.subplot(132)
arr = np.arange(25).reshape((5,5))
ax2.imshow(arr)
cntr = ax2.contour(arr, colors="k")
+
+ plt.setp(cntr.collections,
+ path_effects=[PathEffects.withStroke(linewidth=3,
+ foreground="w")])
+
@pelson Collaborator
pelson added a note

Picky: too many newlines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
examples/pylab_examples/to_numeric.py
@@ -30,5 +30,4 @@
X.shape = h, w, 3
im = Image.fromstring( "RGB", (w,h), s)
-im.show()
-
+# im.show()
@pelson Collaborator
pelson added a note

Intentional?

@mdboom Owner
mdboom added a note

Yes -- though I should probably remove the line altogether -- this causes ImageMagick's "display" utility to be called during the documentation build.

@pelson Collaborator
pelson added a note

Oh! That annoys me everytime and I've never got to the bottom of it! :smile:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/artist.py
@@ -456,6 +458,52 @@ def set_snap(self, snap):
"""
self._snap = snap
+ def get_sketch_params(self):
@pelson Collaborator
pelson added a note

I'd be keen to use numpydoc form here (https://github.com/matplotlib/matplotlib/wiki/Mep10)

@mdboom Owner
mdboom added a note

Ah, sure -- I didn't notice that. This PR predates MEP10, so I forgot to update it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/backend_bases.py
@@ -1003,6 +1005,42 @@ def get_hatch_path(self, density=6.0):
return None
return Path.hatch(self._hatch, density)
+ def get_sketch_params(self):
+ """
@pelson Collaborator
pelson added a note

Not an action: We should think about removing the duplicated docstings (duplicated in Artist) from here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/backend_bases.py
((5 lines not shown))
+ """
+ Returns the sketch parameters, which is a tuple with three elements:
+
+ * *scale*: The amplitude of the wiggle perpendicular to the
+ source line.
+
+ * *length*: The length of the wiggle along the line.
+
+ * *randomness*: The scale factor by which the length is
+ shrunken or expanded.
+
+ May return `None` if no sketch parameters were set.
+ """
+ return self._sketch
+
+ def set_sketch_params(self, scale=None, length=None, randomness=None):
@pelson Collaborator
pelson added a note

Technically I don't think these need to be keywords as they are always given (in the draw method). But I agree that keeping the signature consistent is useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/collections.py
@@ -258,11 +260,24 @@ def draw(self, renderer):
if self._hatch:
gc.set_hatch(self._hatch)
- renderer.draw_path_collection(
- gc, transform.frozen(), paths, self.get_transforms(),
- offsets, transOffset, self.get_facecolor(), self.get_edgecolor(),
- self._linewidths, self._linestyles, self._antialiaseds, self._urls,
- self._offset_position)
+ if self.get_sketch_params() is not None:
+ gc.set_sketch_params(*self.get_sketch_params())
+
+ if self.get_path_effects():
+ #from patheffects import PathEffectsRenderer
@pelson Collaborator
pelson added a note

Rogue comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/collections.py
((6 lines not shown))
- offsets, transOffset, self.get_facecolor(), self.get_edgecolor(),
- self._linewidths, self._linestyles, self._antialiaseds, self._urls,
- self._offset_position)
+ if self.get_sketch_params() is not None:
+ gc.set_sketch_params(*self.get_sketch_params())
+
+ if self.get_path_effects():
+ #from patheffects import PathEffectsRenderer
+ for pe in self.get_path_effects():
+ pe.draw_path_collection(renderer,
+ gc, transform.frozen(), paths, self.get_transforms(),
+ offsets, transOffset, self.get_facecolor(), self.get_edgecolor(),
+ self._linewidths, self._linestyles, self._antialiaseds, self._urls,
+ self._offset_position)
+ else:
+
@pelson Collaborator
pelson added a note

Unnecessary newline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/patheffects.py
@@ -22,6 +21,9 @@ def __init__(self):
"""
super(_Base, self).__init__()
+ def get_proxy_renderer(self, renderer):
+ pe_renderer = ProxyRenderer(self, renderer)
@pelson Collaborator
pelson added a note

Just return it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/patheffects.py
((31 lines not shown))
+ if isinstance(renderer, MixedModeRenderer):
+ renderer = renderer._renderer
+
+ path_ids = []
+ for path, transform in renderer._iter_collection_raw_paths(
+ master_transform, paths, all_transforms):
+ path_ids.append((path, transform))
+
+ for xo, yo, path_id, gc0, rgbFace in renderer._iter_collection(
+ gc, master_transform, all_transforms, path_ids, offsets,
+ offsetTrans, facecolors, edgecolors, linewidths, linestyles,
+ antialiaseds, urls, offset_position):
+ path, transform = path_id
+ transform = transforms.Affine2D(transform.get_matrix()).translate(xo, yo)
+ self.draw_path(renderer, gc0, path, transform, rgbFace)
+
@pelson Collaborator
pelson added a note

Rogue newline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/patheffects.py
@@ -51,6 +53,50 @@ def draw_path(self, renderer, gc, tpath, affine, rgbFace):
"""
renderer.draw_path(gc, tpath, affine, rgbFace)
+ def draw_path_collection(self, renderer,
@pelson Collaborator
pelson added a note

As far as I can work out, this is a copy and paste of RendererBase's method. Does this suggest that _Base should be subclassing RendererBase...

@leejjoon - thoughts?

@leejjoon Owner

Yes, this is a copy of RendererBases method. Well, _Base implements only a subset of RendererBase's methods, and I am not sure if it is a good idea to subclass RendereBase. We may consider some more refactoring though.

@mdboom Owner
mdboom added a note

@pelson -- inheriting from RendererBase might make some sense, but we can probably put that off for a later PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/patheffects.py
((33 lines not shown))
+ is an affine transform applied to the path.
+
+ This provides a fallback implementation of draw_markers that
+ makes multiple calls to :meth:`draw_path`. Some backends may
+ want to override this method in order to draw the marker only
+ once and reuse it multiple times.
+ """
+ for vertices, codes in path.iter_segments(trans, simplify=False):
+ if len(vertices):
+ x,y = vertices[-2:]
+ self.draw_path(renderer, gc, marker_path,
+ marker_trans + transforms.Affine2D().translate(x, y),
+ rgbFace)
+
+
+class ProxyRenderer(object):
@pelson Collaborator
pelson added a note

A docstring? Why does this exist?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/pyplot.py
@@ -255,6 +255,38 @@ def setp(*args, **kwargs):
draw_if_interactive()
return ret
+def xkcd():
+ """
+ Turns on `xkcd <xkcd.com>`_ sketch-style drawing mode. This will
@pelson Collaborator
pelson added a note

Link is a 404.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/pyplot.py
@@ -255,6 +255,38 @@ def setp(*args, **kwargs):
draw_if_interactive()
return ret
+def xkcd():
+ """
+ Turns on `xkcd <xkcd.com>`_ sketch-style drawing mode. This will
+ only have effect on things drawn after this function is called.
+
+ For best results, the "Humor Sans" font should be installed: it is
@pelson Collaborator
pelson added a note

How? Is there a link?

@mdboom Owner
mdboom added a note

It's hard to tell what the canonical URL for this font should be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/pyplot.py
@@ -255,6 +255,38 @@ def setp(*args, **kwargs):
draw_if_interactive()
return ret
+def xkcd():
@pelson Collaborator
pelson added a note

I'm not the biggest fan of globals - how about we make xkcd a context manager?

with plt.xkcd():
    plt.plot(range(10))
    plt.show()
@mdboom Owner
mdboom added a note

It's probably not a bad idea to optionally make it a context manager, but I don't think it should be required. The imposes a level of structure that's beyond the quick-and-dirty plotting scripts that most people write.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/rcsetup.py
@@ -740,9 +754,10 @@ def __call__(self, s):
'path.simplify': [True, validate_bool],
'path.simplify_threshold': [1.0 / 9.0, ValidateInterval(0.0, 1.0)],
'path.snap': [True, validate_bool],
+ 'path.sketch': [None, validate_sketch],
+ 'path.effects': [[], validate_any],
@pelson Collaborator
pelson added a note

I think this goes against most other rcParams - I have no idea what is a valid path.effect value...

@mdboom Owner
mdboom added a note

It's not really meant to be public -- just needed a place to store global state that would be resettable. Perhaps rename to _path.effects to make its private nature clearer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/tests/test_patheffects.py
@@ -0,0 +1,54 @@
+import numpy as np
@pelson Collaborator
pelson added a note

:+1: for adding a test. Needs to be added to lib/matplotlib/__init__.py though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
src/_path.cpp
@@ -1572,11 +1576,23 @@ class _path_module : public Py::ExtensionModule<_path_module>
bool return_curves = args[7].isTrue();
+ Py::Object sketch_params = args[8];
+ double sketch_scale = 0.0;
+ double sketch_length = 0.0;
+ double sketch_randomness = 0.0;
+ if (sketch_params.ptr() != Py_None) {
+ Py::Tuple sketch(sketch_params);
+ sketch_scale = Py::Float(sketch[0]);
@pelson Collaborator
pelson added a note
@mdboom Owner
mdboom added a note

Nope -- this is the PyCXX interface that will raise a C++ exception if it fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
src/path_converters.h
@@ -3,12 +3,14 @@
#ifndef __PATH_CONVERTERS_H__
@pelson Collaborator
pelson added a note

Technically shouldn't this file be called src/path_converters.cpp?

@mdboom Owner
mdboom added a note

Long story short -- templatized classes need to be implemented in a header so that the compiler can instantiate the templates. Once they are in object files (which a .cpp file would compile into) the template is static and can not be filled in by the compiler. You can see how it gets used from _backend_agg.cpp and path_cleanup.cpp for example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson
Collaborator

Mike: This is looking good. Please only add commits on top of c288df2 (rather than rebasing / modifying any history) and I would be happy to merge after some of the actions have been addressed/discussed.

I love the xkcd rendered version of the docs - very nicely done :smile:

@mdboom
Owner

@pelson: Thanks for the feedback. I believe I have addressed all of your comments. The context manager took some work because the font.* rcParams are "dynamic". I've changed this so that they only affect to-be-created text objects and not ones already created (this brings them in line with most other rcParams). That's a pretty significant change, but it surprisingly doesn't break any tests. Still something to take some caution about.

Out of curiosity, why the rebase warning?

@pelson
Collaborator

Out of curiosity, why the rebase warning?

I didn't want to re-read the whole lot again :smile:.

This all looks good to me. Very nice work :smile:

@pelson pelson merged commit 6b442b8 into from
@pelson pelson commented on the diff
src/_path.cpp
@@ -58,7 +58,7 @@ class _path_module : public Py::ExtensionModule<_path_module>
add_varargs_method("convert_path_to_polygons", &_path_module::convert_path_to_polygons,
"convert_path_to_polygons(path, trans, width, height)");
add_varargs_method("cleanup_path", &_path_module::cleanup_path,
- "cleanup_path(path, trans, remove_nans, clip, snap, simplify, curves)");
+ "cleanup_path(path, trans, remove_nans, clip, snap, simplify, curves, sketch_params)");
@pelson Collaborator
pelson added a note

@mdboom - I don't this this string is correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
src/_path.cpp
((15 lines not shown))
}
}
Py::Object
_path_module::cleanup_path(const Py::Tuple& args)
{
- args.verify_length(8);
+ args.verify_length(9);
@pelson Collaborator
pelson added a note

This is a backwards incompatible change to a public module function. Would you mind adding this to the doc/api/api_changes.rst?

@pelson Collaborator
pelson added a note

Actually, I've got a change incoming in which I will add the documentation.

@mdboom Owner
mdboom added a note

_path is a private module -- it should only be accessed publicly through path.py, so I don't think we need to consider this a public API change.

@pelson Collaborator
pelson added a note

Whilst I agree that it isn't defined in path, it is certainly part of path's namespace:

>>> import matplotlib.path
>>> print matplotlib.path.cleanup_path.__doc__
cleanup_path(path, trans, remove_nans, clip, snap, simplify, curves, sketch_params)
@mdboom Owner
mdboom added a note

Ah -- good point. That's unintentional... Path.iter_segments provides a much more Pythonic interface on top of the same functionality. I guess we should deprecate these C++ functions now and hide them completely in 1.4. I'll file a new issue for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson

Was this supposed to be 'font.stretch'? Relates to #2006

Owner

Indeed. Sorry about that -- didn't take long to find, though. Fix in de956ef

@leejjoon

@mdboom : is this change necessary? This causes an error with texmanager.py, which expects rcParams["font.family"] to be a string. And I guess there are user codes that will fail with this change.

Owner

Ah -- I missed that about texmanager. The other text handling handled this just fine without further changes. I think maybe we should try to fix texmanager to support a list (see #2012).

Here the use case that brought this about:

The xkcd function needs to change the font of all text that is created while it is in effect, and then go back to the previous settings afterward. If you set font.family to fantasy and change font.fantasy to Humor Sans, this doesn't work, because the lookup from a category name ('fantasy') to a concrete name is dynamic so when font.family is reverted, so is all of the text that was created in the xkcd context. I think this is the correct behavior for category names, as they are supposed to be dynamically updatable. So the only way to make the font setting on a text object permanent is to not use the category names but to use an actual concrete font name. And ideally that should be provided as a list so that we can account for users who don't have a particular font installed.

I'm not sure what user code would fail because of this change -- if it does, I think it's probably a real corner case. I know there is a lot of code that sets font.family as a single name, but that will continue to work. But I think it's much less common that user code will read this value.

@leejjoon

@mdboom: is there any reason you deleted this line? __init__ method takes an explicit path_effects keyword parameter (it is not captured by kwargs), so path_effects argument is now ignored if one directly create Text instance. And this seems to be the cause of #2032. Same apply for Patch and Line2D. Either we resurrect these lines, or we modify the __init__ methods so that path_effects is captured by kwargs. Maybe the latter is what you meant?

@mdboom mdboom deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 13, 2013
  1. @leejjoon @mdboom

    implement path_effects for Line2D objects

    leejjoon authored mdboom committed
  2. @leejjoon @mdboom
  3. @leejjoon @mdboom

    initial implementation of patheffect for collections

    leejjoon authored mdboom committed
  4. @leejjoon @mdboom

    add tests for patheffects

    leejjoon authored mdboom committed
  5. @leejjoon @mdboom

    patheffect.draw_path_collection work with mixed renderer.

    leejjoon authored mdboom committed
  6. @mdboom

    Add a sketch path filter.

    mdboom authored
  7. @mdboom

    Fix oops in _path.cpp

    mdboom authored
  8. @mdboom

    Add xkcd() function to set up a number of parameters to create plots …

    mdboom authored
    …that look like xkcd. Add an example, and a what's new. Expose path effects as an rcParam so that they can be set globally.
Commits on May 14, 2013
  1. @mdboom

    Credit basis for plots

    mdboom authored
  2. @mdboom
  3. @mdboom
  4. @mdboom
  5. @mdboom
Something went wrong with that request. Please try again.