├── drawnow
├── __init__.py
└── drawnow.py
├── setup.cfg
├── .gitignore
├── test-data
├── test.gif
├── test.mov
├── mandrill.png
└── matlab_drawnow.m
├── MANIFEST
├── LISCENSE.txt
├── test.py
├── setup.py
└── README.md
/drawnow/__init__.py:
--------------------------------------------------------------------------------
1 | from .drawnow import *
2 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 |
2 | [metadata]
3 | description-file = README.md
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | dist/
3 | drawnow.egg-info/
4 | __pycache__/
5 |
--------------------------------------------------------------------------------
/test-data/test.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stsievert/python-drawnow/HEAD/test-data/test.gif
--------------------------------------------------------------------------------
/test-data/test.mov:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stsievert/python-drawnow/HEAD/test-data/test.mov
--------------------------------------------------------------------------------
/test-data/mandrill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stsievert/python-drawnow/HEAD/test-data/mandrill.png
--------------------------------------------------------------------------------
/MANIFEST:
--------------------------------------------------------------------------------
1 | # file GENERATED by distutils, do NOT edit
2 | README.txt
3 | setup.cfg
4 | setup.py
5 | drawnow/__init__.py
6 | drawnow/drawnow.py
7 |
--------------------------------------------------------------------------------
/test-data/matlab_drawnow.m:
--------------------------------------------------------------------------------
1 | clc; clear all; close all;
2 |
3 | N = 16;
4 | x = zeros(N,N);
5 |
6 | figure()
7 | imshow(x)
8 | %function_to_draw()
9 |
10 | for i=1:N*N,
11 | x(i) = i;
12 |
13 | imshow(x)
14 | %function_to_draw()
15 |
16 | drawnow
17 | pause(0.01)
18 | end
--------------------------------------------------------------------------------
/LISCENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Copyright (C) 2014 Scott Sievert
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 | from pylab import *
3 | from scipy.sparse.linalg import svds
4 | from drawnow import *
5 |
6 | def approx(x, k):
7 | """ Approximate x using the SVD keeping the k largest singular values. """
8 | y = zeros_like(x)
9 | for i in arange(4):
10 | u, sigmas, v = svd(x[:,:,i])
11 | sigmas[k:] = 0
12 |
13 | s = zeros_like(x[:,:,i])
14 | fill_diagonal(s, sigmas)
15 |
16 | color = u.dot(s).dot(v)
17 | y[:,:,i] = np.clip(color, 0, 1)
18 | return y
19 |
20 | WIDTH = 7
21 | figure(figsize=(WIDTH, WIDTH / 2))
22 | def draw_fig():
23 | """ Uses Python's global scope """
24 | subplot(1, 2, 1)
25 | imshow(x, cmap='gray')
26 | title('Original')
27 | axis('off')
28 |
29 | subplot(1, 2, 2)
30 | imshow(x_hat, cmap='gray')
31 | title('Approx with $k=%d$' % k)
32 | axis('off')
33 | # show()
34 |
35 | x = imread('test-data/mandrill.png')
36 | k_values = around(logspace(0.1, log10(64), num=10)).astype('int')
37 | for k in k_values:
38 | x_hat = approx(x, k)
39 | drawnow(draw_fig, stop_on_close=True)
40 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 | from os import path
3 |
4 | # Steps to update on PyPI:
5 | # 1. python setup.py sdist bdist_wheel
6 | # 2. twine upload dist/*
7 |
8 | this_directory = path.abspath(path.dirname(__file__))
9 | with open(path.join(this_directory, 'README.md'), "r") as f:
10 | long_description = f.read()
11 |
12 | setup(
13 | name='drawnow',
14 | packages=['drawnow'],
15 | version='0.72.5',
16 | description='MATLAB-like drawnow',
17 | long_description=long_description,
18 | long_description_content_type='text/markdown',
19 | author='Scott Sievert',
20 | author_email='dev@stsievert.com',
21 | url='https://github.com/stsievert/python-drawnow',
22 | download_url='https://github.com/stsievert/python-drawnow/archive/master.zip',
23 | keywords=['figure', 'plotting', 'visualization', 'matlab'],
24 | use_2to3=True,
25 | requires=['matplotlib'],
26 | install_requires=['matplotlib>=1.5'],
27 | classifiers=[
28 | "Intended Audience :: Science/Research",
29 | "License :: OSI Approved :: MIT License",
30 | "Natural Language :: English", "Operating System :: OS Independent",
31 | "Programming Language :: Python", "Topic :: Scientific/Engineering",
32 | "Topic :: Scientific/Engineering :: Visualization"
33 | ])
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | `drawnow` for matplotlib
6 | ========================
7 |
8 | The scientific community often runs iterative code, often in the form of
9 | simulation. It's often useful to see the results after each iteration.
10 | Accordingly, MATLAB® has a nice feature that allows you to update the
11 | figure, `drawnow`. This repo brings the same feature to Python's
12 | matplotlib, with some extras.
13 |
14 | Example:
15 |
16 | 
17 |
18 | This is shown with `imshow`, but python-drawnow allows updates of any
19 | figure.
20 |
21 | Usage:
22 |
23 | ``` python
24 | # complete implementation of script found in test/test.py
25 | from pylab import *
26 | from drawnow import drawnow, figure
27 | # if global namespace, import plt.figure before drawnow.figure
28 |
29 | def approx(x, k):
30 | """Approximate x with k singular values"""
31 | ...
32 |
33 | figure(figsize=(7, 7/2))
34 | def draw_fig():
35 | subplot(1, 2, 1)
36 | imshow(x)
37 |
38 | subplot(1, 2, 2)
39 | imshow(x_hat)
40 | #show()
41 |
42 | x = imread('test-data/mandrill.png').mean(axis=2)
43 | k_values = around(logspace(0, 2, num=10))
44 | for k in k_values:
45 | x_hat = approx(x, k)
46 | drawnow(draw_fig)
47 | ```
48 |
49 | Documentation
50 | =============
51 |
52 | If you want to wait for confirmation after update or the option to drop
53 | into a debugger, call `drawnow(function_to_draw_figure, confirm=True)`.
54 |
55 | If you only want to show the figure once, call
56 | `drawnow(function_to_draw_figure, show_once=True)`. The full
57 | documentation is included in the doc strings. Use `drawnow?` or
58 | `help(drawnow)` to see these docs.
59 |
60 | Jupyter/Spyder
61 | ==============
62 |
63 | Try running the folloowing code in a Jupyter input cell/in the
64 | console/etc:
65 |
66 | ```
67 | %matplotlib
68 | ```
69 |
70 | This will disable the Matplotlin inline mode and use the default
71 | plotting backend. For more detail, see the [IPython plotting
72 | documentation](https://ipython.readthedocs.io/en/stable/interactive/plotting.html#id1).
73 |
74 | Installation
75 | ============
76 |
77 | Two options:
78 |
79 | 1. Run `pip install drawnow`.
80 | 2. Download this repository and run `python setup.py install`.
81 |
82 | Option 2 assumes a working Python installation with `pip`. I suggest
83 | Anaconda's distribution: For
84 | other options, see .
85 |
86 | Changes to code
87 | ---------------
88 |
89 | This does require *small* changes to your code. All it should really
90 | amount to is moving `figure(); plot(...); show()` inside a function; not
91 | much.
92 |
--------------------------------------------------------------------------------
/drawnow/drawnow.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import sys
3 | import pdb
4 | import matplotlib.pyplot as plt
5 |
6 |
7 | def drawnow(draw_fig, show_once=False, confirm=False, stop_on_close=False,
8 | *args, **kwargs):
9 | """A function to refresh the current figure.
10 |
11 | Depends on matplotlib's interactive mode. Similar functionality to MATLAB's
12 | drawnow.
13 |
14 | Parameters
15 | ----------
16 | draw_fig : callable
17 | The function that draws the figure you want to update
18 | show_once, optional : bool (default: False)
19 | If True, will call show() instead of draw().
20 | confirm, optional : bool, (default: False)
21 | If True, wait for user input after each iteration and present
22 | option to drop to python debugger (pdb).
23 | stop_on_close, optional : bool (default: False)
24 | When the figure is closed, stop the program execution.
25 | *args : list
26 | The list of parameters to pass ``draw_fig()``
27 | **kwargs : dict
28 | The keywords to pass to ``draw_fig()``
29 |
30 | Notes
31 | -----
32 |
33 | This function does not work with the inline plotting mode, which is
34 | common in Jupyter notebooks/lab, Spyder and the QTConsole. To
35 | disable this, run the following "magic" command:
36 |
37 | %matplotlib
38 |
39 | This will disable the Matplotlib inline mode and use the default plotting backend. For more detail, see `IPython's plotting documentation`_.
40 |
41 | Some limitations are the following:
42 |
43 | - Occaisonally ignores Ctrl-C especially while processing LaTeX.
44 | - The initial processing of Latex labels (typically on the x/y axis and
45 | title) is slow. However, matplotlib caches the results so any subsequent
46 | animations are pretty fast.
47 | - If two figures open and focus moved between figures, then other figure
48 | gets cleared.
49 |
50 | Usage Example
51 | -------------
52 | >>> from pylab import * # import matplotlib before drawnow
53 | >>> from drawnow import drawnow, figure
54 | >>> def draw_fig_real():
55 | >>> #figure() # don't call, otherwise opens new window
56 | >>> imshow(z, interpolation='nearest')
57 | >>> colorbar()
58 | >>> #show()
59 | >>>
60 | >>> N = 16
61 | >>> z = zeros((N,N))
62 | >>>
63 | >>> figure()
64 | >>> for i in arange(N*N):
65 | >>> z.flat[i] = 0
66 | >>> drawnow(draw_fig_real)
67 |
68 | .. _IPython's plotting documentation: https://ipython.readthedocs.io/en/stable/interactive/plotting.html#id1
69 |
70 | """
71 | # replace the current figure w/o opening new GUI
72 | plt.clf()
73 | draw_fig(*args, **kwargs)
74 |
75 | if show_once:
76 | plt.show()
77 | else:
78 | plt.draw_all()
79 |
80 | plt.pause(1e-3) # allows time to draw
81 |
82 | figures = plt.get_fignums()
83 | if stop_on_close and not figures:
84 | sys.exit()
85 |
86 | if confirm:
87 | string = raw_input('Hit to continue, "d" for debugger and "x" '
88 | 'to exit: ')
89 | if string == 'x' or string == 'exit':
90 | sys.exit()
91 | if string == 'd' or string == 'debug':
92 | print('\nType "exit" to continue program execution\n')
93 | pdb.runeval('u')
94 |
95 |
96 | def figure(*args, **kwargs):
97 | """
98 | Enable drawnow. This function just enables interactivity then
99 | call's matplotlib's ion() to enable interactivity. Any arguments passed to
100 | this function are then passed to plt.figure()
101 |
102 | This function only enables interactivity and calls figure. To implement
103 | interactivity yourself, call plt.ion()
104 |
105 | Parameters
106 | ----------
107 | *argv : any
108 | pass these arguments to plt.figure
109 | **kwargs : any
110 | pass these arguments to plt.figure
111 | """
112 | plt.ion()
113 | plt.figure(*args, **kwargs)
114 |
--------------------------------------------------------------------------------