|
| 1 | + |
| 2 | +MEP25: Serialization |
| 3 | +==================== |
| 4 | +.. contents:: |
| 5 | + :local: |
| 6 | + |
| 7 | +Status |
| 8 | +------ |
| 9 | + |
| 10 | +**Discussion** |
| 11 | + |
| 12 | +Branches and Pull requests |
| 13 | +-------------------------- |
| 14 | + |
| 15 | +* development branches: |
| 16 | + |
| 17 | +* related pull requests: |
| 18 | + |
| 19 | +Abstract |
| 20 | +-------- |
| 21 | + |
| 22 | +This MEP aims at adding a serializable ``Controller`` objects to act |
| 23 | +as an ``Artist`` managers. Users would then communicate changes to an |
| 24 | +``Artist`` via a ``Controller``. In this way, functionality of the |
| 25 | +``Controller`` objects may be added incrementally since each |
| 26 | +``Artist`` is still responsible for drawing everything. The goal is to |
| 27 | +create an API that is usable both by graphing libraries requiring |
| 28 | +high-level descriptions of figures and libraries requiring low-level |
| 29 | +interpretations. |
| 30 | + |
| 31 | +Detailed description |
| 32 | +-------------------- |
| 33 | + |
| 34 | +Matplotlib is a core plotting engine with an API that many users |
| 35 | +already understand. It's difficult/impossible for other graphing |
| 36 | +libraries to (1) get a complete figure description, (2) output raw |
| 37 | +data from the figure object as the user has provided it, (3) |
| 38 | +understand the semantics of the figure objects without heuristics, |
| 39 | +and (4) give matplotlib a complete figure description to visualize. In |
| 40 | +addition, because an ``Artist`` has no conception of its own semantics |
| 41 | +within the figure, it's difficult to interact with them in a natural |
| 42 | +way. |
| 43 | + |
| 44 | +In this sense, matplotlib will adopt a standard |
| 45 | +Model-View-Controller (MVC) framework. The *Model* will be the user |
| 46 | +defined data, style, and semantics. The *Views* are the ensemble of |
| 47 | +each individual ``Artist``, which are responsible for producing the |
| 48 | +final image based on the *model*. The *Controller* will be the |
| 49 | +``Controller`` object managing its set of ``Artist`` objects. |
| 50 | + |
| 51 | +The ``Controller`` must be able to export the information that it's |
| 52 | +carrying about the figure on command, perhaps via a ``to_json`` method |
| 53 | +or similar. Because it would be extremely extraneous to duplicate all |
| 54 | +of the information in the model with the controller, only |
| 55 | +user-specified information (data + style) are explicitly kept. If a |
| 56 | +user wants more information (defaults) from the view/model, it should |
| 57 | +be able to query for it. |
| 58 | + |
| 59 | +- This might be annoying to do, non-specified kwargs are pulled from |
| 60 | + the rcParams object which is in turn created from reading a user |
| 61 | + specified file and can be dynamically changed at run time. I |
| 62 | + suppose we could keep a dict of default defaults and compare against |
| 63 | + that. Not clear how this will interact with the style sheet |
| 64 | + [[MEP26]] - @tacaswell |
| 65 | + |
| 66 | +Additional Notes: |
| 67 | + |
| 68 | +* The `raw data` does not necessarily need to be a ``list``, |
| 69 | + ``ndarray``, etc. Rather, it can more abstractly just have a method |
| 70 | + to yield data when needed. |
| 71 | + |
| 72 | +* Because the ``Controller`` will contain extra information that users |
| 73 | + may not want to keep around, it should *not* be created by |
| 74 | + default. You should be able to both (a) instantiate a ``Controller`` |
| 75 | + with a figure and (b) build a figure with a ``Controller``. |
| 76 | + |
| 77 | +Use Cases: |
| 78 | + |
| 79 | +* Export all necessary informat |
| 80 | +* Serializing a matplotlib figure, saving it, and being able to rerun later. |
| 81 | +* Any other source sending an appropriately formatted representation to matplotlib to open |
| 82 | + |
| 83 | +Examples |
| 84 | +-------- |
| 85 | +Here are some examples of what the controllers should be able to do. |
| 86 | + |
| 87 | +1. Instantiate a matplotlib figure from a serialized representation (e.g., JSON): :: |
| 88 | + |
| 89 | + import json |
| 90 | + from matplotlib.controllers import Controller |
| 91 | + with open('my_figure') as f: |
| 92 | + o = json.load(f) |
| 93 | + c = Controller(o) |
| 94 | + fig = c.figure |
| 95 | + |
| 96 | +2. Manage artists from the controller (e.g., Line2D): :: |
| 97 | + |
| 98 | + # not really sure how this should look |
| 99 | + c.axes[0].lines[0].color = 'b' |
| 100 | + # ? |
| 101 | + |
| 102 | +3. Export serializable figure representation: :: |
| 103 | + |
| 104 | + o = c.to_json() |
| 105 | + # or... we should be able to throw a figure object in there too |
| 106 | + o = Controller.to_json(mpl_fig) |
| 107 | + |
| 108 | +Implementation |
| 109 | +-------------- |
| 110 | + |
| 111 | +1. Create base ``Controller`` objects that are able to manage |
| 112 | + ``Artist`` objects (e.g., ``Hist``) |
| 113 | + |
| 114 | + Comments: |
| 115 | + |
| 116 | + * initialization should happen via unpacking ``**``, so we need a |
| 117 | + copy of call signature parameter for the ``Artist`` we're |
| 118 | + ultimately trying to control. Unfortunate hard-coded |
| 119 | + repetition... |
| 120 | + * should the additional ``**kwargs`` accepted by each ``Artist`` |
| 121 | + be tracked at the ``Controller`` |
| 122 | + * how does a ``Controller`` know which artist belongs where? E.g., |
| 123 | + do we need to pass ``axes`` references? |
| 124 | + |
| 125 | + Progress: |
| 126 | + |
| 127 | + * A simple NB demonstrating some functionality for |
| 128 | + ``Line2DController`` objects: |
| 129 | + http://nbviewer.ipython.org/gist/theengineear/f0aa8d79f64325e767c0 |
| 130 | + |
| 131 | +2. Write in protocols for the ``Controller`` to *update* the model. |
| 132 | + |
| 133 | + Comments: |
| 134 | + |
| 135 | + * how should containers be dealt with? E.g., what happens to old |
| 136 | + patches when we re-bin a histogram? |
| 137 | + * in the link from (1), the old line is completely destroyed and |
| 138 | + redrawn, what if something is referencing it? |
| 139 | + |
| 140 | +3. Create method by which a json object can be assembled from the |
| 141 | + ``Controllers`` |
| 142 | +4. Deal with serializing the unserializable aspects of a figure (e.g., |
| 143 | + non-affine transforms?) |
| 144 | +5. Be able to instantiate from a serialized representation |
| 145 | +6. Reimplement the existing pyplot and Axes method, |
| 146 | + e.g. ``pyplot.hist`` and ``Axes.hist`` in terms of the new |
| 147 | + controller class. |
| 148 | + |
| 149 | +> @theengineer: in #2 above, what do you mean by *get updates* from |
| 150 | +each ``Artist``? |
| 151 | + |
| 152 | +^ Yup. The ``Controller`` *shouldn't* need to get updated. This just |
| 153 | +happens in #3. Delete comments when you see this. |
| 154 | + |
| 155 | +Backward compatibility |
| 156 | +---------------------- |
| 157 | + |
| 158 | +* pickling will change |
| 159 | +* non-affine transformations will require a defined pickling method |
| 160 | + |
| 161 | +Alternatives |
| 162 | +------------ |
| 163 | + |
| 164 | +PR #3150 suggested adding semantics by parasitically attaching extra |
| 165 | +containers to axes objects. This is a more complete solution with what |
| 166 | +should be a more developed/flexible/powerful framework. |
0 commit comments