I've created a class to redirect stdout in order to send the outputs of text and dataframes to specific cells within a notebook as markdown.
(Capture class based on: How to capture stdout output from a Python function call?)
I need to update the output of a cell other the the one the code is run from.
You can do this using IPython update_display, but only for a single output as the next update_display replaces the previous output of the cell.
This is why I'm trying to capture stdout, so that I can use a single update_display command to pass multiple outputs to a cell in markdown.
It works well, but individual statements need to be modified for nicer formatting when combined in stdout: print('hello') needs to be modified to print('hello<br>'), and df.to_markdown() needs to be modified to df.to_markdown + '\n'.
Is there a way I can modify individual outputs within stdout, so that I don't need to modify the statements in the cell?
Splitting by line won't work due to the dataframe markdown, but maybe regex?
I'm looking to do it using the class here and not contextlib etc., as when it's working it will be an extension of another class. A wrapper would be fine, but not preferable.
Hopefully this makes sense (the annotated code should if my explanation doesn't) and somebody can please help me!?
Thanks!
Phil.
P.S. If the class could also handle the .to_markdown() for the dataframe then that would be better.
from IPython.display import display, update_display, Markdown
import pandas as pd
import tabulate
from io import StringIO
import sys
# Update a cell with display handle cell_id
def cell_id(cell_id):
display(display_id=cell_id, clear=True)
# Class to capture stdout and update output of cell with display hand cell_id
class Capturing(list):
def __init__(self, cell_id):
self.cell_id = cell_id
def __enter__(self):
self._stdout = sys.stdout
sys.stdout = self._stringio = StringIO()
return self
def __exit__(self, *args):
self.out = self._stringio.getvalue()
update_display(Markdown(self.out), display_id=self.cell_id)
del self._stringio
sys.stdout = self._stdout
# Test data to output to cell
df1= pd.DataFrame({'col1': ['dog',2,3,4,5], 'col2': [6,7,8,'hippopotamus',0]})
df2 = pd.DataFrame({'colA': ['a','b','c','d','e'], 'colB': ['f','g','h','i','j']})
# Output using unmodified statements
cell_id('text_cell')
# Desired input
# Output using unmodified statements (desired input below, but not desired output above)
with Capturing('text_cell') as cap:
print('hello')
print('there')
print(df1.to_markdown())
print(df2.to_markdown())
# Desired output, but using modified statements
cell_id('markdown_cell')
# Expected output above, but statements are modified
with Capturing('markdown_cell') as cap:
print('hello<br>')
print('there<br>')
print(df1.to_markdown() + '\n')
print(df2.to_markdown() + '\n')