|
| 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 |
| 3 | + |
| 4 | + |
| 5 | +== Committing Changes == |
| 6 | + |
| 7 | +When committing changes to matplotlib, there are a few things to bear |
| 8 | +in mind. |
| 9 | + |
| 10 | + * if your changes are nontrivial, please make an entry in the |
| 11 | + CHANGELOG |
| 12 | + |
| 13 | + * if you change the API, please document it in API_CHANGES, and |
| 14 | + consider posing to mpl-devel |
| 15 | + |
| 16 | + * Are your changes python2.3 compatible? We are still trying to |
| 17 | + support 2.3, so avoid 2.4 only features like decorators until we |
| 18 | + remove 2.3 support |
| 19 | + |
| 20 | + * Are your changes Numeric, numarray and numpy compatible? Try |
| 21 | + running simple_plot.py or image_demo.py with --Numeric, --numarray |
| 22 | + and --numpy (Note, someone should add examples to |
| 23 | + backend_driver.py which explicitly require numpy, numarray and |
| 24 | + Numeric so we can automatically catch these |
| 25 | + |
| 26 | + * Can you pass examples/backend_driver.py . This is our poor man's |
| 27 | + unit test |
| 28 | + |
| 29 | + * If you have altered extension code, do you pass |
| 30 | + unit/memleak_hawaii.py |
| 31 | + |
| 32 | + |
| 33 | +== Naming conventions == |
| 34 | + |
| 35 | + functions and class methods : undercase_separated_lower |
| 36 | + |
| 37 | + attributes and variables : lower or lowerUpper |
| 38 | + |
| 39 | + classes : Upper or MixedCase |
| 40 | + |
| 41 | +Personally, I prefer the shortest names that are still readable. |
| 42 | + |
| 43 | +== kwargs processing == |
| 44 | + |
| 45 | +Matplotlib makes extensive use of kwargs so 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 kwargs to be used in somefunc alone, I just |
| 55 | +use the key/value keyword args in the function definition rather than |
| 56 | +the **kwargs idiom. In some cases I want to consume some keys and |
| 57 | +pass through the others, in which case I pop the ones I want to use |
| 58 | +locally and pass on the rest, eg I pop scalex and scaley in Axes.plot |
| 59 | +and assume the rest are Line2D args. Whenever you mutate a kwargs |
| 60 | +dictionary, you must first copy it since the user may be explitly |
| 61 | +passing in a dictionary which is used across many function calls, eg, |
| 62 | +in Axes.plot |
| 63 | + |
| 64 | + kwargs = kwargs.copy() |
| 65 | + scalex = popd(kwargs, 'scalex', True) |
| 66 | + scaley = popd(kwargs, 'scaley', True) |
| 67 | + if not self._hold: self.cla() |
| 68 | + lines = [] |
| 69 | + for line in self._get_lines(*args, **kwargs): |
| 70 | + self.add_line(line) |
| 71 | + lines.append(line) |
| 72 | + |
| 73 | +popd is a matplotlib.cbook function. |
| 74 | + |
| 75 | +Note there is a use case when kwargs are meant to be used locally in |
| 76 | +the function, but you still need the **kwargs idiom. That is when you |
| 77 | +want to use *args to allow variable numbers of non keyword args. In |
| 78 | +this case, python will not allow you to use named keyword args after |
| 79 | +the *args usage, so you will be forces to use kwargs. An example is |
| 80 | +matplotlib.contour.ContourLabeler.clabel |
| 81 | + |
| 82 | + def clabel(self, *args, **kwargs): |
| 83 | + fontsize = kwargs.get('fontsize', None) |
| 84 | + inline = kwargs.get('inline', 1) |
| 85 | + self.fmt = kwargs.get('fmt', '%1.3f') |
| 86 | + colors = kwargs.get('colors', None) |
| 87 | + if len(args) == 0: |
| 88 | + levels = self.levels |
| 89 | + indices = range(len(self.levels)) |
| 90 | + elif len(args) == 1: |
| 91 | + ...etc... |
| 92 | + |
| 93 | + |
| 94 | + |
| 95 | +== class documentation == |
| 96 | + |
| 97 | +matplotlib uses artist instrospection of docstrings to support |
| 98 | +properties. All properties that you want to support through setp and |
| 99 | +getp should have a set_property and get_property method in the Artist |
| 100 | +class. Yes this is not ideal given python properties or enthought |
| 101 | +traits but it is a historical legacy for now. The setter methods use |
| 102 | +the docstring with the ACCEPTS token to indicate the type of argument |
| 103 | +the method accepts. Eg in matplotlib.lines.Line2D |
| 104 | + |
| 105 | + def set_linestyle(self, linestyle): |
| 106 | + """ |
| 107 | + Set the linestyle of the line |
| 108 | + |
| 109 | + ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'None' | ' ' | '' ] |
| 110 | + """ |
| 111 | + |
| 112 | + |
| 113 | +Since matplotlib uses a lot of pass through kwargs, eg in every |
| 114 | +function that creates a line (plot, semilogx, semilogy, etc...), it |
| 115 | +can be difficult for the new user to know which kwargs are supported. |
| 116 | +I have developed a docstring interpolation scheme to support |
| 117 | +documentation of every function that takes a **kwargs. The |
| 118 | +requirements are: |
| 119 | + |
| 120 | + 1) single point of configuration so changes to the properties don't |
| 121 | + require multiple docstring edits |
| 122 | + |
| 123 | + 2) as automated as possible so that as setters and getters change |
| 124 | + the docs are updated automagically. |
| 125 | + |
| 126 | +I have added a matplotlib.artist.kwdocd to faciliate this. This |
| 127 | +combines python string interpolation in the docstring with the |
| 128 | +matplotlib artist introspection facility that underlies setp and getp. |
| 129 | +The kwdocd is a single dictionary that maps class name to a docstring |
| 130 | +of kwargs. Here is an example at the bottom of matplotlib.lines |
| 131 | + |
| 132 | +artist.kwdocd['Line2D'] = '\n'.join(artist.ArtistInspector(Line2D).pprint_setters(leadingspace=12)) |
| 133 | + |
| 134 | +Then in any function accepting Line2D passthrough kwargs, eg |
| 135 | +matplotlib.axes.Axes.plot |
| 136 | + |
| 137 | + def plot(self, *args, **kwargs): |
| 138 | + """ |
| 139 | + Some stuff omitted |
| 140 | + |
| 141 | + The kwargs are Line2D properties: |
| 142 | +%(Line2D)s |
| 143 | + |
| 144 | + kwargs scalex and scaley, if defined, are passed on |
| 145 | + to autoscale_view to determine whether the x and y axes are |
| 146 | + autoscaled; default True. See Axes.autoscale_view for more |
| 147 | + information |
| 148 | + """ |
| 149 | + pass |
| 150 | + plot.__doc__ = plot.__doc__ % artist.kwdocd |
| 151 | + |
| 152 | + |
0 commit comments