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

1from sympy.core.containers import Tuple 

2from sympy.core.singleton import S 

3from sympy.core.symbol import Symbol 

4from sympy.core.sympify import SympifyError 

5 

6from types import FunctionType 

7 

8 

9class TableForm: 

10 r""" 

11 Create a nice table representation of data. 

12 

13 Examples 

14 ======== 

15 

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 

22 

23 You can use the SymPy's printing system to produce tables in any 

24 format (ascii, latex, html, ...). 

25 

26 >>> print(t.as_latex()) 

27 \begin{tabular}{l l} 

28 $5$ & $7$ \\ 

29 $4$ & $2$ \\ 

30 $10$ & $3$ \\ 

31 \end{tabular} 

32 

33 """ 

34 

35 def __init__(self, data, **kwarg): 

36 """ 

37 Creates a TableForm. 

38 

39 Parameters: 

40 

41 data ... 

42 2D data to be put into the table; data can be 

43 given as a Matrix 

44 

45 headings ... 

46 gives the labels for rows and columns: 

47 

48 Can be a single argument that applies to both 

49 dimensions: 

50 

51 - None ... no labels 

52 - "automatic" ... labels are 1, 2, 3, ... 

53 

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 

58 

59 [default: None] 

60 

61 alignments ... 

62 alignment of the columns with: 

63 

64 - "left" or "<" 

65 - "center" or "^" 

66 - "right" or ">" 

67 

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. 

72 

73 [default: "left"] 

74 

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.) 

80 

81 wipe_zeros ... 

82 Do not show zeros in the table. 

83 

84 [default: True] 

85 

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. 

94 

95 [default: None] 

96 

97 Examples 

98 ======== 

99 

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 

119 

120 # We only support 2D data. Check the consistency: 

121 if isinstance(data, Matrix): 

122 data = data.tolist() 

123 _h = len(data) 

124 

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]) 

148 

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] 

159 

160 allow = ('l', 'r', 'c') 

161 alignments = kwarg.get("alignments", "l") 

162 

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))) 

189 

190 _column_formats = kwarg.get("formats", [None]*_w) 

191 

192 _wipe_zeros = kwarg.get("wipe_zeros", True) 

193 

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 

202 

203 def __repr__(self): 

204 from .str import sstr 

205 return sstr(self, order=None) 

206 

207 def __str__(self): 

208 from .str import sstr 

209 return sstr(self, order=None) 

210 

211 def as_matrix(self): 

212 """Returns the data of the table in Matrix form. 

213 

214 Examples 

215 ======== 

216 

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) 

233 

234 def as_str(self): 

235 # XXX obsolete ? 

236 return str(self) 

237 

238 def as_latex(self): 

239 from .latex import latex 

240 return latex(self) 

241 

242 def _sympystr(self, p): 

243 """ 

244 Returns the string representation of 'self'. 

245 

246 Examples 

247 ======== 

248 

249 >>> from sympy import TableForm 

250 >>> t = TableForm([[5, 7], [4, 2], [10, 3]]) 

251 >>> s = t.as_str() 

252 

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) 

268 

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]]) 

273 

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 

284 

285 format_str = [] 

286 

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' 

297 

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 

316 

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 

328 

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) 

334 

335 s = r"\begin{tabular}{" + " ".join(alignments) + "}\n" 

336 

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