1
- Devs, feel free to edit this document. This is meant to be a guide to
2
- developers on the mpl coding practices and standards
1
+ = The matplotlib developer's guide =
3
2
3
+ This is meant to be a guide to developers on the mpl coding practices
4
+ and standards. Please edit and extend this document.
4
5
5
- == Committing Changes ==
6
+ == Committing changes ==
6
7
7
8
When committing changes to matplotlib, there are a few things to bear
8
9
in mind.
9
10
10
- * if your changes are nontrivial , please make an entry in the
11
+ * if your changes are non-trivial , please make an entry in the
11
12
CHANGELOG
12
13
13
14
* if you change the API, please document it in API_CHANGES, and
14
- consider posing to mpl-devel
15
+ consider posting to mpl-devel
15
16
16
17
* Are your changes python2.3 compatible? We are still trying to
17
18
support 2.3, so avoid 2.4 only features like decorators until we
@@ -30,7 +31,7 @@ in mind.
30
31
unit/memleak_hawaii.py?
31
32
32
33
33
- == Naming conventions ==
34
+ == Naming and spacing conventions ==
34
35
35
36
functions and class methods : lower or lower_underscore_separated
36
37
@@ -40,28 +41,72 @@ in mind.
40
41
41
42
Personally, I prefer the shortest names that are still readable.
42
43
43
- == kwargs processing ==
44
+ Also, use an editor that does not put tabs in files. Four spaces
45
+ should be used for indentation everywhere and if there is a file with
46
+ tabs or more or less spaces it is a bug -- please fix it.
44
47
45
- Matplotlib makes extensive use of **kwargs for pass through
46
- customizations from one function to another, eg the pylab plot ->
47
- Axes.plot pass through. As a general rule, the use of **kwargs should
48
- be reserved for pass-through keyword arguments, eg
49
-
50
- def somefunc(x, k1='something', **kwargs):
51
- # do some thing with x, k1
52
- return some_other_func(..., **kwargs)
53
-
54
- If I intend for all the keyword args to be used in somefunc alone, I
55
- just use the key/value keyword args in the function definition rather
56
- than the **kwargs idiom. In some cases I want to consume some keys
57
- and pass through the others, in which case I pop the ones I want to
58
- use locally and pass on the rest, eg I pop scalex and scaley in
59
- Axes.plot and assume the rest are Line2D keyword arguments. Whenever
60
- you mutate a kwargs dictionary (eg by popping it), you must first copy
61
- it since the user may be explitly passing in a dictionary which is
62
- used across many function calls. As an example of a copy, pop,
63
- passthrough usage, see Axes.plot:
48
+ == Licenses ==
49
+
50
+ matplotlib only uses BSD compatible code. If you bring in code from
51
+ another project make sure it has a PSF, BSD, MIT or compatible
52
+ license. If not, you may consider contacting the author and asking
53
+ them to relicense it. GPL and LGPL code are not acceptible in the
54
+ main code base, though we are considering an alternative way of
55
+ distributing L/GPL code through an separate channel, possibly a
56
+ toolkit. If you include code, make sure you include a copy of that
57
+ code's license in the license directory if the code's license requires
58
+ you to distribute the license with it.
59
+
60
+
61
+ == Keyword argument processing ==
64
62
63
+ Matplotlib makes extensive use of **kwargs for pass through
64
+ customizations from one function to another. A typical example is in
65
+ pylab.text, The definition of the pylab text function is a simple
66
+ pass-through to axes.Axes.text
67
+
68
+ # in pylab.py
69
+ def text(*args, **kwargs):
70
+ ret = gca().text(*args, **kwargs)
71
+ draw_if_interactive()
72
+ return ret
73
+
74
+
75
+ axes.Axes.text in simplified form looks like this, ie it just passes
76
+ them on to text.Text.__init__
77
+ # in axes.py
78
+ def text(self, x, y, s, fontdict=None, withdash=False, **kwargs):
79
+ t = Text(x=x, y=y, text=s, **kwargs)
80
+
81
+
82
+ and Text.__init__ (again with liberties for illustration) just passes
83
+ them on to the artist.Artist.update method
84
+
85
+ # in text.py
86
+ def __init__(self, x=0, y=0, text='', **kwargs):
87
+ Artist.__init__(self)
88
+ self.update(kwargs)
89
+
90
+ 'update' does the work looking for methods named like 'set_property'
91
+ if 'property' is a keyword argument. Ie, noone looks at the keywords,
92
+ they just get passed through the API to the artist constructor which
93
+ looks for suitably named methods and calls them with the value.
94
+
95
+ As a general rule, the use of **kwargs should be reserved for
96
+ pass-through keyword arguments, as in the exmaple above. If I intend
97
+ for all the keyword args to be used in some function and not passed
98
+ on, I just use the key/value keyword args in the function definition
99
+ rather than the **kwargs idiom.
100
+
101
+ In some cases I want to consume some keys and pass through the others,
102
+ in which case I pop the ones I want to use locally and pass on the
103
+ rest, eg I pop scalex and scaley in Axes.plot and assume the rest are
104
+ Line2D keyword arguments. Whenever you mutate a kwargs dictionary (eg
105
+ by popping it), you must first copy it since the user may be explitly
106
+ passing in a dictionary which is used across many function calls. As
107
+ an example of a copy, pop, passthrough usage, see Axes.plot:
108
+
109
+ # in axes.py
65
110
def plot(self, *args, **kwargs):
66
111
kwargs = kwargs.copy()
67
112
scalex = popd(kwargs, 'scalex', True)
@@ -82,6 +127,7 @@ non-keyword args. In this case, python will not allow you to use
82
127
named keyword args after the *args usage, so you will be forced to use
83
128
**kwargs. An example is matplotlib.contour.ContourLabeler.clabel
84
129
130
+ # in contour.py
85
131
def clabel(self, *args, **kwargs):
86
132
fontsize = kwargs.get('fontsize', None)
87
133
inline = kwargs.get('inline', 1)
@@ -93,18 +139,17 @@ named keyword args after the *args usage, so you will be forced to use
93
139
elif len(args) == 1:
94
140
...etc...
95
141
96
-
97
-
98
- == class documentation ==
142
+ == Class documentation ==
99
143
100
144
matplotlib uses artist instrospection of docstrings to support
101
145
properties. All properties that you want to support through setp and
102
146
getp should have a set_property and get_property method in the Artist
103
- class. Yes this is not ideal given python properties or enthought
147
+ class. Yes, this is not ideal given python properties or enthought
104
148
traits, but it is a historical legacy for now. The setter methods use
105
149
the docstring with the ACCEPTS token to indicate the type of argument
106
150
the method accepts. Eg in matplotlib.lines.Line2D
107
151
152
+ # in lines.py
108
153
def set_linestyle(self, linestyle):
109
154
"""
110
155
Set the linestyle of the line
@@ -130,13 +175,15 @@ I have added a matplotlib.artist.kwdocd to faciliate this. This
130
175
combines python string interpolation in the docstring with the
131
176
matplotlib artist introspection facility that underlies setp and getp.
132
177
The kwdocd is a single dictionary that maps class name to a docstring
133
- of kwargs. Here is an example at the bottom of matplotlib.lines
178
+ of kwargs. Here is an example from matplotlib.lines
134
179
135
- artist.kwdocd['Line2D'] = '\n'.join(artist.ArtistInspector(Line2D).pprint_setters(leadingspace=12))
180
+ # in lines.py
181
+ artist.kwdocd['Line2D'] = '\n'.join(artist.ArtistInspector(Line2D).pprint_setters(leadingspace=12))
136
182
137
183
Then in any function accepting Line2D passthrough kwargs, eg
138
184
matplotlib.axes.Axes.plot
139
185
186
+ # in axes.py
140
187
def plot(self, *args, **kwargs):
141
188
"""
142
189
Some stuff omitted
@@ -152,9 +199,9 @@ matplotlib.axes.Axes.plot
152
199
pass
153
200
plot.__doc__ = plot.__doc__ % artist.kwdocd
154
201
155
- Note there is a problem for Artist __init__ methods, eg
156
- Patch.__init__ which supports Patch kwargs, since the artist inspector
157
- cannot work until the class is fully defined and we can't modify the
202
+ Note there is a problem for Artist __init__ methods, eg Patch.__init__
203
+ which supports Patch kwargs, since the artist inspector cannot work
204
+ until the class is fully defined and we can't modify the
158
205
Patch.__init__.__doc__ docstring outside the class definition. I have
159
206
made some manual hacks in this case which violates the "single entry
160
207
point" requirement above; hopefully we'll find a more elegant solution
0 commit comments