pythonalignmentjupyter-labipywidgetshbox

Align ipywidgets inside two HBoxes python


I would like to align widgets inside two HBoxes horizontally.

import ipywidgets as widgets

but1 = widgets.RadioButtons(options=["foo", "bar"])
but2 = widgets.RadioButtons(options=["verylongstringherethisislong", "bar"])

check1 = widgets.Checkbox(description="asdf")
check2 = widgets.Checkbox(description="verylongstringherethisislong")

box_layout = widgets.Layout(
    align_items='flex-start',
    width='1300px',  
    justify_content='flex-start'  
)

widgets.VBox(
    children=[
        widgets.HBox(children=[but1, but1, but2, but2], layout=box_layout),
        widgets.HBox([check2, check2, check1, check1], layout=box_layout)
    ]
)

My current code doesn't do the job: enter image description here


Solution

  • Update: Using Grid Layout

    This update to make four columns of RadioButtons with Checkboxes aligned below each column uses a Grid Layout after comments by OP that the fine-tuning necessary with using the margins doesn't seem clean as expected.
    Still, the key change of setting indent=False for the Checkbox widgets is important, see the details below the original reply for more.

    import ipywidgets as widgets
    
    but1 = widgets.RadioButtons(options=["foo", "bar"])
    but1pt5 = widgets.RadioButtons(options=["foo", "bar"])
    but2 = widgets.RadioButtons(options=["verylongstringherethisislong", "bar"])
    but2pt5 = widgets.RadioButtons(options=["verylongstringherethisislong", "bar"])
    
    check1 = widgets.Checkbox(description="asdf", indent=False)
    check2 = widgets.Checkbox(description="verylongstringherethisislong", indent=False)
    check3 = widgets.Checkbox(description="verylongstringherethisislong", indent=False)
    check4 = widgets.Checkbox(description="asdf", indent=False)
    
    # Create GridBox layout
    grid_layout = widgets.Layout(
        display='grid',
        grid_template_columns='auto auto auto auto',
        grid_gap='10px 10px',
        width='1300px',
        justify_content='flex-start'
    )
    
    # Create GridBox
    grid_box = widgets.GridBox(
        children=[
            but1, but1pt5, but2, but2pt5,
            check2, check3, check4, check1
        ],
        layout=grid_layout
    )
    
    display(grid_box)
    

    RESULT WITH GRID LAYOUT

    enter image description here



    Original reply keeping closer to OP's code

    This gets close on my system:

    import ipywidgets as widgets
    
    but1 = widgets.RadioButtons(options=["foo", "bar"])
    but1pt5 = widgets.RadioButtons(options=["foo", "bar"], layout=widgets.Layout(margin='0 0 0 5px') )
    but2 = widgets.RadioButtons(options=["verylongstringherethisislong", "bar"], layout=widgets.Layout(margin='0 0 0 4px')  )
    but2pt5 = widgets.RadioButtons(options=["verylongstringherethisislong", "bar"], layout=widgets.Layout(margin='0 0 0 4px') )
    
    
    check1 = widgets.Checkbox(description="asdf", indent=False)
    check2 = widgets.Checkbox(description="verylongstringherethisislong", indent=False)
    check3 = widgets.Checkbox(description="verylongstringherethisislong", indent=False)
    check4 = widgets.Checkbox(description="asdf", indent=False)
    
    box_layout = widgets.Layout(
        align_items='flex-start',
        width='1300px',
        justify_content='flex-start'
    )
    
    vbox = widgets.VBox(
        children=[
            widgets.HBox(children=[but1, but1pt5, but2, but2pt5], layout=box_layout),
            widgets.HBox(children=[check2, check3, check1, check4], layout=box_layout)
        ]
    )
    
    display(vbox)
    

    RESULT USING ORIGINAL CODE

    enter image description here

    Keep in mind some adjustment may still be in order. I doubt these are the real labels, and so you may need to also adjust more. Plus, your system may handle the spacing a little different so some adjustment may be necessary. Hopefully the details I provide below will help in that fine tuning.

    UPDATE: speaking of adjustments it was pointed out that you can also use percents for controlling the padding setting. In this case, this is what I found works for substituting in for the lines with the pixel settings for padding:

    but1pt5 = widgets.RadioButtons(options=["foo", "bar"], layout=widgets.Layout(margin='0 0 0 0.4%') )
    but2 = widgets.RadioButtons(options=["verylongstringherethisislong", "bar"], layout=widgets.Layout(margin='0 0 0 0.3%')  )
    but2pt5 = widgets.RadioButtons(options=["verylongstringherethisislong", "bar"], layout=widgets.Layout(margin='0 0 0 0.2%') )
    

    That seems rather arbitrary, yet it was what I saw produced reasonable results in this situation. I add it because maybe it is resistant to changes in window size, unlike I suspect the pixel settings. Indeed that ability is why the percent setting was suggested here and there the use of the 50% makes sense because it is centering a checkbox in that case. Unlike here where the values seem very arbitrary.

    Details:

    The key change in my code relative yours, is setting indent=False for the Checkbox widgets. By default, ipywidgets indents the checkboxes for better alignment with their descriptions. However, here you don't want this as it is causing a major issue with the alignment in your case. Fortunately, the setting indent=False ensures that the checkboxes are not indented and are aligned with the left edge of their containers.
    In your case, just adding that setting indent=False for the Checkbox widgets gets you 90% of the way there relative your original code.

    However, it still isn't aligned even though it is much less dramatic with the indent nixed.
    So next I added ,layout=widgets.Layout(margin='0 0 0 1px') to the Checkbox widget for the Checkbox appearing on the left side of your columns and that addition of a left margin CSS property of some pixel value via the layout parameter helped that one in the second column look better aligned. However, I realized the others wouldn't be as easy, and so I switched to adding the left margin to the radio buttons. Doing that I realized, I need to separate these out so that each column has a very similarly setup widget, but an actual different widget that I can adjust independently. So that is why there are more than you had. I could pare down the checkboxes and second set of radio buttons back gain since I moved the margin handling to the radio buttons and the two radio buttons with the long label are the same, but I left them for now since you may need to fine tune. In the end, with your code the margins for the radio buttons just needed values of a few pixels to bring them in line with the unindented checkboxes.