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