Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty Console Output --> ascii art #14266

Closed
sagetrac-elixyre mannequin opened this issue Mar 13, 2013 · 85 comments
Closed

Pretty Console Output --> ascii art #14266

sagetrac-elixyre mannequin opened this issue Mar 13, 2013 · 85 comments

Comments

@sagetrac-elixyre
Copy link
Mannequin

sagetrac-elixyre mannequin commented Mar 13, 2013

My patch creates a simple ascii-art module to manipule several structure: list,dict,tuple, linear expression:

sage: R = NonCommutativeSymmetricFunctions(QQ).R()
sage: R[1]**5
R  + R   + R   + R    + R   + R    + R    + R     + R   + R    +
 *    **     *    ***     *     **      *    ****     *     **  
 *    *     **    *       *    **     ***    *        *     *   
 *    *     *     *      **    *      *               *    **   
 *    *     *            *                           **
 *

 R    + R     + R    + R     + R     + R
    *     ***      *      **       *    *****
   **    **        *    ***     ****
  **             ***

Apply:

Depends on #8703
Depends on #14203
Depends on #14574

CC: @nthiery @VivianePons

Component: user interface

Keywords: ascii-art

Author: Jean-Baptiste Priez

Reviewer: Volker Braun, Travis Scrimshaw

Merged: sage-5.11.beta0

Issue created by migration from https://trac.sagemath.org/ticket/14266

@sagetrac-elixyre sagetrac-elixyre mannequin added this to the sage-5.10 milestone Mar 13, 2013
@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Mar 13, 2013

patch

@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Mar 13, 2013

Attachment: pretty_console_print-EliX-jbp.patch.gz

several examples (some not in the patch)

@vbraun
Copy link
Member

vbraun commented Mar 13, 2013

comment:1

Attachment: pcp_monkey_patch.py.gz

Whats the difference between _repr_, _pretty_repr_normal_, and _pretty_repr_term_? I think there should be only one _repr_, using ascii art unconditionally if printing the object benefits from it. Why would you want to turn it off? I don't see the need for a different display handler, we aleady have one that does handle ascii art.

@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Mar 13, 2013

comment:2

I implement _pretty_repr_ to introduce a special ascii-art method (like in mupad) and I prefere let the method _repr_ to allow differents use. In general case, we can copy the ouput and re-use it in terminal (it is very usefull I think).
Then I put a method _pretty_repr_term_ like we have _repr_term_ for a linear expression.

I saw your handle ascii art and I try to send you a mail to merge that.... (no??).

@vbraun
Copy link
Member

vbraun commented Mar 13, 2013

comment:3

I saw your email but #14040 has already been merged. What I'm saying is, there should be more integration into the existing framework and less reinventing the wheel. Also nobody wants an ugly representation. You can't copy/paste matrices either. To get an input that recreates the object, we already have

sage: m = matrix(ZZ, [[0, 0, 0], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])
sage: m
[0 0 0]
[0 0 0]
[1 0 0]
[0 1 0]
[0 0 1]
sage: sage_input(m)
matrix(ZZ, [[0, 0, 0], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])

@vbraun
Copy link
Member

vbraun commented Mar 13, 2013

comment:4

How about a %magic to switch to the sage input representation to the displayhook, e.g.:

sage: %sage_input on
sage: m = matrix(ZZ, [[0, 0, 0], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])
sage: m
matrix(ZZ, [[0, 0, 0], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])

or perhaps both (if sage_input differs from _repr_)

@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Mar 13, 2013

comment:5

I don't reinventing the wheel... Then I prefere a nice LaTeX representation too but with some objects the LaTeX compilation is very slow.
Then thanks to the method

sage: sage_input(m)

I didn't know but... after try...

sage: R = NonCommutativeSymmetricFunctions(QQ).R()
sage: a = R[1]**3; a
R  + R   + R   + R
 *    **     *    ***
 *    *     **
 *
sage: %pcp
'Pretty Console Print' is uninstalled
sage: sage_input(a)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-10-7eccf1bd1684> in <module>()
----> 1 sage_input(a)

/home/priezjea/sage-5.8.beta4/local/lib/python2.7/site-packages/sage/misc/sage_input.pyc in sage_input(x, preparse, verify, allow_locals)
    252     if not verify:
    253         sib = SageInputBuilder(allow_locals=allow_locals, preparse=preparse)
--> 254         return sib.result(sib(x))
    255 
    256     # In verify mode, we actually compute and verify the answer with

/home/priezjea/sage-5.8.beta4/local/lib/python2.7/site-packages/sage/misc/sage_input.pyc in __call__(self, x, coerced)
    540             return SIE_literal_stringrep(self, loc_name)
    541         else:
--> 542             raise ValueError, "Can't convert %r to sage_input form"%x
    543 
    544     def preparse(self):

ValueError: Can't convert R[1, 1, 1] + R[1, 2] + R[2, 1] + R[3] to sage_input form

and

sage: R[1]**3
R[1, 1, 1] + R[1, 2] + R[2, 1] + R[3]

can be easily be copy.

So I don't say I invented something... I just purpose something to work (In my case) easily with linear combination.

@vbraun
Copy link
Member

vbraun commented Mar 13, 2013

comment:6

So the bug is that NonCommutativeSymmetricFunctions doesn't define its own Sage input representation (define _sage_input_). The ascii art should be the default (and only) print representation.

@vbraun vbraun changed the title Simple Ascii-Art Fix sage_input and pretty print for NonCommutativeSymmetricFunctions, others. Mar 13, 2013
@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Mar 14, 2013

comment:7

I like the idea of a magic function "%sage_input on". And if every thing is ascii-art... I have some question:

1 - The _repr_ method return (and must return) a string and it is too poor to produce an efficient and usefull ascii-art output. We could image use some baseline notion or ... My opinion is an ascii-art output must be a special class like PrettyConsoleRepr or whatever which can be improve by heritage. (That is not available with string.) --> That why my opinion is we don't have to use _repr_ but anything else.

2 - How to use your code to get (easily) a list, a dict or whatever of some objects with an ascii-art output ? Your code implement only a hack for Matrix (or it was before...) no? --> If it is true my code suggests a solution (may be a bad one...)

(Sorry for my very bad english)

@VivianePons
Copy link

comment:8

I am a bit new on this discussion, but I want to add my contribution.

I think having _pretty_repr_ as a plus for combinatorial objects is a good idea and useful. It is not the same as _repr_.

First, you don't want to change the repr of every combinatorial objects to have pretty prints, this will just break everything every where. (I am thinking of trees, Dyck paths, partitions...). Most objects already had a way being pretty printed, it was just not centralized and could not be used in linear combinations.

I actually think having the two _repr_ and _pretty_repr_ is useful. I have started to work with Jean-Baptiste's patch and depending on what I want to do with the output, I use both the pretty prints and usal prints.

@hivert
Copy link

hivert commented Mar 20, 2013

comment:9

Replying to @vbraun:

Whats the difference between _repr_, _pretty_repr_normal_, and _pretty_repr_term_? I think there should be only one _repr_, using ascii art unconditionally if printing the object benefits from it. Why would you want to turn it off? I don't see the need for a different display handler, we aleady have one that does handle ascii art.

There is definitely a need for a configurable display. In combinatorics
depending on the context we really need to be able to be able to print various
object in several different ways: The simplest example is
partitions. Sometimes you need to see:
(3,3,2,1,1)
sometime you need

   ###
   ###
   ##
   #
   #

or if you are french

   #
   #
   ##
   ###
   ###

Another example is graphs. Currently we only have
Graph on 6 vertices
Probably many user will rather have
Graph on 6 vertices with 5 edges
Or to see the incidence matrix...

So I definitely see a need for configurable output.

Florent

@vbraun
Copy link
Member

vbraun commented Mar 20, 2013

comment:10

I don't agree with your partition example: It should just print ascii-art (with some cutoff if the tableau gets too large) and provide a method to get the tuple-of-integers. Which you need anyways. And the French should get along with the program and get used to the same notation as the rest of the world ;-)

Seriously, we should first of all think about sane defaults that are as expressive as possible without being overly verbose. Just making everything configurable is a lame cop-out where you admit that you couldn't be bothered thinking about good defaults. If you want to see some other representation then you can always add an extra method. Why do you want a %magic to always print graphs as incidence matrix if you can just call the incidence_matrix() method?

@tscrim
Copy link
Collaborator

tscrim commented Mar 20, 2013

comment:11

I would recommend using the GlobalOptions that was setup in #13605 (you can look in partition.py or tableau.py for examples) to choose been what type of output you want on a global level. I also have some fairly generic code for ascii printing lists of arrays (it's currently sitting inside of #13872 and have been calling the specialized display functions _repr_diagram()), which is what you'd want since you'd want to call partition._repr_ to be consistent with the options specified there. I could separate that out into a separate ticket or copy/paste it here if you'd like.

@hivert
Copy link

hivert commented Mar 21, 2013

comment:12

Replying to @vbraun:

I don't agree with your partition example: It should just print ascii-art (with some cutoff if the tableau gets too large) and provide a method to get the tuple-of-integers. Which you need anyways. And the French should get along with the program and get used to the same notation as the rest of the world ;-)

Unforunately, I seems that many combinatorialist agree with me. Please se the beginning of the sage/combinat/partitions.py files. There is a PartitionOptions dictionary which allows one to configure various thing including the output.

@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Apr 10, 2013

new ascii art version.

That one is compatible with the Braun's displayhook.

It uses sympy to rewrite expression (or try to rewrite)::

sage: integral(exp(x^2)/(x+1), x)
⌠
⎮  ⎛ 2⎞
⎮  ⎝x ⎠
⎮ ℯ
⎮ ───── dx
⎮ x + 1
⌡

(FIXME:: For that I have to use utf-8 output for that I use a hack in sage/all_cmdline.py...)

I implement several pretty_repr for combinatorial object and plug that for free_module::

sage: R = NonCommutativeSymmetricFunctions(QQ).ribbon()
sage: Tableaux.global_options(convention="french")
sage: R[3,1,1]
R
 ***
   *
   *
sage: R[3,1,1] * R[2,1,2]
R      + R
 ***      ***
   *        *
   *        ***
   **         *
    *         **
    **
sage: F = QSym.F()
sage: F[2,1,2]
F
 **
  *
  **

The AsciiArt module (old PrettyConsolRepr) purpose a 'new' option of baseline.

@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Apr 10, 2013

Attachment: trac_14266_pretty_console_print-EliX-jbp.patch.gz

new ascii art version

@sagetrac-elixyre sagetrac-elixyre mannequin changed the title Fix sage_input and pretty print for NonCommutativeSymmetricFunctions, others. Pretty Console Output --> ascii art Apr 10, 2013
@vbraun
Copy link
Member

vbraun commented Apr 11, 2013

comment:15

Looks pretty nice! I'm fine with the functionality, but the documentation needs to be improved. Especially since you want to provide other developers a framework to enable ascii art output.

Some of the names are awkward in English. Pretty console representation means that the console is pretty, not the repr(esentation). It would be nice (and it would make writing doctests easier) if we install a global function analogous to repr() to get the ascii art representation. I would suggest we call it display() and the magic %display (instead of %pcp, unless you want to use it as a pun on the hallucinogenic drug).

Similarly, I don't like __pretty_repr__. Its not a variant of __repr__ with pretty output since it returns a specialized object instead of a string. Its also not a Python builtin, so Sage coding style would use only single underscores. How about we call it _ascii_art_()? Similarly, set_display instead of set_pretty_repr.

Also, since this should be a general framework we should add a default _ascii_art_ method (with suitable documentation to benefit developers) to SageObject. For example (in sage_object.pyx):

    def _ascii_art_(self):
        '''
        Return an ASCII art representation.

        To implement multi-line ASCII art output in a derived class
        you must override this method. Unlike :meth:`_repr_`, which is
        sometimes used for the hash key, the output of
        :meth:`_ascii_art_` may depend on settings and is allowed to
        change during runtime. For example,
        :meth:`~sage.combinat.tableau.Tableaux.set_display` can be
        used to switch the ASCII art of tableaux between different
        mathematical conventions.

        OUTPUT:

        An :class:`~sage.misc.ascii_art.AsciiArt` object, see
        :mod:`sage.misc.ascii_art` for details.

        EXAMPLES:

        You can use the :func:`~sage.misc.ascii_art.display` function
        to get the ASCII art representation of any object in Sage::

            sage: display(integral(exp(x^2)/(x+1), x))
            ⌠         
            ⎮  ⎛ 2⎞   
            ⎮  ⎝x ⎠   
            ⎮ ℯ       
            ⎮ ───── dx
            ⎮ x + 1   
            ⌡

        Alternatively, you can use the `%display on/off` magic to
        switch all output to ASCII art and back::
        
            sage: tab = StandardTableaux(3)[2];  tab
            [[1, 2], [3]]
            sage: %display on
            sage: tab
            1  2
            3
            sage: Tableau.set_display("normal")
            sage: tab
            +---+
            | 3 |
            +---+---+
            | 1 | 2 |
            +---+---+
            sage: %display off

        TESTS::

            sage: 1._ascii_art_()
            1
            sage: type(_)
            sage.misc.ascii_art.AsciiArt
        '''
        from sage.misc.ascii_art import AsciiArt
        return AsciiArt(repr(self))

Finally, __every__ function must be documented and doctested. Please follow http://www.sagemath.org/doc/developer/conventions.html#docstring-markup-with-rest-and-sphinx for the markup. For example, we use an OUTPUT: block instead of @postcondition.

@tscrim
Copy link
Collaborator

tscrim commented Apr 11, 2013

comment:16

Replying to @vbraun:

Some of the names are awkward in English. Pretty console representation means that the console is pretty, not the repr(esentation). It would be nice (and it would make writing doctests easier) if we install a global function analogous to repr() to get the ascii art representation. I would suggest we call it display() and the magic %display (instead of %pcp, unless you want to use it as a pun on the hallucinogenic drug).

I'm not a big fan of %display, it's somewhat vague as a true/false. How about %ascii_art or have %display accept a string input such as "ascii_art" incase we end up with more display types later on? (I think if you see ascii art, you're trippin' on some %pcp O_o )

Similarly, I don't like __pretty_repr__. Its not a variant of __repr__ with pretty output since it returns a specialized object instead of a string. Its also not a Python builtin, so Sage coding style would use only single underscores. How about we call it _ascii_art_()? Similarly, set_display instead of set_pretty_repr.

I like the _ascii_art_(). However I would rather this be converted into using the GlobalOptions framework instead of a separate function and attribute (tableaux already has this, and I can do it for Dyck paths if preferred). We can also use this for partitions as well.

Also, since this should be a general framework we should add a default _ascii_art_ method (with suitable documentation to benefit developers) to SageObject.

+1

@Jean-Baptiste

I would also like to see AsciiArt inherit from SageObject as well, and subsequently use _repr_ instead of __repr__ (1 underscore instead of 2). Also I would like to see the trailing whitespace removed from the new lines you've added, but this is not too important. (I like your ascii art in the beginning, too bad it's not of a sage [okay, I'm done with bad puns for now, promise].)

Thanks,

Travis

@novoselt
Copy link
Member

comment:17

It would be even better if default _ascii_art_ was deTeXed _latex_, rather than just _repr_.

I played with tex2mail a bit and it was quite nice, although I never got to trying to include it into Sage.

@vbraun
Copy link
Member

vbraun commented Apr 12, 2013

comment:18

Replying to @novoselt:

It would be even better if default _ascii_art_ was deTeXed _latex_, rather than just _repr_.
I played with tex2mail a bit and it was quite nice, although I never got to trying to include it into Sage.

There are other implementations of that idea, for example AsciiTeX. But that's not what this ticket is about.

@vbraun
Copy link
Member

vbraun commented Apr 12, 2013

comment:19

Replying to @tscrim:

I'm not a big fan of %display, it's somewhat vague as a true/false. How about %ascii_art or have %display accept a string input such as "ascii_art" incase we end up with more display types later on?

Sounds good to me. %display ascii_art and %display repr, perhaps with aliases on/off for the lazy.

@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Apr 29, 2013

comment:20

Attachment: trac_14266_ascii_art_module-EliX-jbp.patch.gz

New version with several tests for lot of methods... with AsciiArt inherit SageObject .
I purpose to use %display ascii_art and display repr to select one use.

I hope I don't forget anything.

Enjoy.

Thanks,
Jean-Baptiste

@vbraun
Copy link
Member

vbraun commented May 1, 2013

comment:21

I see you are developing your own whitespace style. Unfortunately, its a slap in Guido Rossum's face. Can you have a look at pep8 ( http://www.python.org/dev/peps/pep-0008/#whitespace-in-expressions-and-statements)?

def display_magic_function( self, mode = 'ascii_art'):  # no
def display_magic_function(self, mode='ascii_art'):     # yes

@vbraun
Copy link
Member

vbraun commented May 27, 2013

comment:68

Ok, applies to plain sage-5.10.beta5. It does conflict with #14523, though.

Changes look good to me.

@vbraun
Copy link
Member

vbraun commented May 28, 2013

comment:69

I just noticed that the sympy output is dependent on the terminal width:

sage -t sage/misc/ascii_art.py
**********************************************************************
File "sage/misc/ascii_art.py", line 45, in sage.misc.ascii_art
Failed example:
    shell.run_cell('sum(factorial(i)*x^i, i, 0, 10)')
Expected:
             10           9          8         7        6        5       4      3
    3628800*x   + 362880*x  + 40320*x  + 5040*x  + 720*x  + 120*x  + 24*x  + 6*x
    <BLANKLINE>
         2
    + 2*x  + x + 1
Got:
             10           9          8         7        6        5       4      3      2        
    3628800*x   + 362880*x  + 40320*x  + 5040*x  + 720*x  + 120*x  + 24*x  + 6*x  + 2*x  + x + 1
**********************************************************************
File "sage/misc/ascii_art.py", line 67, in sage.misc.ascii_art

@vbraun

This comment has been minimized.

@vbraun
Copy link
Member

vbraun commented May 28, 2013

Attachment: trac_14266_terminal_width.patch.gz

Initial patch

@vbraun
Copy link
Member

vbraun commented May 28, 2013

comment:71

Last patch disables sympy terminal width detection during doctesting.

If you are happy with it, set ticket to positive review.

Patchbot:

apply trac_14266_ascii_art_13_05_15_EliX-jbp.patch, trac_14266-ascii_art-review-ts.patch, trac_14266_terminal_width.patch

@tscrim
Copy link
Collaborator

tscrim commented May 28, 2013

comment:72

Looks good to me. Thanks Volker.

@nthiery
Copy link
Contributor

nthiery commented May 29, 2013

comment:73

Replying to @tscrim:

Looks good to me. Thanks Volker.

Beware though that trac_14266_terminal_width.patch introduces trailing whitespace.

@vbraun
Copy link
Member

vbraun commented May 29, 2013

comment:74

If you don't like trailing whitespace then feel free to work on commit hooks that check for it.

@nthiery
Copy link
Contributor

nthiery commented May 29, 2013

comment:75

Replying to @vbraun:

If you don't like trailing whitespace then feel free to work on commit hooks that check for it.

The sage dev scripts will strip them away for us. Which is how I actually detected this for I got a conflict when importing stuff into sage-git ... Do whatever you wish here; I just thought I might as well report the information.

@nthiery
Copy link
Contributor

nthiery commented May 29, 2013

comment:76

In case anyone cares, here is the version without trailing whitespaces I put in the Sage-Combinat queue to ease my playing with importing into git.

http://combinat.sagemath.org/patches/file/tip/trac_14266_terminal_width.patch

@jdemeyer
Copy link

jdemeyer commented Jun 6, 2013

Merged: sage-5.11.beta0

@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Jun 22, 2013

comment:78

the ascii_art doesn't work with notebook.
I purpose this patch but it is may be not a good solution.

@sagetrac-elixyre
Copy link
Mannequin Author

sagetrac-elixyre mannequin commented Jun 22, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants