-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allows updating the dataset of a gr.Examples
#8745
Changes from all commits
0304ce1
b64ee18
f26dea0
56d71bd
438f056
ad68b97
bab55c0
2c063a0
2db5b64
018e90c
b2c699f
c3e0d90
89eaa32
777bfc5
ee1d201
56840f9
8bc3388
0fb8612
5bb773b
c763148
7ecf7c2
3762395
a35d67c
5f26556
688c83a
c2dc8a1
f86d082
e48fb9b
78af285
d0e61dc
305eb9c
a456090
6365a9b
fb7d05d
368024a
1e7c738
fd614b4
3874e38
532ae27
f0ea0ce
6c73b95
f1cc7cc
ff2beec
205b448
841609e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@gradio/dataframe": minor | ||
"gradio": minor | ||
"website": minor | ||
--- | ||
|
||
feat:Allows updating the dataset of a `gr.Examples` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: image_mod"]}, {"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": ["# Downloading files from the demo repo\n", "import os\n", "os.mkdir('images')\n", "!wget -q -O images/cheetah1.jpg https://github.com/gradio-app/gradio/raw/main/demo/image_mod/images/cheetah1.jpg\n", "!wget -q -O images/lion.jpg https://github.com/gradio-app/gradio/raw/main/demo/image_mod/images/lion.jpg\n", "!wget -q -O images/logo.png https://github.com/gradio-app/gradio/raw/main/demo/image_mod/images/logo.png\n", "!wget -q -O images/tower.jpg https://github.com/gradio-app/gradio/raw/main/demo/image_mod/images/tower.jpg"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import os\n", "\n", "\n", "def image_mod(image):\n", " return image.rotate(45)\n", "\n", "\n", "demo = gr.Interface(\n", " image_mod,\n", " gr.Image(type=\"pil\"),\n", " \"image\",\n", " flagging_options=[\"blurry\", \"incorrect\", \"other\"],\n", " examples=[\n", " os.path.join(os.path.abspath(''), \"images/cheetah1.jpg\"),\n", " os.path.join(os.path.abspath(''), \"images/lion.jpg\"),\n", " os.path.join(os.path.abspath(''), \"images/logo.png\"),\n", " os.path.join(os.path.abspath(''), \"images/tower.jpg\"),\n", " ],\n", ")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} | ||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: image_mod"]}, {"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": ["# Downloading files from the demo repo\n", "import os\n", "os.mkdir('images')\n", "!wget -q -O images/cheetah1.jpg https://github.com/gradio-app/gradio/raw/main/demo/image_mod/images/cheetah1.jpg\n", "!wget -q -O images/lion.jpg https://github.com/gradio-app/gradio/raw/main/demo/image_mod/images/lion.jpg\n", "!wget -q -O images/logo.png https://github.com/gradio-app/gradio/raw/main/demo/image_mod/images/logo.png\n", "!wget -q -O images/tower.jpg https://github.com/gradio-app/gradio/raw/main/demo/image_mod/images/tower.jpg"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import os\n", "\n", "\n", "def image_mod(image):\n", " return image.rotate(45)\n", "\n", "new_samples = [\n", " [os.path.join(os.path.abspath(''), \"images/logo.png\")],\n", " [os.path.join(os.path.abspath(''), \"images/tower.jpg\")],\n", "]\n", "\n", "with gr.Blocks() as demo:\n", " interface = gr.Interface(\n", " image_mod,\n", " gr.Image(type=\"pil\"),\n", " \"image\",\n", " flagging_options=[\"blurry\", \"incorrect\", \"other\"],\n", " examples=[\n", " os.path.join(os.path.abspath(''), \"images/cheetah1.jpg\"),\n", " os.path.join(os.path.abspath(''), \"images/lion.jpg\"),\n", " ],\n", " )\n", "\n", " btn = gr.Button(\"Update Examples\")\n", " btn.click(lambda : gr.Dataset(samples=new_samples), None, interface.examples_handler.dataset)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,7 +32,7 @@ def __init__( | |
component_props: list[dict[str, Any]] | None = None, | ||
samples: list[list[Any]] | None = None, | ||
headers: list[str] | None = None, | ||
type: Literal["values", "index"] = "values", | ||
type: Literal["values", "index", "tuple"] = "values", | ||
abidlabs marked this conversation as resolved.
Show resolved
Hide resolved
abidlabs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
samples_per_page: int = 10, | ||
visible: bool = True, | ||
elem_id: str | None = None, | ||
|
@@ -51,7 +51,7 @@ def __init__( | |
components: Which component types to show in this dataset widget, can be passed in as a list of string names or Components instances. The following components are supported in a Dataset: Audio, Checkbox, CheckboxGroup, ColorPicker, Dataframe, Dropdown, File, HTML, Image, Markdown, Model3D, Number, Radio, Slider, Textbox, TimeSeries, Video | ||
samples: a nested list of samples. Each sublist within the outer list represents a data sample, and each element within the sublist represents an value for each component | ||
headers: Column headers in the Dataset widget, should be the same len as components. If not provided, inferred from component labels | ||
type: 'values' if clicking on a sample should pass the value of the sample, or "index" if it should pass the index of the sample | ||
type: "values" if clicking on a sample should pass the value of the sample, "index" if it should pass the index of the sample, or "tuple" if it should pass both the index and the value of the sample. | ||
samples_per_page: how many examples to show per page. | ||
visible: If False, component will be hidden. | ||
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles. | ||
|
@@ -95,18 +95,20 @@ def __init__( | |
self.proxy_url = proxy_url | ||
for component in self._components: | ||
component.proxy_url = proxy_url | ||
self.samples = [[]] if samples is None else samples | ||
for example in self.samples: | ||
self.raw_samples = [[]] if samples is None else samples | ||
self.samples: list[list] = [] | ||
for example in self.raw_samples: | ||
self.samples.append([]) | ||
for i, (component, ex) in enumerate(zip(self._components, example)): | ||
# If proxy_url is set, that means it is being loaded from an external Gradio app | ||
# which means that the example has already been processed. | ||
if self.proxy_url is None: | ||
# The `as_example()` method has been renamed to `process_example()` but we | ||
# use the previous name to be backwards-compatible with previously-created | ||
# custom components | ||
example[i] = component.as_example(ex) | ||
example[i] = processing_utils.move_files_to_cache( | ||
example[i], component, keep_in_cache=True | ||
self.samples[-1].append(component.as_example(ex)) | ||
self.samples[-1][i] = processing_utils.move_files_to_cache( | ||
self.samples[-1][i], component, keep_in_cache=True | ||
) | ||
self.type = type | ||
self.label = label | ||
|
@@ -137,19 +139,21 @@ def get_config(self): | |
|
||
return config | ||
|
||
def preprocess(self, payload: int | None) -> int | list | None: | ||
def preprocess(self, payload: int | None) -> int | list | tuple[int, list] | None: | ||
""" | ||
Parameters: | ||
payload: the index of the selected example in the dataset | ||
Returns: | ||
Passes the selected sample either as a `list` of data corresponding to each input component (if `type` is "value") or as an `int` index (if `type` is "index") | ||
Passes the selected sample either as a `list` of data corresponding to each input component (if `type` is "value") or as an `int` index (if `type` is "index"), or as a `tuple` of the index and the data (if `type` is "tuple"). | ||
""" | ||
if payload is None: | ||
return None | ||
if self.type == "index": | ||
return payload | ||
elif self.type == "values": | ||
return self.samples[payload] | ||
return self.raw_samples[payload] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a small breaking change, but almost certainly the right behavior. When you are using the Dataset as an input, it should send the original values of the samples, not after they have already been postprocessed (and e.g. truncated as in the case of the dataframe). For example, in a demo like this: import gradio as gr
with gr.Blocks() as demo:
image = gr.Image(type="pil")
textbox = gr.Textbox()
dataset = gr.Dataset(samples=[["cat.jpg"], ["cat.jpg"]], components=[image], type="values")
dataset.click(lambda x:(x[0], x[0]), dataset, [textbox, image])
demo.launch() clicking on the dataset, will send a human-readable value into the textbox and a valid image into the image component |
||
elif self.type == "tuple": | ||
return payload, self.raw_samples[payload] | ||
|
||
def postprocess(self, sample: int | list | None) -> int | None: | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { test, expect } from "@gradio/tootils"; | ||
|
||
test("examples_get_updated_correctly", async ({ page }) => { | ||
await page.locator(".gallery-item").first().click(); | ||
let image = await page.getByTestId("image").locator("img").first(); | ||
await expect(await image.getAttribute("src")).toContain("cheetah1.jpg"); | ||
await page.getByRole("button", { name: "Update Examples" }).click(); | ||
|
||
let example_image; | ||
await expect(async () => { | ||
example_image = await page.locator(".gallery-item").locator("img").first(); | ||
await expect(await example_image.getAttribute("src")).toContain("logo.png"); | ||
}).toPass(); | ||
|
||
await example_image.click(); | ||
await expect(async () => { | ||
image = await page.getByTestId("image").locator("img").first(); | ||
await expect(await image.getAttribute("src")).toContain("logo.png"); | ||
}).toPass(); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,7 @@ | |
export let index: number; | ||
|
||
let hovered = false; | ||
let loaded_value: (string | number)[][] | string = value; | ||
let loaded = Array.isArray(loaded_value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure why we added import gradio as gr
import numpy as np
data = np.random.random((100,5))
np.savetxt('test.csv', data, fmt = '%.2f', delimiter=',', header = 'c1, c2, c3, c4, c5')
gr.Interface(lambda x:x, "dataframe", "dataframe", examples=["test.csv", "test.csv"]).launch() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lol no clue who would ever write that 🙈 |
||
let loaded = Array.isArray(value); | ||
</script> | ||
|
||
{#if loaded} | ||
|
@@ -19,11 +18,11 @@ | |
on:mouseenter={() => (hovered = true)} | ||
on:mouseleave={() => (hovered = false)} | ||
> | ||
{#if typeof loaded_value === "string"} | ||
{loaded_value} | ||
{#if typeof value === "string"} | ||
{value} | ||
{:else} | ||
<table class=""> | ||
{#each loaded_value.slice(0, 3) as row, i} | ||
{#each value.slice(0, 3) as row, i} | ||
<tr> | ||
{#each row.slice(0, 3) as cell, j} | ||
<td>{cell}</td> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated this demo instead of adding another demo because the original demo is quite simplistic and not referenced anywhere in the docs, and this way we don't have to add more images to the repo (I want to use local images instead of urls to make sure the test is not flaky)