Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying dictionary argument with dict() or braces matters in set_bbox

In matplotlib home page, there is a link to a tutorial by Nicolas Rougier. In the section of the tutorial entitled "Devil is in the details", the script:

http://www.loria.fr/~rougier/teaching/matplotlib/scripts/exercice_10.py

produces the figure displayed on the web page. Line 48 of the script is:

label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.65 ))

If we replace this line by:

label.set_bbox({"facecolor": "white", "edgecolor": "None","alpha":0.65})

then the edgecolor request is not taken into account. I would have thought that the two statements above were equivalent. I have asked the author of the tutorial, Nicolas Rougier, about this and he is surprised too. Is this a bug of Matplotlib ?

like image 765
Lionel GUEZ Avatar asked Apr 19 '13 15:04

Lionel GUEZ


1 Answers

You can easily determine if the two dicts are equivalent:

dict(facecolor='white', edgecolor='None', alpha=0.65 ) == \
    {"facecolor": "white", "edgecolor": "None", "alpha":0.65}

This is True.

However, if you type these literals into a Python interpreter, the resulting dictionary reprs have the values in different orders.

{'alpha': 0.65000000000000002, 'facecolor': 'white', 'edgecolor': 'None'}
{'edgecolor': 'None', 'facecolor': 'white', 'alpha': 0.65000000000000002}

This may vary based on the version of Python you use, and I believe that in newer versions of Python it varies from run to run of the interpreter; the hash seeding is randomized to prevent dictionaries from being constructed with maliciously poor performance. The above output is from Python 2.6.6 (Win32).

Python dicts are unordered, by which we mean that you can't rely on the order. However, when iterating over a dictionary, elements have to come out in some order. This order is influenced by the order in which the items are inserted, and though it isn't obvious, they are inserted in two different orders in these two dictionaries: the dict() constructor gets a dictionary of keywords, which it then inserts into the constructed dict, so in effect the elements of the first dict are inserted twice! First in the order you specify them, then in whatever order they ended up in the dictionary constructed in that step.

Hypothesis: There is something in matplotlib (or the version of Python you're using) that cares what order dictionary items come out in. In fact, since the second one has its edgecolor key first, perhaps it's skipping the first value, or maybe one of the later values has a side effect that causes it to override edgecolor (e.g. maybe facecolor also sets edgecolor to make sure there aren't gaps between faces). This might reasonably be called a bug since the behavior can differ based on the order in which the keywords happen to come out of the dictionary.

like image 152
kindall Avatar answered Oct 04 '22 00:10

kindall