gradio-app / gradio

Build and share delightful machine learning apps, all in Python. 🌟 Star to support our work!
http://www.gradio.app
Apache License 2.0
33.41k stars 2.53k forks source link

Allow the radio buttons to be a toggle. #6840

Closed Solomin0 closed 10 months ago

Solomin0 commented 10 months ago

Is your feature request related to a problem? Please describe.
I would like the user to be able to deselect their last clicked button without having to click another component to clear it.

Describe the solution you'd like
Allow a selected radio button to still pass SelectData when clicked.

Additional context
If the user has 3 options A,B,C and they select A. The button is pressed but in using the radio buttons as a setting selector if the user wants to select none they cannot press A again to deselect to my knowlege. If there is a way to do this let me know.

Here is the code I am using. You cannot get a signal from pressing A twice in a row.

import gradio as gr
def update(name):
    return f"Welcome to Gradio, {name}!"

def printer(a:gr.SelectData):
    print(a)

with gr.Blocks() as demo:
    gr.Markdown("Start typing below and then click **Run** to see the output.")
    with gr.Row():
        inp = gr.Textbox(placeholder="What is your name?")
        out = gr.Textbox()

        rad = gr.Radio(choices = ["1","2","3"])

    rad.select(printer)

    btn = gr.Button("Run")
    btn.click(fn=update, inputs=inp, outputs=out)

demo.launch()
abidlabs commented 10 months ago

Hi @Solomin0 the standard behavior for radio buttons is that you can not "unselect" it because it is not intended to be empty. For the behavior that you're trying to capture, a different component may be more appropriate.

For example, you could do a gr.CheckboxGroup but then have a .select() event to enforce that only a single checkbox is toggled on at a time. Something like this:

import gradio as gr

def enforce_single(current_selection, sd: gr.SelectData):
    if sd.value == current_selection:
        return [], None
    else:
        return [sd.value], sd.value

with gr.Blocks() as demo:
    current_selection = gr.State()
    cg = gr.CheckboxGroup(["a", "b", "c"], interactive=True)
    cg.select(enforce_single, current_selection, [cg, current_selection])

demo.launch()

Not the simplest solution, but its flexible enough to support any sort of custom constraints you might want to put on the gr.CheckboxGroup