Search code examples
pythonjupyteripywidgets

How to overwrite Python Jupyter display output


I have created a small form with ipywidgets. The sample code can be run in Jupyter or Google colab.

Each time the form is filled and the button is clicked a row gets added to a dataframe. Subsequently the dataframe gets displayed.

My problem is that the output displays the new updated dataframe on top of the old one. What I want is that the new display output overwrites the old one. See image description here.

import ipywidgets as widgets
from ipywidgets import HBox, Label
from ipywidgets import Layout, Button, Box, FloatText, Textarea, Dropdown, Label, IntSlider
import time
import pandas as pd

#Create DF
df = df = pd.DataFrame(columns = ['Dropdown_column', 'Float_column'])
df

# Layout
form_item_layout = Layout(
    display='flex',
    flex_flow='row',
    justify_content='space-between',
)


button_item_layout = Layout(
    display='flex',
    flex_flow='row',
    justify_content='center',
    padding = '5%'
)

# Dropdown item

drop_down_input = 'Dropdown_input_1'

drop_down = widgets.Dropdown(options=[('Dropdown_input_1', 'Dropdown_input_1'), ('Dropdown_input_2','Dropdown_input_2'), ('Dropdown_input_3', 'Dropdown_input_3')])

def dropdown_handler(change):
    global drop_down_input
    print('\r','Dropdown: ' + str(change.new),end='')
    drop_down_input = change.new  
drop_down.observe(dropdown_handler, names='value')

# FloatText item

float_input = 0

FloatText = widgets.FloatText()

def IntText_handler(change):
    global float_input
    print('\r','Float text:' + str(change.new),end='')
    float_input = change.new 
FloatText.observe(IntText_handler, names='value')



# Button

button = widgets.Button(description='Add row to dataframe')
out = widgets.Output()
def on_button_clicked(b):
    global df
    button.description = 'Row added'
    time.sleep(1)
    with out:
      new_row = {'Dropdown_column': drop_down_input, 'Float_column': float_input}
      df = df.append(new_row, ignore_index=True)
      button.description = 'Add row to dataframe'
      display(df)
button.on_click(on_button_clicked)

# Form items

form_items = [         
    Box([Label(value='Dropdown'),
         drop_down], layout=form_item_layout),
    Box([Label(value='FloatText'),
         FloatText], layout=form_item_layout),
    Box([Label(value=''), button],
        layout=button_item_layout),    
]

form = Box(form_items, layout=Layout(
    display='flex',
    flex_flow='column',
    border='solid 1px',
    align_items='stretch',
    width='30%',
    padding = '1%'
))
display(form)
display(out)

I have tried using the print() function in combination with '/r' and changing #button part of my code. Change:

display(df)

to

print('\r',str(df), end='')

or

print(str(df), end='\r')

But this does not work either.

Does somebody have any idea what to do?


Solution

  • \r works only for single line of normal text but df is not displayed as normal text (and it is not single line) but as HTML code.

    You have to use out.clear_output() to remove previous content.

       with out:
          new_row = {'Dropdown_column': drop_down_input, 'Float_column': float_input}
          df = df.append(new_row, ignore_index=True)
          button.description = 'Add row to dataframe'
    
          out.clear_output()  # <---
    
          display(df)
    

    You can see more about out.clear_output() in documentation:
    Output widgets: leveraging Jupyter’s display system