mirror of
https://github.com/gradio-app/gradio.git
synced 2025-02-17 11:29:58 +08:00
add markdown and html support to dataframe (#1684)
* add markdown and html support to dataframe * fix bug, address review comments * fix test * fix test * rename parser instance variable
This commit is contained in:
parent
00a1894bf5
commit
609de11ce8
@ -1,5 +1,26 @@
|
||||
import gradio as gr
|
||||
|
||||
|
||||
def make_markdown():
|
||||
return [
|
||||
[
|
||||
"# hello again",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
'<img src="https://images.unsplash.com/photo-1574613362884-f79513a5128c?fit=crop&w=500&q=80"/>',
|
||||
],
|
||||
[
|
||||
"## hello again again",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
'<img src="https://images.unsplash.com/photo-1574613362884-f79513a5128c?fit=crop&w=500&q=80"/>',
|
||||
],
|
||||
[
|
||||
"### hello thrice",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
'<img src="https://images.unsplash.com/photo-1574613362884-f79513a5128c?fit=crop&w=500&q=80"/>',
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
with gr.Column():
|
||||
txt = gr.Textbox(label="Small Textbox", lines=1, show_label=False)
|
||||
@ -43,27 +64,31 @@ with gr.Blocks() as demo:
|
||||
gr.Dataframe(
|
||||
interactive=True, headers=["One", "Two", "Three", "Four"], col_count=4
|
||||
)
|
||||
gr.DataFrame(
|
||||
df = gr.DataFrame(
|
||||
[
|
||||
[
|
||||
"# hello",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
'<img src="https://images.unsplash.com/photo-1574613362884-f79513a5128c?fit=crop&w=500&q=80"/>',
|
||||
],
|
||||
[
|
||||
"## hello",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
'<img src="https://images.unsplash.com/photo-1574613362884-f79513a5128c?fit=crop&w=500&q=80"/>',
|
||||
],
|
||||
[
|
||||
"### hello",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
"Hello my name is frank, I am liking the small turtle you have there. It would be a shame if it went missing.",
|
||||
'<img src="https://images.unsplash.com/photo-1574613362884-f79513a5128c?fit=crop&w=500&q=80"/>',
|
||||
],
|
||||
],
|
||||
headers=["One", "Two", "Three"],
|
||||
wrap=True,
|
||||
datatype=["markdown", "markdown", "html"],
|
||||
interactive=True,
|
||||
)
|
||||
btn = gr.Button("Run")
|
||||
btn.click(fn=make_markdown, inputs=None, outputs=df)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -2354,6 +2354,8 @@ class Dataframe(Changeable, IOComponent):
|
||||
Demos: filter_records, matrix_transpose, tax_calculator
|
||||
"""
|
||||
|
||||
markdown_parser = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
value: Optional[List[List[Any]]] = None,
|
||||
@ -2403,13 +2405,17 @@ class Dataframe(Changeable, IOComponent):
|
||||
self.__validate_headers(headers, self.col_count[0])
|
||||
|
||||
self.headers = headers
|
||||
self.datatype = datatype
|
||||
self.datatype = (
|
||||
datatype if isinstance(datatype, list) else [datatype] * self.col_count[0]
|
||||
)
|
||||
self.type = type
|
||||
values = {
|
||||
"str": "",
|
||||
"number": 0,
|
||||
"bool": False,
|
||||
"date": "01/01/1970",
|
||||
"markdown": "",
|
||||
"html": "",
|
||||
}
|
||||
column_dtypes = (
|
||||
[datatype] * self.col_count[0] if isinstance(datatype, str) else datatype
|
||||
@ -2417,7 +2423,10 @@ class Dataframe(Changeable, IOComponent):
|
||||
self.test_input = [
|
||||
[values[c] for c in column_dtypes] for _ in range(self.row_count[0])
|
||||
]
|
||||
|
||||
self.value = value if value is not None else self.test_input
|
||||
self.value = self.__process_markdown(self.value, datatype)
|
||||
|
||||
self.max_rows = max_rows
|
||||
self.max_cols = max_cols
|
||||
self.overflow_row_behaviour = overflow_row_behaviour
|
||||
@ -2518,16 +2527,24 @@ class Dataframe(Changeable, IOComponent):
|
||||
if y is None:
|
||||
return y
|
||||
if isinstance(y, str):
|
||||
y = pd.read_csv(str)
|
||||
return {"headers": list(y.columns), "data": y.values.tolist()}
|
||||
y = pd.read_csv(y)
|
||||
return {
|
||||
"headers": list(y.columns),
|
||||
"data": Dataframe.__process_markdown(y.values.tolist(), self.datatype),
|
||||
}
|
||||
if isinstance(y, pd.DataFrame):
|
||||
return {"headers": list(y.columns), "data": y.values.tolist()}
|
||||
return {
|
||||
"headers": list(y.columns),
|
||||
"data": Dataframe.__process_markdown(y.values.tolist(), self.datatype),
|
||||
}
|
||||
if isinstance(y, (np.ndarray, list)):
|
||||
if isinstance(y, np.ndarray):
|
||||
y = y.tolist()
|
||||
if len(y) == 0 or not isinstance(y[0], list):
|
||||
y = [y]
|
||||
return {"data": y}
|
||||
return {
|
||||
"data": Dataframe.__process_markdown(y, self.datatype),
|
||||
}
|
||||
raise ValueError("Cannot process value as a Dataframe")
|
||||
|
||||
@staticmethod
|
||||
@ -2548,10 +2565,24 @@ class Dataframe(Changeable, IOComponent):
|
||||
)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def __process_markdown(cls, data: List[List[Any]], datatype: List[str]):
|
||||
if "markdown" not in datatype:
|
||||
return data
|
||||
|
||||
if cls.markdown_parser is None:
|
||||
cls.markdown_parser = MarkdownIt()
|
||||
|
||||
for i in range(len(data)):
|
||||
for j in range(len(data[i])):
|
||||
if datatype[j] == "markdown":
|
||||
data[i][j] = Dataframe.markdown_parser.render(data[i][j])
|
||||
|
||||
return data
|
||||
|
||||
def style(
|
||||
self,
|
||||
rounded: Optional[bool | Tuple[bool, bool, bool, bool]] = None,
|
||||
border: Optional[bool | Tuple[bool, bool, bool, bool]] = None,
|
||||
):
|
||||
return IOComponent.style(
|
||||
self,
|
||||
@ -2693,7 +2724,6 @@ class Timeseries(Changeable, IOComponent):
|
||||
def style(
|
||||
self,
|
||||
rounded: Optional[bool | Tuple[bool, bool, bool, bool]] = None,
|
||||
border: Optional[bool | Tuple[bool, bool, bool, bool]] = None,
|
||||
):
|
||||
return IOComponent.style(
|
||||
self,
|
||||
|
@ -1022,7 +1022,7 @@ class TestDataframe(unittest.TestCase):
|
||||
dataframe_input.get_config(),
|
||||
{
|
||||
"headers": ["Name", "Age", "Member"],
|
||||
"datatype": "str",
|
||||
"datatype": ["str", "str", "str"],
|
||||
"row_count": (3, "dynamic"),
|
||||
"col_count": (3, "dynamic"),
|
||||
"value": [
|
||||
@ -1079,7 +1079,7 @@ class TestDataframe(unittest.TestCase):
|
||||
"style": {},
|
||||
"elem_id": None,
|
||||
"visible": True,
|
||||
"datatype": "str",
|
||||
"datatype": ["str", "str", "str"],
|
||||
"row_count": (3, "dynamic"),
|
||||
"col_count": (3, "dynamic"),
|
||||
"value": [
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
type Headers = Array<string>;
|
||||
type Data = Array<Array<string | number>>;
|
||||
type Datatype = "str" | "markdown" | "html" | "number" | "bool" | "date";
|
||||
|
||||
export let headers: Headers = [];
|
||||
export let elem_id: string = "";
|
||||
@ -19,6 +20,7 @@
|
||||
export let style: Styles = {};
|
||||
export let label: string | null = null;
|
||||
export let wrap: boolean;
|
||||
export let datatype: Datatype | Array<Datatype>;
|
||||
|
||||
$: {
|
||||
if (value && !Array.isArray(value)) {
|
||||
@ -60,5 +62,6 @@
|
||||
editable={mode === "dynamic"}
|
||||
{style}
|
||||
{wrap}
|
||||
{datatype}
|
||||
/>
|
||||
</div>
|
||||
|
@ -3,6 +3,7 @@
|
||||
export let value: string | number = "";
|
||||
export let el: HTMLInputElement | null;
|
||||
export let header: boolean = false;
|
||||
export let datatype: "str" | "markdown" | "html" | "number" | "bool" | "date";
|
||||
</script>
|
||||
|
||||
{#if edit}
|
||||
@ -24,5 +25,11 @@
|
||||
role="button"
|
||||
class:opacity-0={edit}
|
||||
class:pointer-events-none={edit}
|
||||
class="p-2 outline-none border-0 flex-1">{value}</span
|
||||
class="p-2 outline-none border-0 flex-1"
|
||||
>
|
||||
{#if datatype === "markdown" || datatype === "html"}
|
||||
{@html value}
|
||||
{:else}
|
||||
{value}
|
||||
{/if}
|
||||
</span>
|
||||
|
@ -9,6 +9,9 @@
|
||||
import { Upload } from "@gradio/upload";
|
||||
import EditableCell from "./EditableCell.svelte";
|
||||
|
||||
type Datatype = "str" | "markdown" | "html" | "number" | "bool" | "date";
|
||||
|
||||
export let datatype: Datatype | Array<Datatype>;
|
||||
export let label: string | null = null;
|
||||
export let headers: Array<string> = [];
|
||||
export let values: Array<Array<string | number>> = [[]];
|
||||
@ -567,6 +570,9 @@
|
||||
bind:value
|
||||
bind:el={els[id].input}
|
||||
edit={editing === id}
|
||||
datatype={Array.isArray(datatype)
|
||||
? datatype[j]
|
||||
: datatype}
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
|
Loading…
Reference in New Issue
Block a user