chore: import upstream snapshot with attribution
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:17:32 +08:00
commit adf0d17497
3085 changed files with 456962 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
<script lang="ts">
//@ts-nocheck
import { Plot as PlotIcon } from "@gradio/icons";
import { Empty } from "@gradio/atoms";
import type { SelectData } from "@gradio/utils";
import type { ThemeMode } from "../types";
import { untrack } from "svelte";
let {
value,
theme_mode,
caption,
bokeh_version,
show_actions_button,
_selectable,
x_lim,
show_fullscreen_button,
show_label,
on_change,
onselect
}: {
value: null | string;
theme_mode: ThemeMode;
caption: string;
bokeh_version: string | null;
show_actions_button: boolean;
_selectable: boolean;
x_lim: [number, number] | null;
show_fullscreen_button: boolean;
show_label: boolean;
on_change: () => void;
onselect?: (data: SelectData) => void;
} = $props();
let PlotComponent: any = $state(null);
let loaded_plotly_css = $state(false);
let key = $state(0);
const plotTypeMapping = {
plotly: () => import("./plot_types/PlotlyPlot.svelte"),
bokeh: () => import("./plot_types/BokehPlot.svelte"),
matplotlib: () => import("./plot_types/MatplotlibPlot.svelte"),
altair: () => import("./plot_types/AltairPlot.svelte")
};
let loadedPlotTypeMapping: Record<string, any> = {};
const is_browser = typeof window !== "undefined";
let _type = $state(null);
$effect(() => {
let type = value?.type;
untrack(() => {
key = key + 1;
if (type !== _type) {
PlotComponent = null;
}
if (type && type in plotTypeMapping && is_browser) {
if (loadedPlotTypeMapping[type]) {
PlotComponent = loadedPlotTypeMapping[type];
} else {
plotTypeMapping[type]().then((module) => {
PlotComponent = module.default;
loadedPlotTypeMapping[type] = PlotComponent;
});
}
}
_type = type;
});
on_change();
});
</script>
{#if value && PlotComponent}
{#key key}
<PlotComponent
{value}
colors={[]}
{theme_mode}
{show_label}
{caption}
{bokeh_version}
{show_actions_button}
{_selectable}
{x_lim}
bind:loaded_plotly_css
{onselect}
/>
{/key}
{:else}
<Empty unpadded_box={true} size="large"><PlotIcon /></Empty>
{/if}
+197
View File
@@ -0,0 +1,197 @@
<script lang="ts">
//@ts-nocheck
import { set_config } from "./altair_utils";
import { untrack } from "svelte";
import type { TopLevelSpec as Spec } from "vega-lite";
import vegaEmbed from "vega-embed";
import type { SelectData } from "@gradio/utils";
import type { View } from "vega";
let {
value,
colors = [],
caption,
show_actions_button,
_selectable,
onselect
}: {
value: any;
colors?: string[];
caption: string;
show_actions_button: boolean;
_selectable: boolean;
onselect?: (data: SelectData) => void;
} = $props();
let element: HTMLElement;
let parent_element: HTMLElement;
let view: View | undefined;
let computed_style = window.getComputedStyle(document.body);
let old_spec: Spec = $state(null);
let spec_width: number = $state(0);
let plot = $derived(value?.plot);
let spec = $derived.by(() => {
if (!plot) return null;
let parsed_spec = JSON.parse(plot) as Spec;
if (parsed_spec && parsed_spec.params && !_selectable) {
parsed_spec.params = parsed_spec.params.filter(
(param) => param.name !== "brush"
);
}
untrack(() => {
if (old_spec !== parsed_spec) {
old_spec = parsed_spec;
spec_width = parsed_spec.width;
}
if (value.chart && parsed_spec) {
parsed_spec = set_config(
parsed_spec,
computed_style,
value.chart as string,
colors
);
}
});
return parsed_spec;
});
let fit_width_to_parent = $derived(
spec?.encoding?.column?.field ||
spec?.encoding?.row?.field ||
value.chart === undefined
? false
: true
);
const get_width = (): number => {
return Math.min(
parent_element.offsetWidth,
spec_width || parent_element.offsetWidth
);
};
let resize_callback = (): void => {};
const renderPlot = (): void => {
if (view) {
view.finalize();
view = undefined;
}
if (fit_width_to_parent) {
spec.width = get_width();
}
vegaEmbed(element, spec, { actions: show_actions_button }).then(
function (result): void {
view = result.view;
resize_callback = () => {
view.signal("width", get_width()).run();
};
if (!_selectable) return;
const callback = (event, item): void => {
const brushValue = view.signal("brush");
if (brushValue) {
if (Object.keys(brushValue).length === 0) {
onselect?.({
value: null,
index: null,
selected: false
});
} else {
const key = Object.keys(brushValue)[0];
let range: [number, number] = brushValue[key].map(
(x) => x / 1000
);
onselect?.({
value: brushValue,
index: range,
selected: true
});
}
}
};
view.addEventListener("mouseup", callback);
view.addEventListener("touchup", callback);
}
);
};
const resizeObserver = new ResizeObserver(() => {
if (fit_width_to_parent && spec.width !== parent_element.offsetWidth) {
resize_callback();
}
});
$effect(() => {
if (!element || !parent_element || !spec) return;
renderPlot();
resizeObserver.observe(parent_element);
return () => {
if (view) {
view.finalize();
view = undefined;
}
resizeObserver.disconnect();
};
});
</script>
<div data-testid={"altair"} class="altair layout" bind:this={parent_element}>
<div bind:this={element}></div>
{#if caption}
<div class="caption layout">
{caption}
</div>
{/if}
</div>
<style>
.altair :global(canvas) {
padding: 6px;
}
.altair :global(.vega-embed) {
padding: 0px !important;
}
.altair :global(.vega-actions) {
right: 0px !important;
}
.layout {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: var(--size-full);
height: var(--size-full);
color: var(--body-text-color);
}
.altair {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: var(--size-full);
height: var(--size-full);
}
.caption {
font-size: var(--text-sm);
margin-bottom: 6px;
}
:global(#vg-tooltip-element) {
font-family: var(--font) !important;
font-size: var(--text-xs) !important;
box-shadow: none !important;
background-color: var(--block-background-fill) !important;
border: 1px solid var(--border-color-primary) !important;
color: var(--body-text-color) !important;
}
:global(#vg-tooltip-element .key) {
color: var(--body-text-color-subdued) !important;
}
</style>
+166
View File
@@ -0,0 +1,166 @@
<script lang="ts">
//@ts-nocheck
let { value, bokeh_version }: { value: any; bokeh_version: string | null } =
$props();
const div_id = `bokehDiv-${Math.random().toString(5).substring(2)}`;
let plot = $derived(value?.plot);
function static_base(version: string): string {
const root =
(typeof window !== "undefined" && window.gradio_config?.root) || "";
return `${root}/static/bokeh/${version}`;
}
function bokeh_local_url(version: string, filename: string): string {
return `${static_base(version)}/${filename}`;
}
function bokeh_cdn_url(version: string, filename: string): string {
if (filename === `bokeh-${version}.min.js`) {
return `https://cdn.bokeh.org/bokeh/release/${filename}`;
}
return `https://cdn.pydata.org/bokeh/release/${filename}`;
}
function load_script(
src: string,
fallback?: string
): Promise<HTMLScriptElement> {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.onload = () => resolve(script);
script.onerror = () => {
if (fallback) {
const fallback_script = document.createElement("script");
fallback_script.onload = () => resolve(fallback_script);
fallback_script.onerror = () => {
console.error(`Failed to load Bokeh script: ${src}`);
reject(new Error(`Failed to load ${src}`));
};
fallback_script.src = fallback;
document.head.appendChild(fallback_script);
} else {
console.error(`Failed to load Bokeh script: ${src}`);
reject(new Error(`Failed to load ${src}`));
}
};
script.src = src;
document.head.appendChild(script);
});
}
async function embed_bokeh(_plot: string): Promise<void> {
if (document) {
const el = document.getElementById(div_id);
if (el) {
el.innerHTML = "";
}
}
if (window.Bokeh) {
load_bokeh();
let plotObj = JSON.parse(_plot);
await window.Bokeh.embed.embed_item(plotObj, div_id);
}
}
const main_src = bokeh_version
? bokeh_local_url(bokeh_version, `bokeh-${bokeh_version}.min.js`)
: null;
const main_fallback = bokeh_version
? bokeh_cdn_url(bokeh_version, `bokeh-${bokeh_version}.min.js`)
: null;
const plugins_src = bokeh_version
? [
bokeh_local_url(bokeh_version, `bokeh-widgets-${bokeh_version}.min.js`),
bokeh_local_url(bokeh_version, `bokeh-tables-${bokeh_version}.min.js`),
bokeh_local_url(bokeh_version, `bokeh-gl-${bokeh_version}.min.js`),
bokeh_local_url(bokeh_version, `bokeh-api-${bokeh_version}.min.js`)
]
: [];
const plugins_fallback = bokeh_version
? [
bokeh_cdn_url(bokeh_version, `bokeh-widgets-${bokeh_version}.min.js`),
bokeh_cdn_url(bokeh_version, `bokeh-tables-${bokeh_version}.min.js`),
bokeh_cdn_url(bokeh_version, `bokeh-gl-${bokeh_version}.min.js`),
bokeh_cdn_url(bokeh_version, `bokeh-api-${bokeh_version}.min.js`)
]
: [];
let loaded = $state(false);
let plugin_scripts: HTMLScriptElement[] = $state([]);
async function load_plugins(): Promise<void> {
plugin_scripts = await Promise.all(
plugins_src.map((src, i) => load_script(src, plugins_fallback[i]))
);
loaded = true;
}
function handle_bokeh_loaded(): void {
load_plugins();
}
let added_main_script = false;
function load_bokeh(): HTMLScriptElement | null {
const script = document.createElement("script");
script.onload = handle_bokeh_loaded;
script.onerror = () => {
if (main_fallback) {
load_script(main_fallback)
.then(handle_bokeh_loaded)
.catch(() => {});
}
};
script.src = main_src;
const is_bokeh_script_present = document.head.querySelector(
`script[src="${main_src}"]`
);
if (!is_bokeh_script_present) {
document.head.appendChild(script);
added_main_script = true;
return script;
}
handle_bokeh_loaded();
return null;
}
const main_script = bokeh_version ? load_bokeh() : null;
$effect(() => {
if (loaded && plot) {
embed_bokeh(plot);
}
});
$effect(() => {
return () => {
if (
added_main_script &&
main_script &&
document.head.contains(main_script)
) {
document.head.removeChild(main_script);
}
plugin_scripts.forEach((child) => {
if (document.head.contains(child)) {
document.head.removeChild(child);
}
});
};
});
</script>
<div data-testid={"bokeh"} id={div_id} class="gradio-bokeh" />
<style>
.gradio-bokeh {
display: flex;
justify-content: center;
}
</style>
@@ -0,0 +1,24 @@
<script lang="ts">
let { value }: { value: any } = $props();
let plot = $derived(value?.plot);
</script>
<div data-testid={"matplotlib"} class="matplotlib layout">
<img src={plot} alt={`${value.chart} plot visualising provided data`} />
</div>
<style>
.layout {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: var(--size-full);
height: var(--size-full);
color: var(--body-text-color);
}
.matplotlib img {
object-fit: contain;
}
</style>
@@ -0,0 +1,60 @@
<script lang="ts">
//@ts-nocheck
import Plotly from "plotly.js-dist-min";
import { untrack } from "svelte";
let {
value,
show_label,
loaded_plotly_css = $bindable(false)
}: {
value: any;
show_label: boolean;
loaded_plotly_css?: boolean;
} = $props();
let plot = $derived(value?.plot);
let plot_div: HTMLDivElement;
let plotly_global_style: HTMLElement;
function load_plotly_css(): void {
if (!loaded_plotly_css) {
plotly_global_style = document.getElementById("plotly.js-style-global");
const plotly_style_clone = plotly_global_style.cloneNode();
plot_div.appendChild(plotly_style_clone);
for (const rule of plotly_global_style.sheet.cssRules) {
plotly_style_clone.sheet.insertRule(rule.cssText);
}
loaded_plotly_css = true;
}
}
$effect(() => {
if (!plot_div || !plot) return;
// load_plotly_css writes loaded_plotly_css; untrack it so this effect
// doesn't re-run and collapse an autosize plot to zero height.
untrack(() => load_plotly_css());
let plotObj = JSON.parse(plot);
plotObj.config = plotObj.config || {};
plotObj.config.responsive = true;
plotObj.responsive = true;
plotObj.layout.autosize = true;
if (plotObj.layout.margin == undefined) {
plotObj.layout.margin = {};
}
if (plotObj.layout.title && show_label) {
plotObj.layout.margin.t = Math.max(100, plotObj.layout.margin.t || 0);
}
plotObj.layout.margin.autoexpand = true;
Plotly.react(plot_div, plotObj.data, plotObj.layout, plotObj.config);
Plotly.Plots.resize(plot_div);
});
</script>
<div data-testid={"plotly"} bind:this={plot_div}></div>
+111
View File
@@ -0,0 +1,111 @@
import { colors as color_palette } from "@gradio/theme";
import { get_next_color } from "@gradio/utils";
import type { Config, TopLevelSpec as Spec } from "vega-lite";
export function set_config(
spec: Spec,
computed_style: CSSStyleDeclaration,
chart_type: string,
colors: string[]
): Spec {
let accentColor = computed_style.getPropertyValue("--color-accent");
let bodyTextColor = computed_style.getPropertyValue("--body-text-color");
let borderColorPrimary = computed_style.getPropertyValue(
"--border-color-primary"
);
let fontFamily = computed_style.fontFamily;
let titleWeight = computed_style.getPropertyValue(
"--block-title-text-weight"
) as "bold" | "normal" | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
const fontToPxVal = (font: string): number => {
return font.endsWith("px") ? parseFloat(font.slice(0, -2)) : 12;
};
let textSizeMd = fontToPxVal(computed_style.getPropertyValue("--text-md"));
let textSizeSm = fontToPxVal(computed_style.getPropertyValue("--text-sm"));
let config: Config = {
autosize: { type: "fit", contains: "padding" },
axis: {
labelFont: fontFamily,
labelColor: bodyTextColor,
titleFont: fontFamily,
titleColor: bodyTextColor,
tickColor: borderColorPrimary,
labelFontSize: textSizeSm,
gridColor: borderColorPrimary,
titleFontWeight: "normal",
titleFontSize: textSizeSm,
labelFontWeight: "normal",
domain: false,
labelAngle: 0
},
legend: {
labelColor: bodyTextColor,
labelFont: fontFamily,
titleColor: bodyTextColor,
titleFont: fontFamily,
titleFontWeight: "normal",
titleFontSize: textSizeSm,
labelFontWeight: "normal",
offset: 2
},
title: {
color: bodyTextColor,
font: fontFamily,
fontSize: textSizeMd,
fontWeight: titleWeight,
anchor: "middle"
},
view: {
stroke: borderColorPrimary
}
};
spec.config = config;
// @ts-ignore (unsure why the following are not typed in Spec)
let encoding: any = spec.encoding;
// @ts-ignore
let layer: any = spec.layer;
switch (chart_type) {
case "scatter":
spec.config.mark = { stroke: accentColor };
if (encoding.color && encoding.color.type == "nominal") {
encoding.color.scale.range = encoding.color.scale.range.map(
(_: string, i: number) => get_color(colors, i)
);
} else if (encoding.color && encoding.color.type == "quantitative") {
encoding.color.scale.range = ["#eff6ff", "#1e3a8a"];
encoding.color.scale.range.interpolate = "hsl";
}
break;
case "line":
spec.config.mark = { stroke: accentColor, cursor: "crosshair" };
layer.forEach((d: any) => {
if (d.encoding.color) {
d.encoding.color.scale.range = d.encoding.color.scale.range.map(
(_: any, i: any) => get_color(colors, i)
);
}
});
break;
case "bar":
spec.config.mark = { opacity: 0.8, fill: accentColor };
if (encoding.color) {
encoding.color.scale.range = encoding.color.scale.range.map(
(_: any, i: any) => get_color(colors, i)
);
}
break;
}
return spec;
}
function get_color(colors: string[], index: number): string {
let current_color = colors[index % colors.length];
if (current_color && current_color in color_palette) {
return color_palette[current_color as keyof typeof color_palette]?.primary;
} else if (!current_color) {
return color_palette[get_next_color(index) as keyof typeof color_palette]
.primary;
}
return current_color;
}