5

I am trying to use the IPython.display module to convert objects to Markdown. However, there does not seem to be a good way to export this Markdown as a string.

Behaviour:

>>> from IPython.display import *
>>> from numpy import *
>>> display_markdown(eye(3))
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

Wanted behaviour:

>>> display_markdown_string(eye(3))
"$$\left( ... \right)$$"

Is there a good way to achieve this? It seems to me that this functionality has to present somewhere in IPython, since it can be done in the Notebooks.

4
  • 1
    @Synthetica, please can you confirm my understanding of the problem: you want the string representation of the markdown object returned from display_markdown and this string object must contain Latex too? Please can you specify what exactly you want? For Pandas dataframes you don't want Latex table in string representation, but that changes the original requirement? Commented Dec 25, 2019 at 18:43
  • @amanb Correct, I want the string representation of the Markdown object. This representation need not contain markdown, but I suspect it often would. Commented Dec 26, 2019 at 11:24
  • I don't get anything for display_markdown(eye(3)). I had to use display_markdown(str(eye(3)), raw=True), to get an inline array in markdown: [[1. 0. 0.] [0. 1. 0.] [0. 0. 1.]] Commented Dec 27, 2019 at 8:06
  • @Synthetica: but there is no Markdown object. There isn't even any markdown. display_markdown() doesn't output markdown if there is no markdown version available for the input. What is produced for your display is just plain text. Commented Dec 29, 2019 at 18:54

1 Answer 1

6

You have misunderstood what display_markdown() does. It is not a function to convert representation formats. IPython doesn’t use Markdown to display the array, it just outputs plain text in this specific case.

The IPython display system expects the objects to provide the formatted output themselves, and markdown is just one of the different formats supported. Because objects could support multiple formats, you sometimes want to explicitly select one specific format. display_markdown() lets you select the markdown representation and ignore others. But if an object doesn't have a specific markdown representation, its standard repr() string is used instead, as a fall-back. See the Rich Display section of the integration documentation.

Numpy arrays do not have a markdown representation, so display_markdown() has nothing to work with. What you see printed is just the string produced by repr(eye(3)). So you could just use repr(eye(3)), and to use it in markdown, wrap it in backticks:

A = np.eye(3)
markdown_repr = f"```\n{A!r}\n```"

The !r syntax tells Python to take the output of repr(). The above produces the string:

"```\narray([[1., 0., 0.],\n       [0., 1., 0.],\n       [0., 0., 1.]])\n```

If you want to have representation of an array in LaTeX, then there are projects that do produce such representations of numpy arrays you could use; provided you wrap their result in $$ lines, you can then treat those as markdown output as Jupyter supports embedded Mathjax expressions (a subset of LaTeX).

For example, using array-to-latex:

from array_to_latex import to_ltx
to_markdown = lambda m: f"$$\n{to_ltx(m, print_out=False)}\n$$"
print(to_markdown(A))

produces

$$
\begin{bmatrix}
  1.00 &  0.00 &  0.00\\
  0.00 &  1.00 &  0.00\\
  0.00 &  0.00 &  1.00
\end{bmatrix}
$$

You don’t have to use a library (you can write your own text manipulation code to do something similar), but you can’t use IPython to do this.

Of course, once you have such a function, you could not only use it directly, but you can also teach IPython to use it for any numpy array. You can register it as a formatter for text/markdown with IPython, as a third-party formatter function:

md_formatter = get_ipython().display_formatter.formatters["text/markdown"]
md_formatter.for_type(np.ndarray, to_markdown)

Because the library I used outputs LaTeX you could just use to_ltx() directly (with print_out=False) to produce LaTeX output, which will also result in Mathjax output whenever you echo an array:

latex_formatter = get_ipython().display_formatter.formatters["text/latex"]
latex_formatter.for_type(np.ndarray, lambda m: to_ltx(m, print_out=False))

Either way, now you'll see a MathJax rendering of the array:

notebook demo with LaTeX representation of a numpy matrix

Now, if you wanted to access the different formats objects make available to IPython, then you want to use the IPython.core.formatters.format_display_data() function; this gives you two dictionaries, the first is a dictionary with the various representation mime types as keys. If there is a markdown conversion available for the object, then you'll find it under the "text/markdown" key:

from IPython.core.formatters import format_display_data
formatted, metadata = format_display_data(A)
formatted["text/markdown"]

Because I already registered a markdown formatter for numpy arrays, the above produces the output of to_markdown() for us:

'$$\n\\begin{bmatrix}\n  1.00 &  0.00 &  0.00\\\\\n  0.00 &  1.00 &  0.00\\\\\n  0.00 &  0.00 &  1.00\n\\end{bmatrix}\n$$'

but without additional rich display registrations, all you'd get is a "text/plain" entry.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.