This module intercepts all calls to matplotlib and then allows you to do any of the following:
NOTE: mpltracker is still a work in progress and so the API may change at any time.
Currently mpltracker has been tested on Python 2.7. See the travis report for details on the full testing-matrix. Python 3 currently does not track commands correctly see open issue, and has therefore been disabled from travis testing, until fixed.
Installation is done using the standard python setup.py commands.
To install globally:
python setup.py build
sudo python setup.py install
Or to install locally:
python setup.py build
python setup.py install --user
mpltracker is imported as a python module, but must be imported before the first import to matplotlib
import mpltracker
import matplotlib.pyplot as plt
By calling start, the tracker will then start 'spying' and recording all commands sent through matplotlib
mpltracker.start()
To stop tracking, simply issue the stop command
mpltracker.stop()
To save the output to a file
mpltracker.save(filename)
To show the figure(s) currently tracked
mpltracker.show()
or to load in and show a previously saved file
mpltracker.show(filename)
For more details, see the example scripts in the examples directory:
Installing mpltracker also installs a command-line utility called mplshow
. mplshow takes a single command-line argument (either the filename or URL of a file created by mpltracker) and will load the figure(s) and show them in an interactive matplotlib window.
mplshow <file>.mpl
Below is a simple matplotlib figure created in the simple example script but which links to the output file from mpltracker. Clicking on the image will show the simple.mpl
file which could then be opened with mpltracker or mplshow from the command-line.
There is an open issue to support registering mplshow for specific file extensions or web-proticols so that clicking on an image linking to the .mpl file would automatically pop-up the interactive figure. Until then, you need to copy the URL and call mplshow manually:
mplshow https://raw.githubusercontent.com/kecnry/mpltracker/master/examples/simple.mpl
The html code for this is simply
<a href="https://raw.githubusercontent.com/kecnry/mpltracker/master/examples/simple.mpl"><img src="https://github.com/kecnry/mpltracker/blob/master/examples/simple.png" width="400px"/></a>
making it trivial to display images on a website which are then interactive (for any user that has mpltracker/mplshow installed) locally with a single click (once the open issue is close).
mpltracker adds a decorator to all functions and methods inside the matplotlib module. Whenever you make a call that goes through matplotlib, a lightweight wrapper is called first (either intercept_func
or intercept_method
in mpltracker.py) which gets the parent object (eg. fig or ax) or module (eg. plt), the name of the method or function you are trying to call, and all arguments (args) and keyword-arguments (kwargs). The tracker object itself then records these items and passes along all the arguments to the originally requested call. It then attaches the same decorators to any returned objects (eg. if you call ax=fig.add_subplot(111), mpltracker will now also intercept any calls to ax.*), and gives that object an internal id so that when rebuilding the calls we know which resulting object to use.
Calling mpltracker.save simply dumps a json-formatted file of these stored arguments - just a list of dictionaries. If you look at the output file of subplots.py and compare it to the subplots.py script, you can see what is being stored.
The first call to matplotlib after tracking is enabled is fig = plt.figure(figsize=(12,6))
which is then stored in the output file as:
{"returns": ["<id:140521903846288>"], "args": [], "obj": null, "func": "figure", "kwargs": {"figsize": [12, 6]}}
When rebuilding the figure, this simply says to call the figure
function of plt
(since obj is null) with no args and figsize=[12,6] as keyword arguments. This will then return a single object (which was called fig in the script), and which is labeled with a random ID for later reference.
The second call to matplotlib is ax1 = fig.add_subplot(121)
and is stored in the output file as:
{"returns": ["<id:140521903401296>"], "args": [121], "obj": "<id:140521903846288>", "func": "add_subplot", "kwargs": {}}
So as the second step of rebuilding the figure, this says to call the add_subplot
method of whatever object was assigned to the ID associated with obj (in this case what we called fig), with [121] as args and no keyword arguments. This in turn will return a single object (ax1) which will also be assigned ID.
Much of the backbone behind mpltracker depends on hacking and decorating the matplotlib module. Although slightly modified, most of the modulehacker.py and decorations.py were originally created by Eric Snow and included here under the MIT license. The originally postings can be found here for modulehacker.py and for decorations.py (these links can also be found in the credits in the source-code in this project).
Contributions are welcome! Feel free to file an issue or fork and create a pull-request.