##// END OF EJS Templates
Copyright fix on sympyprinting.py and latextools.py...
Takafumi Arakaki -
Show More
@@ -1,151 +1,151 b''
1 """
1 """
2 A print function that pretty prints sympy Basic objects.
2 A print function that pretty prints sympy Basic objects.
3
3
4 :moduleauthor: Brian Granger
4 :moduleauthor: Brian Granger
5
5
6 Usage
6 Usage
7 =====
7 =====
8
8
9 Once the extension is loaded, Sympy Basic objects are automatically
9 Once the extension is loaded, Sympy Basic objects are automatically
10 pretty-printed.
10 pretty-printed.
11
11
12 """
12 """
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 from IPython.lib.latextools import latex_to_png
24 from IPython.lib.latextools import latex_to_png
25 from IPython.testing import decorators as dec
25 from IPython.testing import decorators as dec
26 # use @dec.skipif_not_sympy to skip tests requiring sympy
26 # use @dec.skipif_not_sympy to skip tests requiring sympy
27
27
28 try:
28 try:
29 from sympy import pretty, latex
29 from sympy import pretty, latex
30 except ImportError:
30 except ImportError:
31 pass
31 pass
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Definitions of special display functions for use with IPython
34 # Definitions of special display functions for use with IPython
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 def print_basic_unicode(o, p, cycle):
37 def print_basic_unicode(o, p, cycle):
38 """A function to pretty print sympy Basic objects."""
38 """A function to pretty print sympy Basic objects."""
39 if cycle:
39 if cycle:
40 return p.text('Basic(...)')
40 return p.text('Basic(...)')
41 out = pretty(o, use_unicode=True)
41 out = pretty(o, use_unicode=True)
42 if '\n' in out:
42 if '\n' in out:
43 p.text(u'\n')
43 p.text(u'\n')
44 p.text(out)
44 p.text(out)
45
45
46
46
47 def print_png(o):
47 def print_png(o):
48 """
48 """
49 A function to display sympy expression using inline style LaTeX in PNG.
49 A function to display sympy expression using inline style LaTeX in PNG.
50 """
50 """
51 s = latex(o, mode='inline')
51 s = latex(o, mode='inline')
52 # mathtext does not understand certain latex flags, so we try to replace
52 # mathtext does not understand certain latex flags, so we try to replace
53 # them with suitable subs.
53 # them with suitable subs.
54 s = s.replace('\\operatorname','')
54 s = s.replace('\\operatorname','')
55 s = s.replace('\\overline', '\\bar')
55 s = s.replace('\\overline', '\\bar')
56 png = latex_to_png(s)
56 png = latex_to_png(s)
57 return png
57 return png
58
58
59
59
60 def print_display_png(o):
60 def print_display_png(o):
61 """
61 """
62 A function to display sympy expression using display style LaTeX in PNG.
62 A function to display sympy expression using display style LaTeX in PNG.
63 """
63 """
64 s = latex(o, mode='plain')
64 s = latex(o, mode='plain')
65 s = s.strip('$')
65 s = s.strip('$')
66 # As matplotlib does not support display style, dvipng backend is
66 # As matplotlib does not support display style, dvipng backend is
67 # used here.
67 # used here.
68 png = latex_to_png('$$%s$$' % s, backend='dvipng')
68 png = latex_to_png('$$%s$$' % s, backend='dvipng')
69 return png
69 return png
70
70
71
71
72 def can_print_latex(o):
72 def can_print_latex(o):
73 """
73 """
74 Return True if type o can be printed with LaTeX.
74 Return True if type o can be printed with LaTeX.
75
75
76 If o is a container type, this is True if and only if every element of o
76 If o is a container type, this is True if and only if every element of o
77 can be printed with LaTeX.
77 can be printed with LaTeX.
78 """
78 """
79 import sympy
79 import sympy
80 if isinstance(o, (list, tuple, set, frozenset)):
80 if isinstance(o, (list, tuple, set, frozenset)):
81 return all(can_print_latex(i) for i in o)
81 return all(can_print_latex(i) for i in o)
82 elif isinstance(o, dict):
82 elif isinstance(o, dict):
83 return all((isinstance(i, basestring) or can_print_latex(i)) and can_print_latex(o[i]) for i in o)
83 return all((isinstance(i, basestring) or can_print_latex(i)) and can_print_latex(o[i]) for i in o)
84 elif isinstance(o,(sympy.Basic, sympy.matrices.Matrix, int, long, float)):
84 elif isinstance(o,(sympy.Basic, sympy.matrices.Matrix, int, long, float)):
85 return True
85 return True
86 return False
86 return False
87
87
88 def print_latex(o):
88 def print_latex(o):
89 """A function to generate the latex representation of sympy
89 """A function to generate the latex representation of sympy
90 expressions."""
90 expressions."""
91 if can_print_latex(o):
91 if can_print_latex(o):
92 s = latex(o, mode='plain')
92 s = latex(o, mode='plain')
93 s = s.replace('\\dag','\\dagger')
93 s = s.replace('\\dag','\\dagger')
94 s = s.strip('$')
94 s = s.strip('$')
95 return '$$%s$$' % s
95 return '$$%s$$' % s
96 # Fallback to the string printer
96 # Fallback to the string printer
97 return None
97 return None
98
98
99 _loaded = False
99 _loaded = False
100
100
101 def load_ipython_extension(ip):
101 def load_ipython_extension(ip):
102 """Load the extension in IPython."""
102 """Load the extension in IPython."""
103 import sympy
103 import sympy
104 global _loaded
104 global _loaded
105 if not _loaded:
105 if not _loaded:
106 plaintext_formatter = ip.display_formatter.formatters['text/plain']
106 plaintext_formatter = ip.display_formatter.formatters['text/plain']
107
107
108 for cls in (object, str):
108 for cls in (object, str):
109 plaintext_formatter.for_type(cls, print_basic_unicode)
109 plaintext_formatter.for_type(cls, print_basic_unicode)
110
110
111 printable_containers = [list, tuple]
111 printable_containers = [list, tuple]
112
112
113 # set and frozen set were broken with SymPy's latex() function, but
113 # set and frozen set were broken with SymPy's latex() function, but
114 # was fixed in the 0.7.1-git development version. See
114 # was fixed in the 0.7.1-git development version. See
115 # http://code.google.com/p/sympy/issues/detail?id=3062.
115 # http://code.google.com/p/sympy/issues/detail?id=3062.
116 if sympy.__version__ > '0.7.1':
116 if sympy.__version__ > '0.7.1':
117 printable_containers += [set, frozenset]
117 printable_containers += [set, frozenset]
118 else:
118 else:
119 plaintext_formatter.for_type(cls, print_basic_unicode)
119 plaintext_formatter.for_type(cls, print_basic_unicode)
120
120
121 plaintext_formatter.for_type_by_name(
121 plaintext_formatter.for_type_by_name(
122 'sympy.core.basic', 'Basic', print_basic_unicode
122 'sympy.core.basic', 'Basic', print_basic_unicode
123 )
123 )
124 plaintext_formatter.for_type_by_name(
124 plaintext_formatter.for_type_by_name(
125 'sympy.matrices.matrices', 'Matrix', print_basic_unicode
125 'sympy.matrices.matrices', 'Matrix', print_basic_unicode
126 )
126 )
127
127
128 png_formatter = ip.display_formatter.formatters['image/png']
128 png_formatter = ip.display_formatter.formatters['image/png']
129
129
130 png_formatter.for_type_by_name(
130 png_formatter.for_type_by_name(
131 'sympy.core.basic', 'Basic', print_png
131 'sympy.core.basic', 'Basic', print_png
132 )
132 )
133 png_formatter.for_type_by_name(
133 png_formatter.for_type_by_name(
134 'sympy.matrices.matrices', 'Matrix', print_display_png
134 'sympy.matrices.matrices', 'Matrix', print_display_png
135 )
135 )
136 for cls in [dict, int, long, float] + printable_containers:
136 for cls in [dict, int, long, float] + printable_containers:
137 png_formatter.for_type(cls, print_png)
137 png_formatter.for_type(cls, print_png)
138
138
139 latex_formatter = ip.display_formatter.formatters['text/latex']
139 latex_formatter = ip.display_formatter.formatters['text/latex']
140 latex_formatter.for_type_by_name(
140 latex_formatter.for_type_by_name(
141 'sympy.core.basic', 'Basic', print_latex
141 'sympy.core.basic', 'Basic', print_latex
142 )
142 )
143 latex_formatter.for_type_by_name(
143 latex_formatter.for_type_by_name(
144 'sympy.matrices.matrices', 'Matrix', print_latex
144 'sympy.matrices.matrices', 'Matrix', print_latex
145 )
145 )
146
146
147 for cls in printable_containers:
147 for cls in printable_containers:
148 # Use LaTeX only if every element is printable by latex
148 # Use LaTeX only if every element is printable by latex
149 latex_formatter.for_type(cls, print_latex)
149 latex_formatter.for_type(cls, print_latex)
150
150
151 _loaded = True
151 _loaded = True
@@ -1,174 +1,174 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for handling LaTeX.
2 """Tools for handling LaTeX.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2010-2011, IPython Development Team.
9 # Copyright (C) 2010 IPython Development Team.
10 #
10 #
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12 #
12 #
13 # The full license is in the file COPYING.txt, distributed with this software.
13 # The full license is in the file COPYING.txt, distributed with this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from StringIO import StringIO
20 from StringIO import StringIO
21 from base64 import encodestring
21 from base64 import encodestring
22 import os
22 import os
23 import tempfile
23 import tempfile
24 import shutil
24 import shutil
25 import subprocess
25 import subprocess
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Tools
28 # Tools
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31
31
32 def latex_to_png(s, encode=False, backend='mpl'):
32 def latex_to_png(s, encode=False, backend='mpl'):
33 """Render a LaTeX string to PNG.
33 """Render a LaTeX string to PNG.
34
34
35 Parameters
35 Parameters
36 ----------
36 ----------
37 s : str
37 s : str
38 The raw string containing valid inline LaTeX.
38 The raw string containing valid inline LaTeX.
39 encode : bool, optional
39 encode : bool, optional
40 Should the PNG data bebase64 encoded to make it JSON'able.
40 Should the PNG data bebase64 encoded to make it JSON'able.
41 backend : {mpl, dvipng}
41 backend : {mpl, dvipng}
42 Backend for producing PNG data.
42 Backend for producing PNG data.
43
43
44 None is returned when the backend cannot be used.
44 None is returned when the backend cannot be used.
45
45
46 """
46 """
47 if backend == 'mpl':
47 if backend == 'mpl':
48 f = latex_to_png_mpl
48 f = latex_to_png_mpl
49 elif backend == 'dvipng':
49 elif backend == 'dvipng':
50 f = latex_to_png_dvipng
50 f = latex_to_png_dvipng
51 else:
51 else:
52 raise ValueError('No such backend {0}'.format(backend))
52 raise ValueError('No such backend {0}'.format(backend))
53 bin_data = f(s)
53 bin_data = f(s)
54 if encode and bin_data:
54 if encode and bin_data:
55 bin_data = encodestring(bin_data)
55 bin_data = encodestring(bin_data)
56 return bin_data
56 return bin_data
57
57
58
58
59 def latex_to_png_mpl(s):
59 def latex_to_png_mpl(s):
60 try:
60 try:
61 from matplotlib import mathtext
61 from matplotlib import mathtext
62 except ImportError:
62 except ImportError:
63 return None
63 return None
64
64
65 mt = mathtext.MathTextParser('bitmap')
65 mt = mathtext.MathTextParser('bitmap')
66 f = StringIO()
66 f = StringIO()
67 mt.to_png(f, s, fontsize=12)
67 mt.to_png(f, s, fontsize=12)
68 return f.getvalue()
68 return f.getvalue()
69
69
70
70
71 def latex_to_png_dvipng(s):
71 def latex_to_png_dvipng(s):
72 try:
72 try:
73 workdir = tempfile.mkdtemp()
73 workdir = tempfile.mkdtemp()
74 tmpfile = os.path.join(workdir, "tmp.tex")
74 tmpfile = os.path.join(workdir, "tmp.tex")
75 dvifile = os.path.join(workdir, "tmp.dvi")
75 dvifile = os.path.join(workdir, "tmp.dvi")
76 outfile = os.path.join(workdir, "tmp.png")
76 outfile = os.path.join(workdir, "tmp.png")
77
77
78 with open(tmpfile, "w") as f:
78 with open(tmpfile, "w") as f:
79 f.write(_latex_header)
79 f.write(_latex_header)
80 f.write(s)
80 f.write(s)
81 f.write(_latex_footer)
81 f.write(_latex_footer)
82
82
83 subprocess.check_call(
83 subprocess.check_call(
84 ["latex", "-halt-on-errror", tmpfile], cwd=workdir)
84 ["latex", "-halt-on-errror", tmpfile], cwd=workdir)
85
85
86 subprocess.check_call(
86 subprocess.check_call(
87 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
87 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
88 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir)
88 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir)
89
89
90 with open(outfile) as f:
90 with open(outfile) as f:
91 bin_data = f.read()
91 bin_data = f.read()
92 except subprocess.CalledProcessError:
92 except subprocess.CalledProcessError:
93 bin_data = None
93 bin_data = None
94 finally:
94 finally:
95 shutil.rmtree(workdir)
95 shutil.rmtree(workdir)
96 return bin_data
96 return bin_data
97
97
98
98
99 _latex_header = r'''
99 _latex_header = r'''
100 \documentclass{article}
100 \documentclass{article}
101 \usepackage{amsmath}
101 \usepackage{amsmath}
102 \usepackage{amsthm}
102 \usepackage{amsthm}
103 \usepackage{amssymb}
103 \usepackage{amssymb}
104 \usepackage{bm}
104 \usepackage{bm}
105 \pagestyle{empty}
105 \pagestyle{empty}
106 \begin{document}
106 \begin{document}
107 '''
107 '''
108
108
109 _latex_footer = r'\end{document}'
109 _latex_footer = r'\end{document}'
110
110
111
111
112 _data_uri_template_png = """<img src="data:image/png;base64,%s" alt=%s />"""
112 _data_uri_template_png = """<img src="data:image/png;base64,%s" alt=%s />"""
113
113
114 def latex_to_html(s, alt='image'):
114 def latex_to_html(s, alt='image'):
115 """Render LaTeX to HTML with embedded PNG data using data URIs.
115 """Render LaTeX to HTML with embedded PNG data using data URIs.
116
116
117 Parameters
117 Parameters
118 ----------
118 ----------
119 s : str
119 s : str
120 The raw string containing valid inline LateX.
120 The raw string containing valid inline LateX.
121 alt : str
121 alt : str
122 The alt text to use for the HTML.
122 The alt text to use for the HTML.
123 """
123 """
124 base64_data = latex_to_png(s, encode=True)
124 base64_data = latex_to_png(s, encode=True)
125 if base64_data:
125 if base64_data:
126 return _data_uri_template_png % (base64_data, alt)
126 return _data_uri_template_png % (base64_data, alt)
127
127
128
128
129 # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we
129 # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we
130 # will remove.
130 # will remove.
131 def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None):
131 def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None):
132 """
132 """
133 Given a math expression, renders it in a closely-clipped bounding
133 Given a math expression, renders it in a closely-clipped bounding
134 box to an image file.
134 box to an image file.
135
135
136 *s*
136 *s*
137 A math expression. The math portion should be enclosed in
137 A math expression. The math portion should be enclosed in
138 dollar signs.
138 dollar signs.
139
139
140 *filename_or_obj*
140 *filename_or_obj*
141 A filepath or writable file-like object to write the image data
141 A filepath or writable file-like object to write the image data
142 to.
142 to.
143
143
144 *prop*
144 *prop*
145 If provided, a FontProperties() object describing the size and
145 If provided, a FontProperties() object describing the size and
146 style of the text.
146 style of the text.
147
147
148 *dpi*
148 *dpi*
149 Override the output dpi, otherwise use the default associated
149 Override the output dpi, otherwise use the default associated
150 with the output format.
150 with the output format.
151
151
152 *format*
152 *format*
153 The output format, eg. 'svg', 'pdf', 'ps' or 'png'. If not
153 The output format, eg. 'svg', 'pdf', 'ps' or 'png'. If not
154 provided, will be deduced from the filename.
154 provided, will be deduced from the filename.
155 """
155 """
156 from matplotlib import figure
156 from matplotlib import figure
157 # backend_agg supports all of the core output formats
157 # backend_agg supports all of the core output formats
158 from matplotlib.backends import backend_agg
158 from matplotlib.backends import backend_agg
159 from matplotlib.font_manager import FontProperties
159 from matplotlib.font_manager import FontProperties
160 from matplotlib.mathtext import MathTextParser
160 from matplotlib.mathtext import MathTextParser
161
161
162 if prop is None:
162 if prop is None:
163 prop = FontProperties()
163 prop = FontProperties()
164
164
165 parser = MathTextParser('path')
165 parser = MathTextParser('path')
166 width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop)
166 width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop)
167
167
168 fig = figure.Figure(figsize=(width / 72.0, height / 72.0))
168 fig = figure.Figure(figsize=(width / 72.0, height / 72.0))
169 fig.text(0, depth/height, s, fontproperties=prop)
169 fig.text(0, depth/height, s, fontproperties=prop)
170 backend_agg.FigureCanvasAgg(fig)
170 backend_agg.FigureCanvasAgg(fig)
171 fig.savefig(filename_or_obj, dpi=dpi, format=format)
171 fig.savefig(filename_or_obj, dpi=dpi, format=format)
172
172
173 return depth
173 return depth
174
174
General Comments 0
You need to be logged in to leave comments. Login now