Coverage for /usr/lib/python3/dist-packages/sympy/printing/tableform.py: 8%
177 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from sympy.core.containers import Tuple
2from sympy.core.singleton import S
3from sympy.core.symbol import Symbol
4from sympy.core.sympify import SympifyError
6from types import FunctionType
9class TableForm:
10 r"""
11 Create a nice table representation of data.
13 Examples
14 ========
16 >>> from sympy import TableForm
17 >>> t = TableForm([[5, 7], [4, 2], [10, 3]])
18 >>> print(t)
19 5 7
20 4 2
21 10 3
23 You can use the SymPy's printing system to produce tables in any
24 format (ascii, latex, html, ...).
26 >>> print(t.as_latex())
27 \begin{tabular}{l l}
28 $5$ & $7$ \\
29 $4$ & $2$ \\
30 $10$ & $3$ \\
31 \end{tabular}
33 """
35 def __init__(self, data, **kwarg):
36 """
37 Creates a TableForm.
39 Parameters:
41 data ...
42 2D data to be put into the table; data can be
43 given as a Matrix
45 headings ...
46 gives the labels for rows and columns:
48 Can be a single argument that applies to both
49 dimensions:
51 - None ... no labels
52 - "automatic" ... labels are 1, 2, 3, ...
54 Can be a list of labels for rows and columns:
55 The labels for each dimension can be given
56 as None, "automatic", or [l1, l2, ...] e.g.
57 ["automatic", None] will number the rows
59 [default: None]
61 alignments ...
62 alignment of the columns with:
64 - "left" or "<"
65 - "center" or "^"
66 - "right" or ">"
68 When given as a single value, the value is used for
69 all columns. The row headings (if given) will be
70 right justified unless an explicit alignment is
71 given for it and all other columns.
73 [default: "left"]
75 formats ...
76 a list of format strings or functions that accept
77 3 arguments (entry, row number, col number) and
78 return a string for the table entry. (If a function
79 returns None then the _print method will be used.)
81 wipe_zeros ...
82 Do not show zeros in the table.
84 [default: True]
86 pad ...
87 the string to use to indicate a missing value (e.g.
88 elements that are None or those that are missing
89 from the end of a row (i.e. any row that is shorter
90 than the rest is assumed to have missing values).
91 When None, nothing will be shown for values that
92 are missing from the end of a row; values that are
93 None, however, will be shown.
95 [default: None]
97 Examples
98 ========
100 >>> from sympy import TableForm, Symbol
101 >>> TableForm([[5, 7], [4, 2], [10, 3]])
102 5 7
103 4 2
104 10 3
105 >>> TableForm([list('.'*i) for i in range(1, 4)], headings='automatic')
106 | 1 2 3
107 ---------
108 1 | .
109 2 | . .
110 3 | . . .
111 >>> TableForm([[Symbol('.'*(j if not i%2 else 1)) for i in range(3)]
112 ... for j in range(4)], alignments='rcl')
113 .
114 . . .
115 .. . ..
116 ... . ...
117 """
118 from sympy.matrices.dense import Matrix
120 # We only support 2D data. Check the consistency:
121 if isinstance(data, Matrix):
122 data = data.tolist()
123 _h = len(data)
125 # fill out any short lines
126 pad = kwarg.get('pad', None)
127 ok_None = False
128 if pad is None:
129 pad = " "
130 ok_None = True
131 pad = Symbol(pad)
132 _w = max(len(line) for line in data)
133 for i, line in enumerate(data):
134 if len(line) != _w:
135 line.extend([pad]*(_w - len(line)))
136 for j, lj in enumerate(line):
137 if lj is None:
138 if not ok_None:
139 lj = pad
140 else:
141 try:
142 lj = S(lj)
143 except SympifyError:
144 lj = Symbol(str(lj))
145 line[j] = lj
146 data[i] = line
147 _lines = Tuple(*[Tuple(*d) for d in data])
149 headings = kwarg.get("headings", [None, None])
150 if headings == "automatic":
151 _headings = [range(1, _h + 1), range(1, _w + 1)]
152 else:
153 h1, h2 = headings
154 if h1 == "automatic":
155 h1 = range(1, _h + 1)
156 if h2 == "automatic":
157 h2 = range(1, _w + 1)
158 _headings = [h1, h2]
160 allow = ('l', 'r', 'c')
161 alignments = kwarg.get("alignments", "l")
163 def _std_align(a):
164 a = a.strip().lower()
165 if len(a) > 1:
166 return {'left': 'l', 'right': 'r', 'center': 'c'}.get(a, a)
167 else:
168 return {'<': 'l', '>': 'r', '^': 'c'}.get(a, a)
169 std_align = _std_align(alignments)
170 if std_align in allow:
171 _alignments = [std_align]*_w
172 else:
173 _alignments = []
174 for a in alignments:
175 std_align = _std_align(a)
176 _alignments.append(std_align)
177 if std_align not in ('l', 'r', 'c'):
178 raise ValueError('alignment "%s" unrecognized' %
179 alignments)
180 if _headings[0] and len(_alignments) == _w + 1:
181 _head_align = _alignments[0]
182 _alignments = _alignments[1:]
183 else:
184 _head_align = 'r'
185 if len(_alignments) != _w:
186 raise ValueError(
187 'wrong number of alignments: expected %s but got %s' %
188 (_w, len(_alignments)))
190 _column_formats = kwarg.get("formats", [None]*_w)
192 _wipe_zeros = kwarg.get("wipe_zeros", True)
194 self._w = _w
195 self._h = _h
196 self._lines = _lines
197 self._headings = _headings
198 self._head_align = _head_align
199 self._alignments = _alignments
200 self._column_formats = _column_formats
201 self._wipe_zeros = _wipe_zeros
203 def __repr__(self):
204 from .str import sstr
205 return sstr(self, order=None)
207 def __str__(self):
208 from .str import sstr
209 return sstr(self, order=None)
211 def as_matrix(self):
212 """Returns the data of the table in Matrix form.
214 Examples
215 ========
217 >>> from sympy import TableForm
218 >>> t = TableForm([[5, 7], [4, 2], [10, 3]], headings='automatic')
219 >>> t
220 | 1 2
221 --------
222 1 | 5 7
223 2 | 4 2
224 3 | 10 3
225 >>> t.as_matrix()
226 Matrix([
227 [ 5, 7],
228 [ 4, 2],
229 [10, 3]])
230 """
231 from sympy.matrices.dense import Matrix
232 return Matrix(self._lines)
234 def as_str(self):
235 # XXX obsolete ?
236 return str(self)
238 def as_latex(self):
239 from .latex import latex
240 return latex(self)
242 def _sympystr(self, p):
243 """
244 Returns the string representation of 'self'.
246 Examples
247 ========
249 >>> from sympy import TableForm
250 >>> t = TableForm([[5, 7], [4, 2], [10, 3]])
251 >>> s = t.as_str()
253 """
254 column_widths = [0] * self._w
255 lines = []
256 for line in self._lines:
257 new_line = []
258 for i in range(self._w):
259 # Format the item somehow if needed:
260 s = str(line[i])
261 if self._wipe_zeros and (s == "0"):
262 s = " "
263 w = len(s)
264 if w > column_widths[i]:
265 column_widths[i] = w
266 new_line.append(s)
267 lines.append(new_line)
269 # Check heading:
270 if self._headings[0]:
271 self._headings[0] = [str(x) for x in self._headings[0]]
272 _head_width = max([len(x) for x in self._headings[0]])
274 if self._headings[1]:
275 new_line = []
276 for i in range(self._w):
277 # Format the item somehow if needed:
278 s = str(self._headings[1][i])
279 w = len(s)
280 if w > column_widths[i]:
281 column_widths[i] = w
282 new_line.append(s)
283 self._headings[1] = new_line
285 format_str = []
287 def _align(align, w):
288 return '%%%s%ss' % (
289 ("-" if align == "l" else ""),
290 str(w))
291 format_str = [_align(align, w) for align, w in
292 zip(self._alignments, column_widths)]
293 if self._headings[0]:
294 format_str.insert(0, _align(self._head_align, _head_width))
295 format_str.insert(1, '|')
296 format_str = ' '.join(format_str) + '\n'
298 s = []
299 if self._headings[1]:
300 d = self._headings[1]
301 if self._headings[0]:
302 d = [""] + d
303 first_line = format_str % tuple(d)
304 s.append(first_line)
305 s.append("-" * (len(first_line) - 1) + "\n")
306 for i, line in enumerate(lines):
307 d = [l if self._alignments[j] != 'c' else
308 l.center(column_widths[j]) for j, l in enumerate(line)]
309 if self._headings[0]:
310 l = self._headings[0][i]
311 l = (l if self._head_align != 'c' else
312 l.center(_head_width))
313 d = [l] + d
314 s.append(format_str % tuple(d))
315 return ''.join(s)[:-1] # don't include trailing newline
317 def _latex(self, printer):
318 """
319 Returns the string representation of 'self'.
320 """
321 # Check heading:
322 if self._headings[1]:
323 new_line = []
324 for i in range(self._w):
325 # Format the item somehow if needed:
326 new_line.append(str(self._headings[1][i]))
327 self._headings[1] = new_line
329 alignments = []
330 if self._headings[0]:
331 self._headings[0] = [str(x) for x in self._headings[0]]
332 alignments = [self._head_align]
333 alignments.extend(self._alignments)
335 s = r"\begin{tabular}{" + " ".join(alignments) + "}\n"
337 if self._headings[1]:
338 d = self._headings[1]
339 if self._headings[0]:
340 d = [""] + d
341 first_line = " & ".join(d) + r" \\" + "\n"
342 s += first_line
343 s += r"\hline" + "\n"
344 for i, line in enumerate(self._lines):
345 d = []
346 for j, x in enumerate(line):
347 if self._wipe_zeros and (x in (0, "0")):
348 d.append(" ")
349 continue
350 f = self._column_formats[j]
351 if f:
352 if isinstance(f, FunctionType):
353 v = f(x, i, j)
354 if v is None:
355 v = printer._print(x)
356 else:
357 v = f % x
358 d.append(v)
359 else:
360 v = printer._print(x)
361 d.append("$%s$" % v)
362 if self._headings[0]:
363 d = [self._headings[0][i]] + d
364 s += " & ".join(d) + r" \\" + "\n"
365 s += r"\end{tabular}"
366 return s