Added a find_all method to the RcParams dictionary. #1861

Merged
merged 3 commits into from Apr 18, 2013

Conversation

Projects
None yet
6 participants
Member

pelson commented Mar 27, 2013

I find I want to search for RcParams by keyword quite frequently.

Now you can do:

>>> import matplotlib
>>> print '\n'.join(matplotlib.rcParams.find_all('font').keys())
font.cursive
font.family
font.fantasy
font.monospace
font.sans-serif
font.serif
font.size
font.stretch
font.style
font.variant
font.weight
legend.fontsize
mathtext.fontset
pdf.fonttype
pdf.use14corefonts
pgf.rcfonts
ps.fonttype
svg.fonttype

Owner

mdboom commented Mar 27, 2013

Cool feature. 👍 from me.

Owner

efiring commented Mar 27, 2013

@pelson, while you are at it, you might add a method (maybe with a pyplot function), perhaps "show_all(...)", which would use this selection to return a nicely formatted string with the keys and their current values.

@dmcdougall dmcdougall and 1 other commented on an outdated diff Mar 27, 2013

lib/matplotlib/__init__.py
@@ -751,6 +751,22 @@ def values(self):
Return values in order of sorted keys.
"""
return [self[k] for k in self.iterkeys()]
+
+ def find_all(self, key_contains):
+ """
+ Return the subset of this RcParams dictionary for which the given
+ ``key_contains`` string is found somewhere in the key.
+
+ .. note::
+
+ Changes to the returned dictionary are *not* propagated to
+ the parent RcParams dictionary.
+
+ """
+ return RcParams((key, value)
+ for key, value in self.items()
+ if key_contains in key)
@dmcdougall

dmcdougall Mar 27, 2013

Member

Should this be key_contains.lower(), and the doc string updated to make it clear the search is case insensitive? Here I am assuming all the rcparams are lower case, so correct me if I'm wrong.

@pelson

pelson Mar 28, 2013

Member

I've not done this as I've gone for the regular expression route. I didn't want to make it too magic, and the user can always lower the string they are passing themselves if they are doing it programatically...

Let me know if you really want this feature.

Member

dmcdougall commented Mar 27, 2013

This is beautiful. This will save me from having to search through the matplotlibrc file by hand.

@pelson, while you are at it, you might add a method (maybe with a pyplot function), perhaps "show_all(...)", which would use this selection to return a nicely formatted string with the keys and their current values.

Also, in addition to @efiring's suggestion, might it be worth to have a search for pyplot functions, too? Note, this is just a thought that should be in a separate PR if a consensus is reached.

Member

pelson commented Mar 28, 2013

@pelson, while you are at it, you might add a method (maybe with a pyplot function), perhaps "show_all(...)", which would use this selection to return a nicely formatted string with the keys and their current values.

Personally I wouldn't use the pyplot function and I'm a hesitant to add more stuff there if possible, but I'd certainly make use of a __repr__ to RcParams which wrapped http://docs.python.org/2/library/pprint.html#pprint.pprint

Something like:

>>> print matplotlib.rcParams.find_all('font')
RcParams({
         'font.size': ...,
         })

I'd also be happy to add a __str__ and __repr__.

Member

pelson commented Mar 28, 2013

Ok, I've added some bells and whistles to this PR. I expect the new functionality means that the pyplot function is no longer required, but shout if you disagree @efiring.

Cheers,

@mdboom mdboom and 1 other commented on an outdated diff Mar 28, 2013

lib/matplotlib/__init__.py
@@ -750,7 +761,25 @@ def values(self):
"""
Return values in order of sorted keys.
"""
- return [self[k] for k in self.iterkeys()]
+ return [self[k] for k in self.keys()]
+
+ def find_all(self, pattern):
+ """
+ Return the subset of this RcParams dictionary for which the given
+ ``pattern`` string is found, by :func:`re.search`, somewhere in the key.
@mdboom

mdboom Mar 28, 2013

Owner

I find this a little bit unclear.

Maybe just say "pattern is a Python regular expression".

@pelson

pelson Mar 28, 2013

Member

Thanks @mdboom. I'll change to:

Return the subset of this RcParams dictionary whose keys match,
using :func:`re.search`, the given "pattern".

I'm happy to iterate on this though if you have further improvements?

Member

pelson commented Apr 12, 2013

Ok. I think that is all the actions taken care of. I think this is good to go.

Owner

mdboom commented Apr 12, 2013

Needs a rebase.

Member

pelson commented Apr 12, 2013

Thanks @mdboom - done.

Member

ivanov commented Apr 12, 2013

my initial reaction is against using regular expressions:

to quote @yesthatjwz:

Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.

I can't think of a time when I will want the full power of a regular expression for searching the rcParams, but I can imagine wanting to find all instances of something with a period in the name, and be annoyed every time that I have to escape it.

Edit:
The name find_all makes me think of string's find, so I intuitively just want it to do substring searching. But there are some advantages to use regex, in that it allows us to specify something like '^font' for only keys starting with font.

I have code like this for grabbing portions of rcParam keys so I can set them, or do something else with them:

In [10]: [k for k in matplotlib.rcParams if 'font' in k]
Out[10]: 
['font.fantasy',
 'svg.fonttype',
 'font.cursive',
 'mathtext.fontset',
 'font.serif',
 'font.stretch',
 'font.size',
 'ps.fonttype',
 'legend.fontsize',
 'font.variant',
 'pdf.fonttype',
 'pdf.use14corefonts',
 'font.style',
 'font.family',
 'pgf.rcfonts',
 'font.sans-serif',
 'font.weight',
 'font.monospace']

In [11]: [k for k in matplotlib.rcParams if k.startswith('font')]
Out[11]: 
['font.fantasy',
 'font.cursive',
 'font.serif',
 'font.stretch',
 'font.size',
 'font.variant',
 'font.style',
 'font.family',
 'font.sans-serif',
 'font.weight',
 'font.monospace']

@ivanov ivanov and 1 other commented on an outdated diff Apr 12, 2013

lib/matplotlib/__init__.py
@@ -738,6 +738,17 @@ def __getitem__(self, key):
key = alt
return dict.__getitem__(self, key)
+ def __repr__(self):
+ import pprint
+ class_name = self.__class__.__name__
+ indent = len(class_name) + 1
+ repr_split = pprint.pformat(dict(self), indent=1, width=80 - indent).split('\n')
+ repr_indented = ('\n' + ' ' * indent).join(repr_split)
+ return '{}({})'.format(class_name, repr_indented)
@ivanov

ivanov Apr 12, 2013

Member

this style of formatting is not supported in python2.6

In [5]: '{}({})'.format('sorry', '>= 2.7 only')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-b84304fedd68> in <module>()
----> 1 '{}({})'.format('sorry', '>= 2.7 only')

ValueError: zero length field name in format
@pelson

pelson Apr 12, 2013

Member

Thanks @ivanov - travis spotted this one too - I'm always making this mistake! Bring on ending support for 2.6 😉

@ivanov

ivanov Apr 12, 2013

Member

Phil Elson, on 2013-04-12 12:32, wrote:

Thanks @ivanov - travis spotted this one too -

Good thing Travis spotted it as well, though sometimes it's easy
to ignore that person, since, as we've seen in the past, Travis
isn't always very reliable ;)

Bring on ending support for 2.6 😉

You won't hear complaints from me about it. Machines where I'm
still running 2.6 are not ones I will be updating matplotlib.

@ivanov ivanov commented on an outdated diff Apr 12, 2013

lib/matplotlib/__init__.py
@@ -738,6 +738,17 @@ def __getitem__(self, key):
key = alt
return dict.__getitem__(self, key)
+ def __repr__(self):
+ import pprint
+ class_name = self.__class__.__name__
+ indent = len(class_name) + 1
+ repr_split = pprint.pformat(dict(self), indent=1, width=80 - indent).split('\n')
+ repr_indented = ('\n' + ' ' * indent).join(repr_split)
+ return '{}({})'.format(class_name, repr_indented)
+
+ def __str__(self):
+ return '\n'.join('{}: {}'.format(k, v) for k, v in sorted(self.items()))
@ivanov

ivanov Apr 12, 2013

Member

same as above (>= 2.7 only)

Member

WeatherGod commented Apr 12, 2013

Agreed. I would be happy if we could just simply use the globbing syntax.
I use the glob module all the time to give me basic pattern checking on
list of values (it isn't just for files!)

Member

pelson commented Apr 12, 2013

Agreed. I would be happy if we could just simply use the globbing syntax.

I'm not wed to any particular form. I can see arguments for and against all 3 of the proposed solutions (in, re.search and fnmatch.fnmatch). I only submitted this PR as I was sick of typing the (1 line) list comprehension to filter rcParams 😄 . To be honest, the most frequent use case for me would be to do rcParams.find_all('font'), I don't need re/glob searching etc. etc.. Obviously, no matter which we choose (and I really do not mind which that is), the option of writing your own comprehension is still fine if you have a more complex case that is not handled.

Member

ivanov commented Apr 12, 2013

I'm not wed to any particular form.

well, this bikeshedding won't be very fun if you're always going to be so agreeable, Phil! ;)

I trust your decision, and do not feel strongly either way. My initial reaction was a worry that I'd have to write "font" or something like that, but that's not the case with any of the proposals on the table.

So just that formatting thing needs to be fixed, and if you want to switch the way the matching works, that too, but it's fine as is, too. And then it's 🍰 + 🍴 for you @pelson

Member

pelson commented Apr 18, 2013

My initial reaction was a worry that I'd have to write "font" or something like that, but that's not the case with any of the proposals on the table.

Sadly, this is the case with the globbing syntax, otherwise I would have gone with @WeatherGod's nice suggestion.
Therefore I have stuck with the regex approach (with the understanding that it will annoy @ivanov when searching for keys containing periods 😒).

And then it's 🍰 + 🍴 for you @pelson

Nomnom... anyone care to merge 😄

@ivanov ivanov added a commit that referenced this pull request Apr 18, 2013

@ivanov ivanov Merge pull request #1861 from pelson/find_all_rcs
Added a find_all method to the RcParams dictionary.
bc510f3

@ivanov ivanov merged commit bc510f3 into matplotlib:master Apr 18, 2013

1 check passed

default The Travis build passed
Details
Member

ivanov commented Apr 18, 2013

with the understanding that it will annoy @ivanov when searching for keys containing periods

Oh, I'll get over it... merged, thanks, @pelson. Now have some ☕️ with your 🍰

@dmcdougall dmcdougall commented on the diff Jun 16, 2013

lib/matplotlib/__init__.py
@@ -706,8 +706,8 @@ class RcParams(dict):
:mod:`matplotlib.rcsetup`
"""
- validate = dict([ (key, converter) for key, (default, converter) in \
- defaultParams.iteritems() ])
+ validate = dict((key, converter) for key, (default, converter) in \
@dmcdougall

dmcdougall Jun 16, 2013

Member

I know this has been merged already, but I only just saw this trailing backslash.

@mdboom

mdboom Jun 17, 2013

Owner

Thanks for finding. I have just fixed directly on 1.3.x in `
207469f

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