Skip to content

Commit 0892c29

Browse files
Fix plot Rendering + visibility bug (#12515)
* Fix plot Rendering + visibility bug * add changeset * add changeset * Fix * Fix * Fix failing test --------- Co-authored-by: gradio-pr-bot <[email protected]>
1 parent 8aaa209 commit 0892c29

File tree

8 files changed

+112
-30
lines changed

8 files changed

+112
-30
lines changed

.changeset/cyan-humans-smoke.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@gradio/core": patch
3+
"@gradio/nativeplot": patch
4+
"gradio": patch
5+
---
6+
7+
fix:Fix plot Rendering + visibility bug

demo/invisible_textbox/run.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: invisible_textbox"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "with gr.Blocks() as demo:\n", " textbox = gr.Textbox(visible=False, interactive=True, elem_id=\"test-textbox\")\n", "\n", " make_visible_btn = gr.Button(\"Show\")\n", " hide = gr.Button(\"Hide\")\n", " def show():\n", " return gr.Textbox(visible=True)\n", " make_visible_btn.click(fn=show, outputs=textbox)\n", " hide.click(lambda: gr.Textbox(visible=False), outputs=textbox)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
1+
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: invisible_textbox"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Tabs():\n", " with gr.Tab(\"Invisible Textbox Demo\"):\n", " textbox = gr.Textbox(visible=False, interactive=True, elem_id=\"test-textbox\")\n", "\n", " make_visible_btn = gr.Button(\"Show\")\n", " hide = gr.Button(\"Hide\")\n", " def show():\n", " return gr.Textbox(visible=True)\n", " make_visible_btn.click(fn=show, outputs=textbox)\n", " hide.click(lambda: gr.Textbox(visible=False), outputs=textbox)\n", " with gr.Tab(\"Another Tab\"):\n", " msg = gr.Markdown(\"This is another tab to demonstrate that invisible components work across tabs.\", visible=False)\n", " show_message = gr.Button(\"Show Message\")\n", " show_message.click(lambda: gr.Markdown(visible=True), outputs=msg)\n", " with gr.Tab(\"Third Tab\"):\n", " with gr.Accordion(\"Third Tab Accordion\", open=True, visible=False) as acc:\n", " third_msg = gr.Textbox(label=\"Visible Textbox\", interactive=True, visible=True)\n", " hidden_number = gr.Number(visible=False, label=\"Hidden Number\", value=100, elem_id=\"hidden-number\")\n", " show_number_btn = gr.Button(\"Show Number\")\n", " hide_number_btn = gr.Button(\"Hide Number\")\n", " show_number_btn.click(lambda: gr.Number(visible=True), outputs=hidden_number)\n", " hide_number_btn.click(lambda: gr.Number(visible=False), outputs=hidden_number)\n", "\n", " show_third_message = gr.Button(\"Show Accordion\")\n", " show_third_message.click(lambda: gr.Accordion(visible=True), outputs=acc)\n", " hide_third_message = gr.Button(\"Hide Accordion\")\n", " hide_third_message.click(lambda: gr.Accordion(visible=False), outputs=acc)\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}

demo/invisible_textbox/run.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
11
import gradio as gr
22

33
with gr.Blocks() as demo:
4-
textbox = gr.Textbox(visible=False, interactive=True, elem_id="test-textbox")
4+
with gr.Tabs():
5+
with gr.Tab("Invisible Textbox Demo"):
6+
textbox = gr.Textbox(visible=False, interactive=True, elem_id="test-textbox")
57

6-
make_visible_btn = gr.Button("Show")
7-
hide = gr.Button("Hide")
8-
def show():
9-
return gr.Textbox(visible=True)
10-
make_visible_btn.click(fn=show, outputs=textbox)
11-
hide.click(lambda: gr.Textbox(visible=False), outputs=textbox)
8+
make_visible_btn = gr.Button("Show")
9+
hide = gr.Button("Hide")
10+
def show():
11+
return gr.Textbox(visible=True)
12+
make_visible_btn.click(fn=show, outputs=textbox)
13+
hide.click(lambda: gr.Textbox(visible=False), outputs=textbox)
14+
with gr.Tab("Another Tab"):
15+
msg = gr.Markdown("This is another tab to demonstrate that invisible components work across tabs.", visible=False)
16+
show_message = gr.Button("Show Message")
17+
show_message.click(lambda: gr.Markdown(visible=True), outputs=msg)
18+
with gr.Tab("Third Tab"):
19+
with gr.Accordion("Third Tab Accordion", open=True, visible=False) as acc:
20+
third_msg = gr.Textbox(label="Visible Textbox", interactive=True, visible=True)
21+
hidden_number = gr.Number(visible=False, label="Hidden Number", value=100, elem_id="hidden-number")
22+
show_number_btn = gr.Button("Show Number")
23+
hide_number_btn = gr.Button("Hide Number")
24+
show_number_btn.click(lambda: gr.Number(visible=True), outputs=hidden_number)
25+
hide_number_btn.click(lambda: gr.Number(visible=False), outputs=hidden_number)
1226

27+
show_third_message = gr.Button("Show Accordion")
28+
show_third_message.click(lambda: gr.Accordion(visible=True), outputs=acc)
29+
hide_third_message = gr.Button("Hide Accordion")
30+
hide_third_message.click(lambda: gr.Accordion(visible=False), outputs=acc)
1331
if __name__ == "__main__":
14-
demo.launch()
32+
demo.launch()

js/core/src/init.svelte.ts

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export class AppTree {
7676
ready: Promise<void>;
7777
ready_resolve!: () => void;
7878
resolved: boolean = false;
79+
#hidden_on_startup: Set<number> = new Set();
7980

8081
constructor(
8182
components: ComponentMeta[],
@@ -228,7 +229,8 @@ export class AppTree {
228229
(node) =>
229230
untrack_children_of_closed_accordions_or_inactive_tabs(
230231
node,
231-
this.components_to_register
232+
this.components_to_register,
233+
this.#hidden_on_startup
232234
)
233235
]);
234236
}
@@ -352,9 +354,9 @@ export class AppTree {
352354
: null,
353355
key: component.key,
354356
rendered_in: component.rendered_in,
355-
documentation: component.documentation
357+
documentation: component.documentation,
358+
original_visibility: processed_props.shared_props.visible
356359
};
357-
358360
return node;
359361
}
360362

@@ -475,7 +477,7 @@ export class AppTree {
475477
this.root = this.traverse(this.root!, [
476478
(node) => {
477479
if (node.id === id) {
478-
update_visibility(node, true);
480+
make_visible_if_not_rendered(node, this.#hidden_on_startup);
479481
}
480482
return node;
481483
},
@@ -484,14 +486,15 @@ export class AppTree {
484486
}
485487
}
486488

487-
function update_visibility(
489+
function make_visible_if_not_rendered(
488490
node: ProcessedComponentMeta,
489-
visible: boolean
491+
hidden_on_startup: Set<number>
490492
): void {
491-
node.props.shared_props.visible = visible;
493+
node.props.shared_props.visible = hidden_on_startup.has(node.id)
494+
? true
495+
: node.props.shared_props.visible;
492496
node.children.forEach((child) => {
493-
child.props.shared_props.visible = visible;
494-
update_visibility(child, visible);
497+
make_visible_if_not_rendered(child, hidden_on_startup);
495498
});
496499
}
497500

@@ -626,7 +629,6 @@ function set_visibility_for_updated_node(
626629
): ProcessedComponentMeta {
627630
if (node.id == id) {
628631
node.props.shared_props.visible = visible;
629-
update_visibility(node, visible);
630632
}
631633
return node;
632634
}
@@ -653,17 +655,31 @@ function untrack_children_of_invisible_parents(
653655
return node;
654656
}
655657

658+
function mark_component_invisible_if_visible(
659+
node: ProcessedComponentMeta,
660+
hidden_on_startup: Set<number>
661+
): ProcessedComponentMeta {
662+
if (node.props.shared_props.visible === true) {
663+
hidden_on_startup.add(node.id);
664+
node.props.shared_props.visible = false;
665+
}
666+
node.children.forEach((child) => {
667+
mark_component_invisible_if_visible(child, hidden_on_startup);
668+
});
669+
return node;
670+
}
671+
656672
function untrack_children_of_closed_accordions_or_inactive_tabs(
657673
node: ProcessedComponentMeta,
658-
components_to_register: Set<number>
674+
components_to_register: Set<number>,
675+
hidden_on_startup: Set<number>
659676
): ProcessedComponentMeta {
660677
// Check if the node is an accordion or tabs
661678
if (node.type === "accordion" && node.props.props.open === false) {
662679
_untrack(node, components_to_register);
663680
if (node.children) {
664681
node.children.forEach((child) => {
665-
if (child.props.shared_props.visible === true)
666-
update_visibility(child, false);
682+
mark_component_invisible_if_visible(child, hidden_on_startup);
667683
});
668684
}
669685
}
@@ -675,13 +691,7 @@ function untrack_children_of_closed_accordions_or_inactive_tabs(
675691
(node.props.props.selected || node.props.props.initial_tabs[0].id)
676692
) {
677693
_untrack(child, components_to_register);
678-
if (child.children) {
679-
child.children.forEach((grandchild) => {
680-
if (grandchild.props.shared_props.visible === true) {
681-
update_visibility(grandchild, false);
682-
}
683-
});
684-
}
694+
mark_component_invisible_if_visible(child, hidden_on_startup);
685695
}
686696
});
687697
}

js/core/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface ProcessedComponentMeta {
3232
component_class_id: string; // ?;
3333
key: string | number | null; // ?;
3434
rendered_in?: number; // ?;
35+
original_visibility: boolean | "hidden";
3536
}
3637

3738
/** Dictates whether a dependency is continous and/or a generator */

js/nativeplot/Index.svelte

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,9 @@
643643
legend: {
644644
orient: "bottom",
645645
title: gradio.props.color_title,
646-
values: [...gradio.props.colors_in_legend] || undefined
646+
values: gradio.props.colors_in_legend?.length
647+
? [...gradio.props.colors_in_legend]
648+
: undefined
647649
},
648650
scale:
649651
gradio.props.value!.datatypes[gradio.props.color] ===
@@ -766,6 +768,7 @@
766768
} as Spec;
767769
}
768770
/* eslint-enable complexity */
771+
$inspect("visible", gradio.shared.visible);
769772
</script>
770773

771774
<Block

js/spa/test/invisible_textbox.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,44 @@ test("Textbox visibility can be toggled from the backend. Toggling visibility re
2020
await page.click('text="Show"');
2121
await expect(textbox).toHaveValue("Test value");
2222
});
23+
24+
test("Component visibility is respected in inactive tabs. A component with visibility=False will not be shown when the tab is active", async ({
25+
page
26+
}) => {
27+
await page.click('text="Show"');
28+
29+
await expect(page.locator("#test-textbox")).toHaveCount(1);
30+
31+
await page.getByRole("tab", { name: "Another Tab" }).click();
32+
33+
await page.click('text="Show Message"');
34+
35+
await expect(
36+
page.getByText(
37+
"This is another tab to demonstrate that invisible components work across tabs."
38+
)
39+
).toBeVisible();
40+
41+
// Switch back to first tab and check textbox is still there
42+
await page.getByRole("tab", { name: "Invisible Textbox Demo" }).click();
43+
44+
await expect(page.locator("#test-textbox")).toHaveCount(1);
45+
});
46+
47+
test("Making accordion visible does not show all children automatically", async ({
48+
page
49+
}) => {
50+
await page.getByRole("tab", { name: "Third Tab" }).click();
51+
await expect(page.locator("#hidden-number")).toHaveCount(0);
52+
53+
await page.click('text="Show Accordion"');
54+
55+
await expect(page.getByLabel("Visible Textbox")).toBeVisible();
56+
57+
await page.click('text="Show Number"');
58+
59+
await expect(page.locator("#hidden-number")).toHaveCount(1);
60+
61+
await page.click('text="Hide Number"');
62+
await expect(page.locator("#hidden-number")).toHaveCount(0);
63+
});

js/spa/test/test_chatinterface_streaming_echo.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { test, expect, go_to_testcase } from "@self/tootils";
22

3+
test.describe.configure({ mode: "serial" });
4+
35
const cases = [
46
"messages",
57
"multimodal_messages",

0 commit comments

Comments
 (0)