├── .gitignore
├── Makefile
├── README
├── README.md
├── docs
├── animated.gif
├── lightdark.png
├── sea.py
├── simple.py
├── subplots.png
└── test.py
├── itermplot
└── __init__.py
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .coverage
41 | .coverage.*
42 | .cache
43 | nosetests.xml
44 | coverage.xml
45 | *,cover
46 | .hypothesis/
47 |
48 | # Translations
49 | *.mo
50 | *.pot
51 |
52 | # Django stuff:
53 | *.log
54 | local_settings.py
55 |
56 | # Flask stuff:
57 | instance/
58 | .webassets-cache
59 |
60 | # Scrapy stuff:
61 | .scrapy
62 |
63 | # Sphinx documentation
64 | docs/_build/
65 |
66 | # PyBuilder
67 | target/
68 |
69 | # IPython Notebook
70 | .ipynb_checkpoints
71 |
72 | # pyenv
73 | .python-version
74 |
75 | # celery beat schedule file
76 | celerybeat-schedule
77 |
78 | # dotenv
79 | .env
80 |
81 | # virtualenv
82 | venv/
83 | ENV/
84 |
85 | # Spyder project settings
86 | .spyderproject
87 |
88 | # Rope project settings
89 | .ropeproject
90 |
91 | .DS_Store
92 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | upload:
2 | pandoc --from=markdown --to=rst --output=README README.md
3 | python3 setup.py sdist
4 | twine upload dist/*
5 |
6 | clean:
7 | @rm -fr build dist
8 | @rm -fr itermplot.egg-info
9 | @rm -fr itermplot/__pycache__
10 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | itermplot
2 | =========
3 |
4 | An awesome `iTerm2 `__ backend for Matplotlib,
5 | so you can plot directly in your terminal.
6 |
7 | The above is achieved with zero modifications to your Python script. For
8 | example, the above plots are generated with the following code:
9 |
10 | .. code:: {python}
11 |
12 | import numpy as np
13 | import matplotlib.pyplot as plt
14 | import networkx as nx
15 |
16 | plt.rcParams["font.size"] = 10
17 |
18 | plt.figure(figsize=(8,3))
19 |
20 | ax = plt.subplot(121)
21 | x = np.arange(0,10,0.001)
22 | ax.plot(x, np.sin(np.sinc(x)), 'r', lw=2)
23 | ax.set_title('Nice wiggle')
24 |
25 | ax = plt.subplot(122)
26 | plt.tick_params(axis='both', left='off', top='off', right='off', bottom='off', labelleft='off', labeltop='off', labelright='off', labelbottom='off')
27 | G = nx.random_geometric_graph(200, 0.125)
28 | pos=nx.spring_layout(G)
29 | nx.draw_networkx_edges(G, pos, alpha=0.2)
30 | nx.draw_networkx_nodes(G, pos, node_color='r', node_size=12)
31 | ax.set_title('Random graph')
32 |
33 | plt.show()
34 |
35 | Note: you need to run ``plt.show()`` to display the figure.
36 |
37 | Reverse video
38 | ~~~~~~~~~~~~~
39 |
40 | If you use a dark background in your terminal, you can enable “reverse
41 | video” mode by adding this to your ``.profile``:
42 |
43 | ::
44 |
45 | export ITERMPLOT=rv
46 |
47 | TMUX support
48 | ~~~~~~~~~~~~
49 |
50 | itermplot tries to auto-detect TMUX and behave in a sane way. Vertical
51 | split panes do not work well due to a limitation with iTerm2. Luckily,
52 | horizontals do though.
53 |
54 | Animation support
55 | ~~~~~~~~~~~~~~~~~
56 |
57 | itermplot supports animation created by matplotlib animation module.
58 |
59 | You’ll need to install ImageMagick and have it on the path to use the
60 | animation support. The simplest way to see if ImageMagick is installed
61 | and valid is to run:
62 |
63 | .. code:: {sh}
64 |
65 | $ convert -version
66 | Version: ImageMagick 7.0.4-4 Q16 x86_64 2017-01-14 http://www.imagemagick.org
67 | Copyright: © 1999-2017 ImageMagick Studio LLC
68 | License: http://www.imagemagick.org/script/license.php
69 | Features: Cipher DPC HDRI Modules
70 | Delegates (built-in): bzlib freetype jng jpeg ltdl lzma png tiff xml zlib
71 |
72 | To enable animation support, you need to specifying the desired number
73 | of frames in the output animation. For example, specify it before your
74 | script with:
75 |
76 | ::
77 |
78 | $ ITERMPLOT_FRAMES=30 python script.py
79 |
80 | You can also save the resulting gif file by using ``ITERMPLOT_OUTFILE``
81 | environment variable:
82 |
83 | ::
84 |
85 | $ ITERMPLOT_FRAMES=30 ITERMPLOT_OUTFILE=out.gif python script.py
86 |
87 | Currently animation does not support reverse video with ITERMPLOT=rv.
88 |
89 | Configure lines
90 | ~~~~~~~~~~~~~~~
91 |
92 | You can configure the number of lines used with the ``ITERMPLOT_LINES``
93 | environment variable. For example:
94 |
95 | .. code:: {sh}
96 |
97 | ITERMPLOT_LINES=5 python3 simple.py
98 |
99 | Python 2 and Python 3 support
100 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
101 |
102 | Now supports Python 2, even if this makes me want to cry 😭
103 |
104 | Installation
105 | ------------
106 |
107 | Using pip
108 | ~~~~~~~~~
109 |
110 | Install using ``pip`` using the command:
111 |
112 | .. code:: {sh}
113 |
114 | pip3 install itermplot
115 |
116 | itermplot is enabled by setting ``MPLBACKEND`` in your environment. If
117 | you use ``bash``, then this can be accomplished using the command:
118 |
119 | .. code:: {sh}
120 |
121 | export MPLBACKEND="module://itermplot"
122 |
123 | Note: you can add the ``export`` line above to your ``.profile`` file so
124 | that itermplot is always enabled in your terminal.
125 |
126 | Testing
127 | ~~~~~~~
128 |
129 | To test your installation you can do the following in your iTerm2
130 | console:
131 |
132 | ::
133 |
134 | $ echo $MPLBACKEND
135 | module://itermplot
136 | $ python3
137 | Python 3.5.2 (default, Oct 24 2016, 09:14:06)
138 | [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
139 | Type "help", "copyright", "credits" or "license" for more information.
140 | >>> import matplotlib.pyplot as plt
141 | >>> plt.plot([1,2,3])
142 | []
143 | >>> plt.show()
144 |
145 | You should see a plot!
146 |
147 | Uninstall
148 | ---------
149 |
150 | You can disable this backend by unsetting the ``MPLBACKEND`` environment
151 | variable.
152 |
153 | ::
154 |
155 | $ unset MPLBACKEND
156 | $ echo $MPLBACKEND
157 |
158 | $ python3
159 | Python 3.5.2 (default, Oct 24 2016, 09:14:06)
160 | [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
161 | Type "help", "copyright", "credits" or "license" for more information.
162 | >>> import matplotlib.pyplot as plt
163 | >>> plt.plot([1,2,3])
164 | []
165 | >>> plt.show()
166 |
167 | To remove the package completely, run:
168 |
169 | ::
170 |
171 | pip3 uninstall itermplot
172 |
173 | Bugs
174 | ----
175 |
176 | This backend is very alpha, so if you have a problem please raise an
177 | Issue on GitHub and I will try to fix it.
178 |
179 | I also accept (and appreciate!) good patches / pull request. Thanks to
180 | `garrywu `__,
181 | `brenshanny `__,
182 | `hbredin `__,
183 | `zevlg `__ for their patches so far.
184 |
185 | Other cool things
186 | -----------------
187 |
188 | I encourage you to check-out some of my `other little
189 | projects `__. Lots more coming as I
190 | slowly release them…
191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # itermplot
2 |
3 | ```
4 | pip install itermplot==0.5
5 | ```
6 |
7 | An awesome [iTerm2](https://www.iterm2.com/) backend for Matplotlib, so you can plot directly in your terminal.
8 |
9 |
10 |
11 | The above is achieved with zero modifications to your Python script. For example, the above
12 | plots are generated with the following code:
13 | ```{python}
14 | import numpy as np
15 | import matplotlib.pyplot as plt
16 | import networkx as nx
17 |
18 | plt.rcParams["font.size"] = 10
19 |
20 | plt.figure(figsize=(8,3))
21 |
22 | ax = plt.subplot(121)
23 | x = np.arange(0,10,0.001)
24 | ax.plot(x, np.sin(np.sinc(x)), 'r', lw=2)
25 | ax.set_title('Nice wiggle')
26 |
27 | ax = plt.subplot(122)
28 | plt.tick_params(axis='both', left='off', top='off', right='off', bottom='off', labelleft='off', labeltop='off', labelright='off', labelbottom='off')
29 | G = nx.random_geometric_graph(200, 0.125)
30 | pos=nx.spring_layout(G)
31 | nx.draw_networkx_edges(G, pos, alpha=0.2)
32 | nx.draw_networkx_nodes(G, pos, node_color='r', node_size=12)
33 | ax.set_title('Random graph')
34 |
35 | plt.show()
36 | ```
37 |
38 | Note: you need to run `plt.show()` to display the figure.
39 |
40 | ### Reverse video
41 |
42 | If you use a dark background in your terminal, you can enable "reverse video" mode by adding this to your `.profile`:
43 | ```
44 | export ITERMPLOT=rv
45 | ```
46 |
47 | ### TMUX support
48 |
49 | itermplot tries to auto-detect TMUX and behave in a sane way. Vertical split panes do not work well due to a
50 | limitation with iTerm2. Luckily, horizontals do though.
51 |
52 | ### Animation support
53 |
54 | itermplot supports animation created by matplotlib animation module.
55 |
56 |
57 |
58 | You'll need to install ImageMagick and have it on the path to use the animation support. The simplest way to see if ImageMagick is installed and valid is to run:
59 | ```{sh}
60 | $ convert -version
61 | Version: ImageMagick 7.0.4-4 Q16 x86_64 2017-01-14 http://www.imagemagick.org
62 | Copyright: © 1999-2017 ImageMagick Studio LLC
63 | License: http://www.imagemagick.org/script/license.php
64 | Features: Cipher DPC HDRI Modules
65 | Delegates (built-in): bzlib freetype jng jpeg ltdl lzma png tiff xml zlib
66 | ```
67 |
68 | To enable animation support, you need to specifying the desired number of frames in the output animation. For example, specify it before your script with:
69 | ```
70 | $ ITERMPLOT_FRAMES=30 python script.py
71 | ```
72 |
73 | You can also save the resulting gif file by using `ITERMPLOT_OUTFILE` environment variable:
74 | ```
75 | $ ITERMPLOT_FRAMES=30 ITERMPLOT_OUTFILE=out.gif python script.py
76 | ```
77 |
78 | Currently animation does not support reverse video with ITERMPLOT=rv.
79 |
80 | ### Configure lines
81 |
82 | You can configure the number of lines used with the `ITERMPLOT_LINES` environment variable. For example:
83 | ```{sh}
84 | ITERMPLOT_LINES=5 python3 simple.py
85 | ```
86 |
87 | ### Python 2 and Python 3 support
88 |
89 | Now supports Python 2, even if this makes me want to cry 😭
90 |
91 | ## Installation
92 |
93 | ### Using pip
94 |
95 | Install using `pip` using the command:
96 | ```{sh}
97 | pip3 install itermplot
98 | ```
99 |
100 | itermplot is enabled by setting `MPLBACKEND` in your environment. If you use `bash`, then this can be accomplished using the command:
101 | ```{sh}
102 | export MPLBACKEND="module://itermplot"
103 | ```
104 | Note: you can add the `export` line above to your `.profile` file so that itermplot is always enabled in your terminal.
105 |
106 | ### Testing
107 |
108 | To test your installation you can do the following in your iTerm2 console:
109 | ```
110 | $ echo $MPLBACKEND
111 | module://itermplot
112 | $ python3
113 | Python 3.5.2 (default, Oct 24 2016, 09:14:06)
114 | [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
115 | Type "help", "copyright", "credits" or "license" for more information.
116 | >>> import matplotlib.pyplot as plt
117 | >>> plt.plot([1,2,3])
118 | []
119 | >>> plt.show()
120 | ```
121 |
122 | You should see a plot!
123 |
124 | ## Uninstall
125 |
126 | You can disable this backend by unsetting the `MPLBACKEND` environment variable.
127 | ```
128 | $ unset MPLBACKEND
129 | $ echo $MPLBACKEND
130 |
131 | $ python3
132 | Python 3.5.2 (default, Oct 24 2016, 09:14:06)
133 | [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
134 | Type "help", "copyright", "credits" or "license" for more information.
135 | >>> import matplotlib.pyplot as plt
136 | >>> plt.plot([1,2,3])
137 | []
138 | >>> plt.show()
139 | ```
140 |
141 | To remove the package completely, run:
142 | ```
143 | pip3 uninstall itermplot
144 | ```
145 |
146 | ## Bugs
147 |
148 | This backend is very alpha, so if you have a problem please raise an Issue on GitHub and I will try to fix it.
149 |
150 | I also accept (and appreciate!) good patches / pull request. Thanks to [garrywu](https://github.com/garywu), [brenshanny](https://github.com/brenshanny), [hbredin](https://github.com/hbredin), [zevlg](https://github.com/zevlg) for their patches so far.
151 |
152 | ## Other cool things
153 |
154 | I encourage you to check-out some of my [other little projects](https://github.com/daleroberts). Lots more coming as I slowly release them...
155 |
--------------------------------------------------------------------------------
/docs/animated.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daleroberts/itermplot/e8427ce87b0d74e18e14d8c092a01696c17b4c3e/docs/animated.gif
--------------------------------------------------------------------------------
/docs/lightdark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daleroberts/itermplot/e8427ce87b0d74e18e14d8c092a01696c17b4c3e/docs/lightdark.png
--------------------------------------------------------------------------------
/docs/sea.py:
--------------------------------------------------------------------------------
1 | import matplotlib
2 | import matplotlib.pyplot as plt
3 | import seaborn as sns
4 | iris = sns.load_dataset("iris")
5 | species = iris.pop("species")
6 | g = sns.clustermap(iris)
7 | plt.show()
8 |
--------------------------------------------------------------------------------
/docs/simple.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | plt.plot([1,2,3])
3 | plt.show()
4 |
--------------------------------------------------------------------------------
/docs/subplots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daleroberts/itermplot/e8427ce87b0d74e18e14d8c092a01696c17b4c3e/docs/subplots.png
--------------------------------------------------------------------------------
/docs/test.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | import networkx as nx
4 |
5 | plt.rcParams["font.size"] = 10
6 |
7 | plt.figure(figsize=(8,3))
8 |
9 | ax = plt.subplot(121)
10 | x = np.arange(0,10,0.001)
11 | ax.plot(x, np.sin(np.sinc(x)), 'r', lw=2)
12 | ax.set_title('Nice wiggle')
13 |
14 | ax = plt.subplot(122)
15 | plt.tick_params(axis='both', left='off', top='off', right='off', bottom='off', labelleft='off', labeltop='off', labelright='off', labelbottom='off')
16 | G = nx.random_geometric_graph(200, 0.125)
17 | pos=nx.spring_layout(G)
18 | nx.draw_networkx_edges(G, pos, alpha=0.2)
19 | nx.draw_networkx_nodes(G, pos, node_color='r', node_size=12)
20 | ax.set_title('Random graph')
21 |
22 | plt.show()
--------------------------------------------------------------------------------
/itermplot/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | An iTerm2 matplotlib backend.
4 |
5 | Author: Dale Roberts
6 | """
7 |
8 | from __future__ import absolute_import, division, print_function, unicode_literals
9 |
10 | import six
11 |
12 | import numpy as np
13 | import matplotlib
14 | import sys
15 | import os
16 | import io
17 |
18 | from matplotlib._pylab_helpers import Gcf
19 | from matplotlib.colors import ColorConverter
20 | from matplotlib.backend_bases import FigureManagerBase, TimerBase
21 | from matplotlib.backends.backend_mixed import MixedModeRenderer
22 | from matplotlib.backends.backend_pdf import (
23 | FigureCanvasPdf,
24 | PdfPages,
25 | PdfFile,
26 | RendererPdf,
27 | )
28 | from matplotlib.backends.backend_agg import FigureCanvasAgg
29 | from matplotlib.animation import ImageMagickWriter
30 | from matplotlib.figure import Figure
31 | from base64 import b64encode
32 |
33 | to_rgba = ColorConverter().to_rgba
34 | rcParams = matplotlib.rcParams
35 |
36 | try:
37 | TMUX = os.getenv("TERM", "").startswith("screen")
38 | LINES = int(os.getenv("ITERMPLOT_LINES", "-1"))
39 | THEME = os.getenv("ITERMPLOT", "") # perhaps rename this now
40 | OUTFILE = os.getenv("ITERMPLOT_OUTFILE", "out.gif")
41 | PLOTFILE = os.getenv("ITERMPLOT_PLOTFILE", "plot.png")
42 | FRAMES = int(os.getenv("ITERMPLOT_FRAMES", "0"))
43 | COLORS = ColorConverter.colors
44 | except ValueError:
45 | print("Error: problems with itermplot configuration.")
46 | sys.exit(1)
47 |
48 | if sys.version_info < (3,):
49 | # Supporting Python 2 makes me want to cry :_(
50 | def B(x):
51 | return bytes(x)
52 |
53 |
54 | else:
55 |
56 | def B(x):
57 | return bytes(x, "utf-8")
58 |
59 |
60 | def revvideo(x):
61 | """Try to 'reverse video' the color. Otherwise,
62 | return the object unchanged if it can't."""
63 |
64 | def rev(c):
65 | if isinstance(c, six.string_types):
66 | c = to_rgba(c)
67 |
68 | if len(c) == 4:
69 | r, g, b, a = c
70 | return (1.0 - r, 1.0 - g, 1.0 - b, a)
71 | else:
72 | r, g, b = c
73 | return (1.0 - r, 1.0 - g, 1.0 - b, 1.0)
74 |
75 | try:
76 | if isinstance(x, str) and x == "none":
77 | return x
78 | if isinstance(x, np.ndarray):
79 | return np.array([rev(el) for el in x])
80 | return rev(x)
81 | except (ValueError, KeyError) as e:
82 | print("bad", x, e)
83 | return x
84 |
85 |
86 | def imgcat(data, fn="plot.pdf"):
87 | """Output the image data to the iTerm2 console. If `lines` is greater
88 | than zero then advance the console `lines` number of blank lines, move
89 | back, and then output the image. This is the default behaviour if TMUX
90 | is detected (lines set to 10)."""
91 |
92 | lines = LINES
93 |
94 | if TMUX:
95 | if lines == -1:
96 | lines = 10
97 | osc = b"\033Ptmux;\033\033]"
98 | st = b"\a\033\\"
99 | else:
100 | osc = b"\033]"
101 | st = b"\a"
102 | csi = b"\033["
103 |
104 | buf = bytes()
105 |
106 | if lines > 0:
107 | buf += lines * b"\n" + csi + b"?25l" + csi + B("%dF" % lines) + osc
108 | dims = "width=auto;height=%d;preserveAspectRatio=1" % lines
109 | else:
110 | buf += osc
111 | dims = "width=auto;height=auto"
112 |
113 | buf += B("1337;File=name=")
114 | buf += b64encode(B(fn))
115 | buf += B(";size=%d;inline=1;" % len(data) + dims + ":")
116 | buf += b64encode(data) + st
117 |
118 | if lines > 0:
119 | buf += csi + B("%dE" % lines) + csi + b"?25h"
120 |
121 | if hasattr(sys.stdout, "buffer"):
122 | sys.stdout.buffer.write(buf)
123 | else:
124 | sys.stdout.write(buf)
125 | sys.stdout.flush()
126 |
127 | print()
128 |
129 |
130 | def draw_if_interactive():
131 | if matplotlib.is_interactive():
132 | figmanager = Gcf.get_active()
133 | if figmanager is not None:
134 | figmanager.show()
135 |
136 |
137 | def show():
138 | figmanager = Gcf.get_active()
139 | if figmanager is not None:
140 | figmanager.show()
141 | else:
142 | for manager in Gcf.get_all_fig_managers():
143 | manager.show()
144 |
145 |
146 | def new_figure_manager(num, *args, **kwargs):
147 | FigureClass = kwargs.pop("FigureClass", Figure)
148 | thisFig = FigureClass(*args, **kwargs)
149 | return new_figure_manager_given_figure(num, thisFig)
150 |
151 |
152 | def new_figure_manager_given_figure(num, figure):
153 | canvas = FigureCanvas(figure)
154 | manager = FigureManager(canvas, num)
155 | return manager
156 |
157 |
158 | class ItermplotCanvasMixin:
159 | def __init__(self):
160 | self.reversed = False
161 | self.supports_blit = False
162 | self.timer = None
163 |
164 | def reverse(self, **kwargs):
165 | if self.reversed:
166 | return
167 |
168 | def modify(c):
169 | fcset = False
170 |
171 | try:
172 | ec = obj.get_edgecolor()
173 | obj.set_edgecolor(revvideo(ec))
174 | except AttributeError as e:
175 | pass
176 |
177 | try:
178 | fc = obj.get_facecolor()
179 | obj.set_facecolor(revvideo(fc))
180 | fcset = True
181 | except AttributeError as e:
182 | pass
183 |
184 | try:
185 | if not fcset:
186 | c = obj.get_color()
187 | obj.set_color(revvideo(c))
188 | except AttributeError as e:
189 | pass
190 |
191 | seen = set()
192 | for obj in self.figure.findobj():
193 | if not obj in seen:
194 | modify(obj)
195 | seen.add(obj)
196 |
197 | self.reversed = True
198 |
199 | def new_timer(self, *args, **kwargs):
200 | self.timer = TimerBase(*args, **kwargs)
201 | return self.timer
202 |
203 | def before_print(self, **kwargs):
204 | transparent = kwargs.pop("transparent", rcParams["savefig.transparent"])
205 |
206 | if transparent:
207 | kwargs.setdefault("facecolor", "none")
208 | kwargs.setdefault("edgecolor", "none")
209 | original_axes_colors = []
210 |
211 | for ax in self.figure.axes:
212 | patch = ax.patch
213 | original_axes_colors.append(
214 | (patch.get_facecolor(), patch.get_edgecolor())
215 | )
216 | patch.set_facecolor("none")
217 | patch.set_edgecolor("none")
218 | else:
219 | kwargs.setdefault("facecolor", rcParams["savefig.facecolor"])
220 | kwargs.setdefault("edgecolor", rcParams["savefig.edgecolor"])
221 |
222 | if "rv" in THEME:
223 | self.reverse()
224 |
225 |
226 | class FigureCanvasItermplotPdf(FigureCanvasPdf, ItermplotCanvasMixin):
227 | def __init__(self, figure):
228 | FigureCanvasPdf.__init__(self, figure)
229 | ItermplotCanvasMixin.__init__(self)
230 |
231 | def print_pdf(self, filename, **kwargs):
232 | ItermplotCanvasMixin.before_print(self, **kwargs)
233 | FigureCanvasPdf.print_pdf(self, filename, **kwargs)
234 |
235 |
236 | class FigureCanvasItermplotPng(FigureCanvasAgg, ItermplotCanvasMixin):
237 | def __init__(self, figure):
238 | FigureCanvasAgg.__init__(self, figure)
239 | ItermplotCanvasMixin.__init__(self)
240 |
241 | def print_png(self, filename, **kwargs):
242 | ItermplotCanvasMixin.before_print(self, **kwargs)
243 | FigureCanvasAgg.print_png(self, filename)
244 |
245 |
246 | class ItermplotImageMagickWriter(ImageMagickWriter):
247 | def cleanup(self):
248 | # ImageMagickWriter perhaps can expose out and err, PR
249 | # to Matplotlib someday
250 | out, err = self._proc.communicate()
251 | self.data = io.BytesIO(out)
252 | self._frame_sink().close()
253 |
254 |
255 | class ItermplotFigureManager(FigureManagerBase):
256 | def __init__(self, canvas, num):
257 | FigureManagerBase.__init__(self, canvas, num)
258 |
259 | def animate(self, loops, outfile=None, dpi=80):
260 | if outfile is None:
261 | outfile = "gif:-"
262 |
263 | self.canvas.draw_event(None)
264 |
265 | writer = ItermplotImageMagickWriter()
266 | with writer.saving(self.canvas.figure, outfile, dpi):
267 | for _ in range(loops):
268 | self.canvas.timer._on_timer()
269 | writer.grab_frame()
270 |
271 | if outfile != "gif:-":
272 | with open(outfile, "rb") as f:
273 | data = io.BytesIO(f.read())
274 | else:
275 | data = writer.data
276 |
277 | return data
278 |
279 | def show(self):
280 | data = io.BytesIO()
281 |
282 | loops = FRAMES
283 | try:
284 | loops = int(loops)
285 | except ValueError:
286 | loops = 0
287 | if not loops or self.canvas.timer is None:
288 | fn = PLOTFILE
289 | self.canvas.print_figure(
290 | data, dpi=200, facecolor="none", edgecolor="none", transparent=True
291 | )
292 | else:
293 | outfile = OUTFILE
294 | fn = "plot.gif"
295 | data = self.animate(loops, outfile)
296 |
297 | if hasattr(data, "getbuffer"):
298 | imgcat(data.getbuffer(), fn)
299 | else: # Python 2
300 | imgcat(data.getvalue(), fn)
301 |
302 |
303 | if os.path.splitext(PLOTFILE)[1] == ".png":
304 | FigureCanvas = FigureCanvasItermplotPng
305 | else:
306 | FigureCanvas = FigureCanvasItermplotPdf
307 |
308 | FigureManager = ItermplotFigureManager
309 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 | from os import path
3 | from io import open
4 |
5 | here = path.abspath(path.dirname(__file__))
6 |
7 | try:
8 | with open(path.join(here, 'README'), encoding='utf-8') as f:
9 | long_description = f.read()
10 | except(IOError):
11 | with open(path.join(here, 'README.md'), encoding='utf-8') as f:
12 | long_description = f.read()
13 |
14 | setup(name='itermplot',
15 | packages=find_packages(),
16 | install_requires=[
17 | 'matplotlib',
18 | 'six',
19 | 'numpy'
20 | ],
21 | version='0.4',
22 | description='An awesome iTerm2 backend for Matplotlib, so you can plot directly in your terminal.',
23 | long_description=long_description,
24 | long_description_content_type='text/markdown',
25 | url='http://github.com/daleroberts/itermplot',
26 | author='Dale Roberts',
27 | author_email='dale.o.roberts@gmail.com',
28 | license='MIT',
29 | zip_safe=False)
30 |
--------------------------------------------------------------------------------