Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/misc/ascii_art.py
8814 views
1
# -*- coding: utf-8 -*-
2
r"""
3
ASCII Art
4
5
This file contains:
6
7
- :class:`AsciiArt` an simple implementation of an ASCII art object,
8
- :func:`ascii_art` a function to get the ASCII art representation of any
9
object in Sage,
10
- several others functions use to get ASCII art representation of primitive
11
python elements (list, tuple, dict, set).
12
13
AUTHOR:
14
15
- Jean-Baptiste Priez (2013-04): initial version
16
17
EXAMPLES::
18
19
sage: n = var('n')
20
sage: integrate(n^2/x,x)
21
n^2*log(x)
22
sage: ascii_art(integrate(n^2/x,x))
23
2
24
n *log(x)
25
sage: ascii_art(integrate(n^2/(pi*x),x))
26
2
27
n *log(x)
28
---------
29
pi
30
sage: ascii_art(list(Partitions(6)))
31
[ * ]
32
[ ** * ]
33
[ *** ** * * ]
34
[ **** *** * ** ** * * ]
35
[ ***** **** * *** ** * ** * * * ]
36
[ ******, * , ** , * , ***, * , * , **, * , * , * ]
37
38
This method :meth:`ascii_art` could be automatically use by the display hook
39
manager activated by the magic function: ``%display ascii_art``::
40
41
sage: from sage.misc.interpreter import get_test_shell
42
sage: shell = get_test_shell()
43
sage: shell.run_cell('%display ascii_art')
44
sage: shell.run_cell("i = var('i')")
45
sage: shell.run_cell('sum(factorial(i)*x^i, i, 0, 10)')
46
10 9 8 7 6 5 4 3
47
3628800*x + 362880*x + 40320*x + 5040*x + 720*x + 120*x + 24*x + 6*x
48
<BLANKLINE>
49
2
50
+ 2*x + x + 1
51
sage: shell.run_cell('3/(7*x)')
52
3
53
---
54
7*x
55
sage: shell.run_cell('list(Compositions(5))')
56
[ *
57
[ * ** * * *
58
[ * * ** *** * ** * * ** * *
59
[ * * * * ** ** *** **** * * ** *** * ** *
60
[ *, * , * , * , * , * , * , * , **, ** , ** , ** , ***, *** , ****,
61
<BLANKLINE>
62
]
63
]
64
]
65
]
66
***** ]
67
sage: shell.run_cell('%display simple')
68
69
::
70
71
. , , ...
72
.? .~?$NNO.II7. ..GOGG
73
., ~7NNI7NDG$ ...~~~MGG
74
..:IG.. ...G7:DDGNNDO.. ...7:~~~~GNN
75
.~~GGGGG... .O .=$+OD7GI$ ...GG:~+~~~~MG?M.7?
76
.~~~D~~GGGGDGOM$..~+IN=NDG.G::D~~~?~~~7?NDI:???G
77
.~~~~G:~~G~D:~NONGMMOGD$ND~~::I77~~$?++MN7G GI?D.
78
7+I~~DG~~~N:GNGGOD$7OIOOMII::~:I7?G+OGN7G $III?.
79
.7==I~~~++IN?+++?$7ND$==$G:G??????N$OG$ ~III?7
80
.$$+++?GG=+G?GDM?GOG:NGMGN7??????D$D~GODIII???.
81
D++++NG+DD$+=GGONGI$DNGDN??????,IN=DOGODN???.
82
, +~+++N??D$I+I=GNMDGDGNIINN??D+:::O~$GGGDIG?7
83
:DD.:::OG?G=I~~G7GNM7777NIGODDNNG:::I$GGGGG7??O.
84
~GDDM:::GGMG+?+~$NNN$7IG7NMNMMMN, =::I7GGGGGO???~
85
:GDND7?::OOM.D+O~GGDI77777DMGNM$. ~:,$IGGGGGO???DO.
86
OGDDNN.D77OO. $?7==GG777$7GNGMGO. NOIGGGGGO???G$.
87
.OODNNN,DIGDM$GGGGG==GGGGIGNDMDMG, IGIGGGDON???GG:
88
.GODNDM.G$I$IOIOMG$G$?GGGIO,7OD7GG. ,GDIGGG??????GGG.
89
.DGDNI7I7MDI+OOODN$$O,$7DMIN,,IOO77O. G?$DIGGG?ID???OGG
90
GGDNNMMO7GD+OOOGIMOG7::NN====:?MMNGIDD,..IINIGGG?I??DIOGG?
91
.7ODMMMN.G7IOGOOODIMG,,:::$=~==::7OGG~IGOMDGMNIGGG????.OG$G.
92
?ODDMNNNO,II$OGODMGDMM?:DMG==~MDINNM$.7$IONDGI?GGG????:$GGG.
93
.$MDMNNNNN..:?7GDDDGG,GGM?~:GGGDNND.GIM7D+GI$ON.:?GGG????$$OGG.
94
.7DNDDDNMDOGG.=IGGND=7II+N??::$GIIO,IIGMG?7I7G$ON?,IGGG????7GIGG.
95
~GGGDNMMOOGGG$MGMMGDGMDGM?,G:GNG,:IIIGDG7IGGGGG$+NMIGGO?????IGGG.
96
.GGGDDMM7OGNGMODMNDDDOO.MII?GI$7IIIIING7GGDMM.IGDG.G7GGGG??$?7GGG
97
.IGDDDDOINNGMGMDMNDDGDO...$OI+??7OIIIDDGN+$==I=GD ?,NGGGGN7????GGG
98
7GGNDM$GONDGDD$MMGNDN. G.:$$G$?$7II$GOO,O=+7O7O~N?OM?GGGGGD+??$GG
99
OOGDOI7DGMG..=~DG$DD. $,,$$$D??7ODOOOODG$777$G OGMM:GGGGGG??GGG.
100
.$GDDG?7DMOGDNNMGGDGG ..,=O7$GG$+O$$OG=+O:GI77G$. ...DIGGGGI?$GGG.
101
.OGGGGO7OGDGGNGGGDGG. O:,77$O$$$D $GN:7777GD ..$GGGG??GGG$.
102
.GGGGDI GD.~NOGDGGG MG,777G77D7 +$~D77777= ..7GGG???GGO.
103
GGD. .~NODN... ..D::77O$7G77 .OG:G???G7. 7$NOM??GG=.
104
. . . .+~~DD~77$G7OD7 .?GGO?$OM$D ?????DGG...
105
7I77DN$II7$M.G$G . .:G?==$G .?????D??~
106
. .:IIIGO7O$GN..O$ 7I=~+?I. =???7? GGIG
107
$,III7NGGNNNG, .O. O====7I. .DG??$?. GG?G
108
.$7III$77777$$~ . +====D$GG ~$???: .$GIG.
109
:.+IIII$77$G$$O,+ OI==+7I$7=.:??? .GG$.
110
,,III$I7?I7$$OG7D ?+,==+77G?$,???. GG?
111
?IIIII=+$I77777 .:++=+++O77:,??: GG.
112
.IIIIG+III77777. 7,=,++?II7$,?G .GO .
113
$OII7?OIIIIIO .I:++??IIIII???. I$ .
114
.DNGDMOIG777. +~++?I$IIMN?, .G,
115
.G.I?IIDGII~ .OG??$$MIMGI. G,
116
N+?II7OGI7. DD?$GGDGID. :
117
=?IIOOI$. ?~~GGG$II .+.
118
,7=IINGI ?=IGGGI?.
119
G,+IGOII ?+II7??+
120
.,:?IGOII ?+GIOII
121
.:N+=?IMGI7=. .~:$I?IO.
122
.$:IGO?$IIIII7+. O::I7I?.
123
.:::=IIGIIIIIII. .~,$IG?IO
124
.+:$IIIIMIII7G$?. I::I7IIG7
125
.$I$+7IIIMMMG7I7 ?G,DGGNII.
126
.$~:$IIGMNGND77I: +I$GOD=?=
127
?=?IIIIGIIIINI7777? .7~=~===?.
128
ONGNDG??IG?III$N7I777 D~====I
129
.:$??7IIIIIII.....,.... O::==~$D.
130
.,........ .. ..M:I.==$7G.
131
I?::IIIII7.
132
.~:G:IIIIIG.
133
.$:,O7III$$O
134
::~DOGGNNO
135
.::,IOODI,
136
.7????$.
137
... .
138
"""
139
#*******************************************************************************
140
# Copyright (C) 2013 Jean-Baptiste Priez <[email protected]>,
141
#
142
# Distributed under the terms of the GNU General Public License (GPL)
143
#
144
# This code is distributed in the hope that it will be useful,
145
# but WITHOUT ANY WARRANTY; without even the implied warranty of
146
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
147
# General Public License for more details.
148
#
149
# The full text of the GPL is available at:
150
#
151
# http://www.gnu.org/licenses/
152
#*******************************************************************************
153
from sage.structure.sage_object import SageObject
154
from sage.rings.integer import Integer
155
156
################################################################################
157
### Global variable use to compute the maximal length allows for ascii art
158
### object.
159
MAX_WIDTH = None
160
################################################################################
161
162
class AsciiArt(SageObject):
163
r"""
164
An Ascii art object is an object with some specific representation for
165
*printing*.
166
167
INPUT:
168
169
- ``lines`` -- the list of lines of the representation of the ascii art
170
object
171
- ``breakpoints`` -- the list of points where the representation can be
172
split
173
- ``baseline`` -- the reference line (from the bottom)
174
- ``atomic`` -- indicate if the ascii art representation is splittable
175
(must be coherent with breakpoints)
176
177
EXAMPLES::
178
179
sage: i = var('i')
180
sage: ascii_art(sum(pi^i/factorial(i)*x^i, i, 0, oo))
181
pi*x
182
e
183
"""
184
def __init__(self, lines=[], breakpoints=[], baseline=None, atomic=True):
185
r"""
186
TESTS::
187
188
sage: from sage.misc.ascii_art import AsciiArt
189
sage: aao = AsciiArt()
190
sage: aao.is_atomic()
191
True
192
sage: aao
193
<BLANKLINE>
194
sage: aa = AsciiArt([" * ", " * * ", "*****"]); aa
195
*
196
* *
197
*****
198
"""
199
self._is_uniq = True
200
self._matrix = lines
201
self._breakpoints = breakpoints
202
self._baseline = baseline if baseline != None else 0
203
self._is_atomic = atomic
204
205
self._h = len(lines)
206
self._l = max(map(lambda line: len(line), lines) + [0])
207
208
def __getitem__(self, key):
209
r"""
210
Return the line `key` of the ASCII art object.
211
212
TESTS::
213
214
sage: from sage.misc.ascii_art import AsciiArt
215
sage: p5 = AsciiArt([" * ", " * * ", "*****"])
216
sage: p5[1]
217
' * * '
218
"""
219
return self._matrix[key]
220
221
def __iter__(self):
222
r"""
223
Iterator on all lines of the ASCII art object.
224
225
TESTS::
226
227
sage: from sage.misc.ascii_art import AsciiArt
228
sage: p5 = AsciiArt([" * ", " * * ", "*****"])
229
sage: for line in p5:
230
....: print line
231
*
232
* *
233
*****
234
"""
235
for elem in self._matrix:
236
yield elem
237
238
def _repr_(self):
239
r"""
240
TESTS::
241
242
sage: from sage.misc.ascii_art import AsciiArt
243
sage: p5 = AsciiArt([" * ", " * * ", "*****"])
244
sage: repr(p5)
245
' * \n * * \n*****'
246
"""
247
#return "\n".join(self._matrix)
248
import os
249
# Compute the max length of a draw
250
global MAX_WIDTH
251
if MAX_WIDTH is not None:
252
hsize = MAX_WIDTH
253
else:
254
hsize = self._terminal_width()
255
#########
256
# if the draw is larger than the max length it try to split...
257
if hsize <= self._l and len(self._breakpoints) > 0:
258
return self._split_repr_(hsize)
259
#########
260
output = ""
261
if len(self._matrix) > 0:
262
for i in range(len(self._matrix) - 1):
263
output += self._matrix[i] + "\n"
264
return output + self._matrix[len(self._matrix) - 1]
265
return output
266
267
268
def is_atomic(self):
269
r"""
270
Return ``True`` if the :class:`AsciiArt` object is not splitable and
271
``False`` in otherwise.
272
273
For example, we considere a linear expression::
274
275
sage: a = 14*x^5 + 5*x^4
276
sage: ascii_art(a)
277
5 4
278
14*x + 5*x
279
280
If ASCII art object is not atomic, it is splittable on the ``+``
281
(in fact it is not really true because we use ``sympy`` to make
282
ASCII art).
283
284
TESTS::
285
286
sage: from sage.misc.ascii_art import AsciiArt
287
sage: aa = AsciiArt([" * ", " * * ", "*****"]); aa
288
*
289
* *
290
*****
291
sage: aa.is_atomic()
292
True
293
sage: laa = ascii_art([aa,aa])
294
sage: laa.is_atomic()
295
False
296
"""
297
return self._is_atomic
298
299
def get_baseline(self):
300
r"""
301
Return the line where the baseline is, for example::
302
303
5 4
304
14*x + 5*x
305
306
the baseline has at line `0` and ::
307
308
{ o }
309
{ \ : 4 }
310
{ o }
311
312
has at line `1`.
313
314
TESTS::
315
316
sage: from sage.misc.ascii_art import AsciiArt
317
sage: aa = AsciiArt([" * ", " * * ", " * * ", "*******"], baseline=1);aa
318
*
319
* *
320
* *
321
*******
322
sage: aa.get_baseline()
323
1
324
sage: b = AsciiArt(["<-"])
325
sage: aa+b
326
*
327
* *
328
* * <-
329
*******
330
"""
331
return self._baseline
332
333
def get_breakpoints(self):
334
r"""
335
Return an iterator of breakpoints where the object can be split.
336
337
For example the expression::
338
339
5 4
340
14x + 5x
341
342
can be split on position 4 (on the ``+``).
343
344
EXAMPLES::
345
346
sage: from sage.misc.ascii_art import AsciiArt
347
sage: p3 = AsciiArt([" * ", "***"])
348
sage: p5 = AsciiArt([" * ", " * * ", "*****"])
349
sage: aa = ascii_art([p3, p5])
350
sage: aa.get_breakpoints()
351
[2, 5, 6, 7, 12]
352
"""
353
return self._breakpoints
354
355
def _terminal_width(self):
356
"""
357
Compute the width size of the terminal.
358
359
EXAMPLES::
360
361
sage: from sage.misc.ascii_art import empty_ascii_art
362
sage: empty_ascii_art._terminal_width()
363
80
364
"""
365
import os, sys
366
from sage.doctest.__init__ import DOCTEST_MODE
367
isatty = os.isatty(sys.stdout.fileno())
368
if DOCTEST_MODE or not isatty:
369
return 80
370
import fcntl, termios, struct
371
rc = fcntl.ioctl(int(0), termios.TIOCGWINSZ,
372
struct.pack('HHHH', sys.stdout.fileno(), 0, 0, 0))
373
h, w, hp, wp = struct.unpack('HHHH', rc)
374
return w
375
376
def _split_repr_(self, size):
377
r"""
378
Split the draw and the left part has length ``size``.
379
380
TESTS::
381
382
sage: from sage.misc.ascii_art import AsciiArt
383
sage: p3 = AsciiArt([" * ", "***"])
384
sage: p5 = AsciiArt([" * ", " * * ", "*****"])
385
sage: aa = ascii_art([p3, p5])
386
sage: print aa._split_repr_(6)
387
[
388
[ *
389
[ ***
390
<BLANKLINE>
391
* ]
392
* * ]
393
, ***** ]
394
"""
395
import sys
396
f_split = self._breakpoints[0]; i = 1
397
while i < len(self._breakpoints) and self._breakpoints[i] < size:
398
f_split = self._breakpoints[i]
399
i += 1
400
if size <= f_split:
401
import warnings
402
warnings.warn("the console size is smaller than the pretty" +
403
"representation of the object")
404
top, bottom = self.split(f_split)
405
return (top * AsciiArt([""])).__repr__() + "\n" + bottom.__repr__()
406
407
def split(self, pos):
408
r"""
409
Split the representation at the position ``pos``.
410
411
EXMAPLES::
412
413
sage: from sage.misc.ascii_art import AsciiArt
414
sage: p3 = AsciiArt([" * ", "***"])
415
sage: p5 = AsciiArt([" * ", " * * ", "*****"])
416
sage: aa = ascii_art([p3, p5])
417
sage: a,b= aa.split(6)
418
sage: a
419
[
420
[ *
421
[ ***,
422
sage: b
423
* ]
424
* * ]
425
***** ]
426
"""
427
left = []; right = []
428
for line in self:
429
left.append(line[:pos])
430
right.append(line[pos:])
431
l_bp = []; r_bp = []
432
for bp in self._breakpoints:
433
if bp < pos:
434
l_bp.append(bp)
435
elif bp > pos:
436
r_bp.append(bp - pos)
437
return AsciiArt(left, l_bp), AsciiArt(right, r_bp)
438
439
@staticmethod
440
def _compute_new_baseline(obj1, obj2):
441
r"""
442
TESTS::
443
444
sage: from sage.misc.ascii_art import AsciiArt
445
sage: l5 = AsciiArt(lines = ['|' for _ in range(5)], baseline = 2); l5
446
|
447
|
448
|
449
|
450
|
451
sage: l3 = AsciiArt(lines = ['|' for _ in range(3)], baseline = 1); l3
452
|
453
|
454
|
455
sage: AsciiArt._compute_new_baseline(l5, l3)
456
2
457
sage: l5 + l3
458
|
459
||
460
||
461
||
462
|
463
sage: l5._baseline = 0
464
sage: AsciiArt._compute_new_baseline(l5, l3)
465
1
466
sage: l5 + l3
467
|
468
|
469
|
470
||
471
||
472
|
473
sage: l5._baseline = 4
474
sage: AsciiArt._compute_new_baseline(l5, l3)
475
4
476
sage: l5 + l3
477
|
478
||
479
||
480
|
481
|
482
|
483
sage: l3._baseline = 0
484
sage: AsciiArt._compute_new_baseline(l3, l5)
485
4
486
sage: l3 + l5
487
|
488
|
489
||
490
|
491
|
492
|
493
|
494
sage: l5._baseline = None
495
sage: AsciiArt._compute_new_baseline(l3, l5)
496
2
497
sage: l3._baseline = 2
498
sage: AsciiArt._compute_new_baseline(l3, l5)
499
4
500
sage: l3 + l5
501
||
502
||
503
||
504
|
505
|
506
507
"""
508
if obj1.get_baseline() is None:
509
if obj2.get_baseline() is None:
510
return None
511
return obj2.get_baseline() + max(obj1._h - obj2._h, 0)
512
if obj2.get_baseline() is None:
513
return obj1.get_baseline() + max(obj2._h - obj1._h, 0)
514
return max(
515
obj1.get_baseline(),
516
obj2.get_baseline()
517
)
518
519
@staticmethod
520
def _compute_new_h(obj1, obj2):
521
r"""
522
TESTS::
523
524
sage: from sage.misc.ascii_art import AsciiArt
525
sage: l5 = AsciiArt(lines=['|' for _ in range(5)], baseline=2); l5
526
|
527
|
528
|
529
|
530
|
531
sage: l3 = AsciiArt(lines=['|' for _ in range(3)], baseline=1); l3
532
|
533
|
534
|
535
sage: AsciiArt._compute_new_h(l5, l3)
536
5
537
sage: l5 + l3
538
|
539
||
540
||
541
||
542
|
543
sage: l5._baseline = 0
544
sage: AsciiArt._compute_new_h(l5, l3)
545
6
546
sage: l5 + l3
547
|
548
|
549
|
550
||
551
||
552
|
553
sage: l5._baseline = 4
554
sage: AsciiArt._compute_new_h(l5, l3)
555
6
556
sage: l5 + l3
557
|
558
||
559
||
560
|
561
|
562
|
563
sage: l3._baseline = 0
564
sage: AsciiArt._compute_new_h(l3, l5)
565
7
566
sage: l3 + l5
567
|
568
|
569
||
570
|
571
|
572
|
573
|
574
"""
575
if obj1.get_baseline() is None or obj2.get_baseline() is None:
576
return max(obj1._h, obj2._h)
577
return max(
578
obj1.get_baseline(),
579
obj2.get_baseline()
580
) + max(
581
obj1._h - obj1.get_baseline(),
582
obj2._h - obj2.get_baseline()
583
)
584
585
def __len__(self):
586
r"""
587
Return the length of the ASCII art object.
588
589
TESTS::
590
591
sage: from sage.misc.ascii_art import AsciiArt
592
sage: p3 = AsciiArt([" * ", "***"])
593
sage: len(p3)
594
3
595
sage: p5 = AsciiArt([" * ", " * * ", "*****"])
596
sage: len(p5)
597
5
598
"""
599
return self._l
600
601
def __add__(self, Nelt):
602
r"""
603
Concatenate two ascii art object.
604
605
By default, when two object are concatenated, the new one will be
606
splittable between both.
607
608
If the baseline is defined, the concatenation is computed such that the
609
new baseline coincidate with the olders.
610
611
For example, let `T` be a tree with it's baseline ascii art
612
representation in the middle::
613
614
o
615
\
616
o
617
/ \
618
o o
619
620
and let `M` be a matrix with it's baseline ascii art representation at
621
the middle two::
622
623
[1 2 3]
624
[4 5 6]
625
[7 8 9]
626
627
then the concatenation of both will give::
628
629
o
630
\ [1 2 3]
631
o [4 5 6]
632
/ \ [7 8 9]
633
o o
634
635
If one of the objects has not baseline, the concatenation is realized
636
from the top::
637
638
o [1 2 3]
639
\ [4 5 6]
640
o [7 8 9]
641
/ \
642
o o
643
644
TESTS::
645
646
sage: from sage.misc.ascii_art import AsciiArt
647
sage: l5 = AsciiArt(lines=['|' for _ in range(5)], baseline=2); l5
648
|
649
|
650
|
651
|
652
|
653
sage: l3 = AsciiArt(lines=['|' for _ in range(3)], baseline=1); l3
654
|
655
|
656
|
657
sage: l3 + l5
658
|
659
||
660
||
661
||
662
|
663
sage: l5 + l3
664
|
665
||
666
||
667
||
668
|
669
sage: l5._baseline = 0
670
sage: l5 + l3
671
|
672
|
673
|
674
||
675
||
676
|
677
sage: l5._baseline = 4
678
sage: l5 + l3
679
|
680
||
681
||
682
|
683
|
684
|
685
sage: l3._baseline = 0
686
sage: l3 + l5
687
|
688
|
689
||
690
|
691
|
692
|
693
|
694
"""
695
new_matrix = []
696
new_h = AsciiArt._compute_new_h(self, Nelt)
697
new_baseline = AsciiArt._compute_new_baseline(self, Nelt)
698
699
if self._baseline != None and Nelt._baseline != None:
700
# left traitement
701
for line in self._matrix:
702
new_matrix.append(line + " "** Integer(self._l - len(line)))
703
704
if new_h > self._h:
705
# | new_h > self._h
706
# | new_baseline > self._baseline
707
# ||<-- baseline number of white lines at the bottom
708
# | } :: Nelt._baseline - self._baseline
709
# | }
710
if new_baseline > self._baseline:
711
for k in range(new_baseline - self._baseline):
712
new_matrix.append(" " ** Integer(self._l))
713
# | } new_h > self._h
714
# | } new_h - new_baseline > self._h - self._baseline
715
# ||<-- baseline number of white lines at the top
716
# || :: new_h - new_baseline - self._h + self._baseline
717
# ||
718
# |
719
# |
720
if new_h - new_baseline > self._h - self._baseline:
721
for _ in range((new_h - new_baseline) - (self._h - self._baseline)):
722
new_matrix.insert(0, " " ** Integer(self._l))
723
724
# right traitement
725
i = 0
726
if new_h > Nelt._h:
727
# | } new_h > Nelt._h
728
# | } new_h - new_baseline > Nelt._h - self._baseline
729
# ||<-- baseline number of white lines at the top
730
# || :: new_h - new_baseline - Nelt._h + Nelt._baseline
731
# ||
732
# ||
733
# |
734
735
i = max(new_h - new_baseline - Nelt._h + Nelt._baseline , 0)
736
737
for j in range(Nelt._h):
738
new_matrix[i+j] += Nelt._matrix[j]
739
else:
740
for line in self._matrix:
741
new_matrix.append(line + " " ** Integer(self._l - len(line)))
742
for i, line_i in enumerate(Nelt._matrix):
743
if i == len(new_matrix):
744
new_matrix.append(" "**Integer(self._l) + line_i)
745
else: new_matrix[i] += line_i
746
747
# breakpoint
748
new_breakpoints = list(self._breakpoints)
749
new_breakpoints.append(self._l)
750
for bp in Nelt._breakpoints:
751
new_breakpoints.append(bp + self._l)
752
from sage.misc.misc import uniq
753
return AsciiArt(
754
lines = new_matrix,
755
breakpoints = uniq(new_breakpoints),
756
baseline = new_baseline,
757
atomic = False
758
)
759
760
def __mul__(self, Nelt):
761
r"""
762
The operator ``*`` is use to the representation ``self`` at
763
the top of an other ``Nelt``.
764
765
TESTS::
766
767
sage: from sage.misc.ascii_art import AsciiArt
768
sage: cub = AsciiArt(lines=['***' for _ in range(3)]); cub
769
***
770
***
771
***
772
sage: pyr = AsciiArt(lines=[' ^ ', '/ \\', '---']); pyr
773
^
774
/ \
775
---
776
sage: cub * pyr
777
***
778
***
779
***
780
^
781
/ \
782
---
783
"""
784
new_repr = AsciiArt(self._matrix + Nelt._matrix)
785
return new_repr
786
787
############## PRIMITIVES ################
788
789
def ascii_art(obj):
790
r"""
791
Return an ASCII art reprensentation of ``obj``::
792
793
sage: ascii_art(integral(exp(x+x^2)/(x+1), x))
794
/
795
|
796
| 2
797
| x + x
798
| e
799
| ------- dx
800
| x + 1
801
|
802
/
803
804
TESTS::
805
806
sage: n = var('n')
807
sage: ascii_art(sum(binomial(2 * n, n + 1) * x^n, n, 0, oo))
808
/ __________ \
809
-\2*x + \/ -4*x + 1 - 1/
810
--------------------------
811
__________
812
2*x*\/ -4*x + 1
813
sage: ascii_art(list(DyckWords(3)))
814
[ /\ ]
815
[ /\ /\ /\/\ / \ ]
816
[ /\/\/\, /\/ \, / \/\, / \, / \ ]
817
sage: ascii_art(1)
818
1
819
"""
820
if isinstance(obj, (tuple, list, dict, set)):
821
if obj.__class__ is tuple:
822
return ascii_art_tuple(obj)
823
elif obj.__class__ is dict:
824
return ascii_art_dict(obj)
825
elif obj.__class__ is list:
826
return ascii_art_list(obj)
827
else:
828
return ascii_art_set(obj)
829
if isinstance(obj, SageObject):
830
res = obj._ascii_art_()
831
else: res = AsciiArt(str(obj).splitlines())
832
return res
833
834
def _ascii_art_iter(iter, func=lambda elem, _: ascii_art(elem)):
835
r"""
836
Intermediate function for ``ascii_art_X`` where ``X`` is ``dict``,
837
``set``, ``list``, or ``tuple``.
838
839
TESTS::
840
841
sage: ascii_art(list(DyckWords(3)))
842
[ /\ ]
843
[ /\ /\ /\/\ / \ ]
844
[ /\/\/\, /\/ \, / \/\, / \, / \ ]
845
"""
846
repr_elems = AsciiArt([""])
847
bool = False
848
for elem in iter:
849
if bool:
850
#print repr_elems.get_baseline()
851
if repr_elems._baseline != None:
852
repr_elems += AsciiArt(
853
["" ** Integer(repr_elems._h - 1 - repr_elems._baseline) ] +
854
[", "],
855
baseline=repr_elems._baseline)
856
else:
857
repr_elems += AsciiArt(
858
(["" ** Integer(repr_elems._h - 1) ] if repr_elems._h > 1 else [])+
859
[", "],
860
baseline=repr_elems._baseline)
861
repr_elems._breakpoints.append(repr_elems._l - 1)
862
repr_elems += func(elem, iter)
863
bool = True
864
return repr_elems
865
866
def ascii_art_set(set):
867
r"""
868
Return an ASCII art output of a set.
869
870
TESTS::
871
872
sage: ascii_art(set(DyckWords(3)))
873
{ /\ }
874
{ /\ /\/\ /\ / \ }
875
{ / \/\, / \, /\/\/\, /\/ \, / \ }
876
"""
877
repr_elems = _ascii_art_iter(set)
878
return _ascii_art_with_borders(repr_elems, "{ ", " }")
879
880
def ascii_art_dict(dict):
881
r"""
882
Return an ASCII art output of a dictionnary.
883
884
TESTS::
885
886
sage: ascii_art({i:dw for i,dw in enumerate(DyckWords(3))})
887
{ /\ }
888
{ /\ /\ /\/\ / \ }
889
{ 0:/\/\/\, 1:/\/ \, 2:/ \/\, 3:/ \, 4:/ \ }
890
"""
891
def func(k, dict):
892
return ascii_art(k) + AsciiArt([":"], baseline=0) + ascii_art(dict[k])
893
repr_elems = _ascii_art_iter(dict, func)
894
return _ascii_art_with_borders(repr_elems, "{ ", " }")
895
896
def _ascii_art_with_borders(repr_elems, l_border, r_border):
897
r"""
898
Intermediate function for elements with borders.
899
900
TESTS::
901
902
sage: ascii_art(list(DyckWords(3)))
903
[ /\ ]
904
[ /\ /\ /\/\ / \ ]
905
[ /\/\/\, /\/ \, / \/\, / \, / \ ]
906
"""
907
new_mat = []
908
for line in repr_elems:
909
new_mat.append(l_border + line + " "**Integer(len(repr_elems) - len(line)) + r_border)
910
new_bp = [bp + 2 for bp in repr_elems.get_breakpoints()] + [len(repr_elems) + 2]
911
return AsciiArt(new_mat, new_bp, baseline = 0, atomic = False)
912
913
def ascii_art_list(list):
914
r"""
915
Return an ASCII art output of a list.
916
917
TESTS::
918
919
sage: ascii_art(list(DyckWords(3)))
920
[ /\ ]
921
[ /\ /\ /\/\ / \ ]
922
[ /\/\/\, /\/ \, / \/\, / \, / \ ]
923
"""
924
repr_elems = _ascii_art_iter(list)
925
return _ascii_art_with_borders(repr_elems, "[ ", " ]")
926
927
def ascii_art_tuple(tuple):
928
r"""
929
Return an ASCII art output of a tuple.
930
931
TESTS::
932
933
sage: ascii_art(tuple(DyckWords(3)))
934
( /\ )
935
( /\ /\ /\/\ / \ )
936
( /\/\/\, /\/ \, / \/\, / \, / \ )
937
"""
938
repr_elems = _ascii_art_iter(tuple)
939
return _ascii_art_with_borders(repr_elems, "( ", " )")
940
941
empty_ascii_art = AsciiArt([""])
942
943
944