mirror of
https://github.com/gradio-app/gradio.git
synced 2025-01-24 10:54:04 +08:00
Improved plot rendering (#8580)
* changes * add changeset * add changeset * add changeset * changes * changes * restore altair * changes * changes * changes * changes * changes * changes * Update twenty-jokes-argue.md * changes * chanegs * changes * changes * changes * changes --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
parent
1e61644624
commit
797621b81a
7
.changeset/twenty-jokes-argue.md
Normal file
7
.changeset/twenty-jokes-argue.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
"@gradio/plot": patch
|
||||
"gradio": patch
|
||||
---
|
||||
|
||||
feat:Improved plot rendering to thematically match
|
||||
highlight:Expect visual changes in gr.Plot, gr.BarPlot, gr.LinePlot, gr.ScatterPlot, including changes to color and width sizing.
|
@ -98,14 +98,14 @@ def bar_plot_fn(display):
|
||||
|
||||
|
||||
with gr.Blocks() as bar_plot:
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
display = gr.Dropdown(
|
||||
choices=["simple", "stacked", "grouped", "simple-horizontal", "stacked-horizontal", "grouped-horizontal"],
|
||||
value="simple",
|
||||
label="Type of Bar Plot"
|
||||
)
|
||||
with gr.Column():
|
||||
plot = gr.BarPlot(show_label=False, show_actions_button=True)
|
||||
display = gr.Dropdown(
|
||||
choices=["simple", "stacked", "grouped", "simple-horizontal", "stacked-horizontal", "grouped-horizontal"],
|
||||
value="simple",
|
||||
label="Type of Bar Plot"
|
||||
)
|
||||
plot = gr.BarPlot(show_label=False)
|
||||
display.change(bar_plot_fn, inputs=display, outputs=plot)
|
||||
bar_plot.load(fn=bar_plot_fn, inputs=display, outputs=plot)
|
||||
|
||||
if __name__ == "__main__":
|
||||
bar_plot.launch()
|
@ -24,8 +24,6 @@ def line_plot_fn(dataset):
|
||||
overlay_point=False,
|
||||
title="Stock Prices",
|
||||
stroke_dash_legend_title=None,
|
||||
height=300,
|
||||
width=500
|
||||
)
|
||||
elif dataset == "climate":
|
||||
return gr.LinePlot(
|
||||
@ -40,8 +38,6 @@ def line_plot_fn(dataset):
|
||||
overlay_point=False,
|
||||
title="Climate",
|
||||
stroke_dash_legend_title=None,
|
||||
height=300,
|
||||
width=500
|
||||
)
|
||||
elif dataset == "seattle_weather":
|
||||
return gr.LinePlot(
|
||||
@ -56,8 +52,6 @@ def line_plot_fn(dataset):
|
||||
overlay_point=True,
|
||||
title="Seattle Weather",
|
||||
stroke_dash_legend_title=None,
|
||||
height=300,
|
||||
width=500
|
||||
)
|
||||
elif dataset == "gapminder":
|
||||
return gr.LinePlot(
|
||||
@ -72,20 +66,15 @@ def line_plot_fn(dataset):
|
||||
overlay_point=False,
|
||||
title="Life expectancy for countries",
|
||||
stroke_dash_legend_title="Country Cluster",
|
||||
height=300,
|
||||
width=500
|
||||
)
|
||||
|
||||
|
||||
with gr.Blocks() as line_plot:
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
dataset = gr.Dropdown(
|
||||
choices=["stocks", "climate", "seattle_weather", "gapminder"],
|
||||
value="stocks",
|
||||
)
|
||||
with gr.Column():
|
||||
plot = gr.LinePlot()
|
||||
dataset = gr.Dropdown(
|
||||
choices=["stocks", "climate", "seattle_weather", "gapminder"],
|
||||
value="stocks",
|
||||
)
|
||||
plot = gr.LinePlot()
|
||||
dataset.change(line_plot_fn, inputs=dataset, outputs=plot)
|
||||
line_plot.load(fn=line_plot_fn, inputs=dataset, outputs=plot)
|
||||
|
||||
|
@ -12,13 +12,14 @@ def scatter_plot_fn(dataset):
|
||||
value=iris,
|
||||
x="petalWidth",
|
||||
y="petalLength",
|
||||
color="species",
|
||||
color=None,
|
||||
title="Iris Dataset",
|
||||
color_legend_title="Species",
|
||||
x_title="Petal Width",
|
||||
y_title="Petal Length",
|
||||
tooltip=["petalWidth", "petalLength", "species"],
|
||||
caption="",
|
||||
height=600,
|
||||
width=600,
|
||||
)
|
||||
else:
|
||||
return gr.ScatterPlot(
|
||||
@ -29,17 +30,15 @@ def scatter_plot_fn(dataset):
|
||||
tooltip="Name",
|
||||
title="Car Data",
|
||||
y_title="Miles per Gallon",
|
||||
color_legend_title="Origin of Car",
|
||||
caption="MPG vs Horsepower of various cars",
|
||||
height=None,
|
||||
width=None,
|
||||
)
|
||||
|
||||
|
||||
with gr.Blocks() as scatter_plot:
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
dataset = gr.Dropdown(choices=["cars", "iris"], value="cars")
|
||||
with gr.Column():
|
||||
plot = gr.ScatterPlot(show_label=False)
|
||||
dataset = gr.Dropdown(choices=["cars", "iris"], value="cars")
|
||||
plot = gr.ScatterPlot(show_label=False)
|
||||
dataset.change(scatter_plot_fn, inputs=dataset, outputs=plot)
|
||||
scatter_plot.load(fn=scatter_plot_fn, inputs=dataset, outputs=plot)
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Any, Callable, Literal
|
||||
|
||||
from gradio_client.documentation import document
|
||||
@ -52,8 +53,8 @@ class BarPlot(Plot):
|
||||
"none",
|
||||
]
|
||||
| None = None,
|
||||
height: int | str | None = None,
|
||||
width: int | str | None = None,
|
||||
height: int | None = None,
|
||||
width: int | None = None,
|
||||
y_lim: list[int] | None = None,
|
||||
caption: str | None = None,
|
||||
interactive: bool | None = True,
|
||||
@ -88,8 +89,8 @@ class BarPlot(Plot):
|
||||
color_legend_title: The title given to the color legend. By default, uses the value of color parameter.
|
||||
group_title: The label displayed on top of the subplot columns (or rows if vertical=True). Use an empty string to omit.
|
||||
color_legend_position: The position of the color legend. If the string value 'none' is passed, this legend is omitted. For other valid position values see: https://vega.github.io/vega/docs/legends/#orientation.
|
||||
height: The height of the plot, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
||||
width: The width of the plot, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
||||
height: The height of the plot in pixels.
|
||||
width: The width of the plot in pixels. If None, expands to fit.
|
||||
y_lim: A tuple of list containing the limits for the y-axis, specified as [y_min, y_max].
|
||||
caption: The (optional) caption to display below the plot.
|
||||
interactive: Whether users should be able to interact with the plot by panning or zooming with their mouse or trackpad.
|
||||
@ -122,10 +123,22 @@ class BarPlot(Plot):
|
||||
self.y_lim = y_lim
|
||||
self.caption = caption
|
||||
self.interactive_chart = interactive
|
||||
if isinstance(width, str):
|
||||
width = None
|
||||
warnings.warn(
|
||||
"Width should be an integer, not a string. Setting width to None."
|
||||
)
|
||||
if isinstance(height, str):
|
||||
warnings.warn(
|
||||
"Height should be an integer, not a string. Setting height to None."
|
||||
)
|
||||
height = None
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.sort = sort
|
||||
self.show_actions_button = show_actions_button
|
||||
if label is None and show_label is None:
|
||||
show_label = False
|
||||
super().__init__(
|
||||
value=value,
|
||||
label=label,
|
||||
@ -172,8 +185,8 @@ class BarPlot(Plot):
|
||||
"none",
|
||||
]
|
||||
| None = None,
|
||||
height: int | str | None = None,
|
||||
width: int | str | None = None,
|
||||
height: int | None = None,
|
||||
width: int | None = None,
|
||||
y_lim: list[int] | None = None,
|
||||
interactive: bool | None = True,
|
||||
sort: Literal["x", "y", "-x", "-y"] | None = None,
|
||||
@ -182,11 +195,7 @@ class BarPlot(Plot):
|
||||
import altair as alt
|
||||
|
||||
interactive = True if interactive is None else interactive
|
||||
orientation = (
|
||||
{"field": group, "title": group_title if group_title is not None else group}
|
||||
if group
|
||||
else {}
|
||||
)
|
||||
orientation = {"field": group, "title": group_title} if group else {}
|
||||
|
||||
x_title = x_title or x
|
||||
y_title = y_title or y
|
||||
@ -234,6 +243,7 @@ class BarPlot(Plot):
|
||||
properties["width"] = width
|
||||
|
||||
if color:
|
||||
color_legend_position = color_legend_position or "bottom"
|
||||
domain = value[color].unique().tolist()
|
||||
range_ = list(range(len(domain)))
|
||||
encodings["color"] = {
|
||||
@ -241,7 +251,7 @@ class BarPlot(Plot):
|
||||
"type": "nominal",
|
||||
"scale": {"domain": domain, "range": range_},
|
||||
"legend": AltairPlot.create_legend(
|
||||
position=color_legend_position, title=color_legend_title or color
|
||||
position=color_legend_position, title=color_legend_title
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Any, Callable, Literal
|
||||
|
||||
from gradio_client.documentation import document
|
||||
@ -64,8 +65,8 @@ class LinePlot(Plot):
|
||||
"none",
|
||||
]
|
||||
| None = None,
|
||||
height: int | str | None = None,
|
||||
width: int | str | None = None,
|
||||
height: int | None = None,
|
||||
width: int | None = None,
|
||||
x_lim: list[int] | None = None,
|
||||
y_lim: list[int] | None = None,
|
||||
caption: str | None = None,
|
||||
@ -101,8 +102,8 @@ class LinePlot(Plot):
|
||||
stroke_dash_legend_title: The title given to the stroke_dash legend. By default, uses the value of the stroke_dash parameter.
|
||||
color_legend_position: The position of the color legend. If the string value 'none' is passed, this legend is omitted. For other valid position values see: https://vega.github.io/vega/docs/legends/#orientation.
|
||||
stroke_dash_legend_position: The position of the stoke_dash legend. If the string value 'none' is passed, this legend is omitted. For other valid position values see: https://vega.github.io/vega/docs/legends/#orientation.
|
||||
height: The height of the plot, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
||||
width: The width of the plot, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
||||
height: The height of the plot in pixels.
|
||||
width: The width of the plot in pixels. If None, expands to fit.
|
||||
x_lim: A tuple or list containing the limits for the x-axis, specified as [x_min, x_max].
|
||||
y_lim: A tuple of list containing the limits for the y-axis, specified as [y_min, y_max].
|
||||
caption: The (optional) caption to display below the plot.
|
||||
@ -136,9 +137,21 @@ class LinePlot(Plot):
|
||||
self.y_lim = y_lim
|
||||
self.caption = caption
|
||||
self.interactive_chart = interactive
|
||||
if isinstance(width, str):
|
||||
width = None
|
||||
warnings.warn(
|
||||
"Width should be an integer, not a string. Setting width to None."
|
||||
)
|
||||
if isinstance(height, str):
|
||||
warnings.warn(
|
||||
"Height should be an integer, not a string. Setting height to None."
|
||||
)
|
||||
height = None
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.show_actions_button = show_actions_button
|
||||
if label is None and show_label is None:
|
||||
show_label = False
|
||||
super().__init__(
|
||||
value=value,
|
||||
label=label,
|
||||
@ -234,6 +247,7 @@ class LinePlot(Plot):
|
||||
properties["width"] = width
|
||||
|
||||
if color:
|
||||
color_legend_position = color_legend_position or "bottom"
|
||||
domain = value[color].unique().tolist()
|
||||
range_ = list(range(len(domain)))
|
||||
encodings["color"] = {
|
||||
@ -241,7 +255,7 @@ class LinePlot(Plot):
|
||||
"type": "nominal",
|
||||
"scale": {"domain": domain, "range": range_},
|
||||
"legend": AltairPlot.create_legend(
|
||||
position=color_legend_position, title=color_legend_title or color
|
||||
position=color_legend_position, title=color_legend_title
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Any, Callable, Literal
|
||||
|
||||
from gradio_client.documentation import document
|
||||
@ -77,8 +78,8 @@ class ScatterPlot(Plot):
|
||||
"none",
|
||||
]
|
||||
| None = None,
|
||||
height: int | str | None = None,
|
||||
width: int | str | None = None,
|
||||
height: int | None = None,
|
||||
width: int | None = None,
|
||||
x_lim: list[int | float] | None = None,
|
||||
y_lim: list[int | float] | None = None,
|
||||
caption: str | None = None,
|
||||
@ -116,8 +117,8 @@ class ScatterPlot(Plot):
|
||||
color_legend_position: The position of the color legend. If the string value 'none' is passed, this legend is omitted. For other valid position values see: https://vega.github.io/vega/docs/legends/#orientation.
|
||||
size_legend_position: The position of the size legend. If the string value 'none' is passed, this legend is omitted. For other valid position values see: https://vega.github.io/vega/docs/legends/#orientation.
|
||||
shape_legend_position: The position of the shape legend. If the string value 'none' is passed, this legend is omitted. For other valid position values see: https://vega.github.io/vega/docs/legends/#orientation.
|
||||
height: The height of the plot, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
||||
width: The width of the plot, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
||||
height: The height of the plot in pixels.
|
||||
width: The width of the plot in pixels. If None, expands to fit.
|
||||
x_lim: A tuple or list containing the limits for the x-axis, specified as [x_min, x_max].
|
||||
y_lim: A tuple of list containing the limits for the y-axis, specified as [y_min, y_max].
|
||||
caption: The (optional) caption to display below the plot.
|
||||
@ -151,11 +152,23 @@ class ScatterPlot(Plot):
|
||||
self.shape_legend_position = shape_legend_position
|
||||
self.caption = caption
|
||||
self.interactive_chart = interactive
|
||||
if isinstance(width, str):
|
||||
width = None
|
||||
warnings.warn(
|
||||
"Width should be an integer, not a string. Setting width to None."
|
||||
)
|
||||
if isinstance(height, str):
|
||||
warnings.warn(
|
||||
"Height should be an integer, not a string. Setting height to None."
|
||||
)
|
||||
height = None
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.x_lim = x_lim
|
||||
self.y_lim = y_lim
|
||||
self.show_actions_button = show_actions_button
|
||||
if label is None and show_label is None:
|
||||
show_label = False
|
||||
super().__init__(
|
||||
value=value,
|
||||
label=label,
|
||||
@ -273,11 +286,12 @@ class ScatterPlot(Plot):
|
||||
range_ = list(range(len(domain)))
|
||||
type_ = "nominal"
|
||||
|
||||
color_legend_position = color_legend_position or "bottom"
|
||||
encodings["color"] = {
|
||||
"field": color,
|
||||
"type": type_,
|
||||
"legend": AltairPlot.create_legend(
|
||||
position=color_legend_position, title=color_legend_title or color
|
||||
position=color_legend_position, title=color_legend_title
|
||||
),
|
||||
"scale": {"domain": domain, "range": range_},
|
||||
}
|
||||
@ -288,7 +302,7 @@ class ScatterPlot(Plot):
|
||||
"field": size,
|
||||
"type": "quantitative" if is_numeric_dtype(value[size]) else "nominal",
|
||||
"legend": AltairPlot.create_legend(
|
||||
position=size_legend_position, title=size_legend_title or size
|
||||
position=size_legend_position, title=size_legend_title
|
||||
),
|
||||
}
|
||||
if shape:
|
||||
@ -296,7 +310,7 @@ class ScatterPlot(Plot):
|
||||
"field": shape,
|
||||
"type": "quantitative" if is_numeric_dtype(value[shape]) else "nominal",
|
||||
"legend": AltairPlot.create_legend(
|
||||
position=shape_legend_position, title=shape_legend_title or shape
|
||||
position=shape_legend_position, title=shape_legend_title
|
||||
),
|
||||
}
|
||||
chart = (
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { Template, Story } from "@storybook/addon-svelte-csf";
|
||||
import PlotComponent from "./Index.svelte";
|
||||
import { allModes } from "../storybook/modes";
|
||||
import { test_plot } from "./testplot";
|
||||
import { matplotlib_plot } from "./testplot";
|
||||
|
||||
export const meta = {
|
||||
title: "Components/Plot",
|
||||
@ -23,13 +23,54 @@
|
||||
</Template>
|
||||
|
||||
<Story
|
||||
name="with value"
|
||||
name="with matplotlib value"
|
||||
args={{
|
||||
value: test_plot,
|
||||
value: matplotlib_plot,
|
||||
label: "Plot"
|
||||
}}
|
||||
/>
|
||||
|
||||
<!--
|
||||
<Story
|
||||
name="with line plot value"
|
||||
args={{
|
||||
value: line_plot
|
||||
}}
|
||||
parameters={{
|
||||
chromatic: { delay: 1000 }
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="with multi-line plot value"
|
||||
args={{
|
||||
value: multi_line_plot
|
||||
}}
|
||||
parameters={{
|
||||
chromatic: { delay: 1000 }
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="with scatter plot value"
|
||||
args={{
|
||||
value: scatter_plot
|
||||
}}
|
||||
parameters={{
|
||||
chromatic: { delay: 1000 }
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="with bar plot value"
|
||||
args={{
|
||||
value: bar_plot
|
||||
}}
|
||||
parameters={{
|
||||
chromatic: { delay: 1000 }
|
||||
}}
|
||||
/> -->
|
||||
|
||||
<Story
|
||||
name="with no value"
|
||||
args={{
|
||||
|
@ -14,8 +14,8 @@
|
||||
"@gradio/utils": "workspace:^",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"plotly.js-dist-min": "^2.10.1",
|
||||
"svelte-vega": "^2.0.0",
|
||||
"vega": "^5.22.1",
|
||||
"vega": "^5.23.0",
|
||||
"vega-embed": "^6.25.0",
|
||||
"vega-lite": "^5.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,235 +1,51 @@
|
||||
<script lang="ts">
|
||||
//@ts-nocheck
|
||||
import Plotly from "plotly.js-dist-min";
|
||||
import { Plot as PlotIcon } from "@gradio/icons";
|
||||
import { colors as color_palette, ordered_colors } from "@gradio/theme";
|
||||
import { get_next_color } from "@gradio/utils";
|
||||
import { Vega } from "svelte-vega";
|
||||
import { afterUpdate, beforeUpdate, onDestroy } from "svelte";
|
||||
import { create_config, bar_plot_header_encoding } from "./utils";
|
||||
import { Empty } from "@gradio/atoms";
|
||||
import type { ThemeMode } from "js/app/src/components/types";
|
||||
|
||||
export let value;
|
||||
export let target;
|
||||
let spec = null;
|
||||
export let target: HTMLElement;
|
||||
export let colors: string[] = [];
|
||||
export let theme_mode: ThemeMode;
|
||||
export let caption: string;
|
||||
export let bokeh_version: string | null;
|
||||
export let show_actions_button: bool;
|
||||
const div_id = `bokehDiv-${Math.random().toString(5).substring(2)}`;
|
||||
|
||||
function get_color(index: number): string {
|
||||
let current_color = colors[index % colors.length];
|
||||
let PlotComponent: any = null;
|
||||
let _type = value?.type;
|
||||
|
||||
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;
|
||||
const plotTypeMapping = {
|
||||
plotly: () => import("./plot_types/PlotlyPlot.svelte"),
|
||||
bokeh: () => import("./plot_types/BokehPlot.svelte"),
|
||||
altair: () => import("./plot_types/AltairPlot.svelte"),
|
||||
matplotlib: () => import("./plot_types/MatplotlibPlot.svelte")
|
||||
};
|
||||
|
||||
$: {
|
||||
let type = value?.type;
|
||||
if (type !== _type) {
|
||||
PlotComponent = null;
|
||||
}
|
||||
return current_color;
|
||||
}
|
||||
|
||||
$: darkmode = theme_mode == "dark";
|
||||
|
||||
$: plot = value?.plot;
|
||||
$: type = value?.type;
|
||||
|
||||
function embed_bokeh(_plot: Record<string, any>, _type: string): void {
|
||||
if (document) {
|
||||
if (document.getElementById(div_id)) {
|
||||
document.getElementById(div_id).innerHTML = "";
|
||||
}
|
||||
}
|
||||
if (_type == "bokeh" && window.Bokeh) {
|
||||
load_bokeh();
|
||||
let plotObj = JSON.parse(_plot);
|
||||
window.Bokeh.embed.embed_item(plotObj, div_id);
|
||||
if (type && type in plotTypeMapping) {
|
||||
plotTypeMapping[type]().then((module) => {
|
||||
PlotComponent = module.default;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$: embed_bokeh(plot, type);
|
||||
|
||||
$: if (type == "altair") {
|
||||
spec = JSON.parse(plot);
|
||||
if (value.chart || "") {
|
||||
const config = create_config(darkmode);
|
||||
spec.config = config;
|
||||
}
|
||||
switch (value.chart || "") {
|
||||
case "scatter":
|
||||
if (spec.encoding.color && spec.encoding.color.type == "nominal") {
|
||||
spec.encoding.color.scale.range = spec.encoding.color.scale.range.map(
|
||||
(e, i) => get_color(i)
|
||||
);
|
||||
} else if (
|
||||
spec.encoding.color &&
|
||||
spec.encoding.color.type == "quantitative"
|
||||
) {
|
||||
spec.encoding.color.scale.range = ["#eff6ff", "#1e3a8a"];
|
||||
spec.encoding.color.scale.range.interpolate = "hsl";
|
||||
}
|
||||
break;
|
||||
case "line":
|
||||
spec.layer.forEach((d) => {
|
||||
if (d.encoding.color) {
|
||||
d.encoding.color.scale.range = d.encoding.color.scale.range.map(
|
||||
(e, i) => get_color(i)
|
||||
);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "bar":
|
||||
if (spec.encoding.color) {
|
||||
spec.encoding.color.scale.range = spec.encoding.color.scale.range.map(
|
||||
(e, i) => get_color(i)
|
||||
);
|
||||
}
|
||||
spec.config.header = bar_plot_header_encoding(darkmode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Plotly
|
||||
let plot_div;
|
||||
let plotly_global_style;
|
||||
|
||||
const main_src = `https://cdn.bokeh.org/bokeh/release/bokeh-${bokeh_version}.min.js`;
|
||||
|
||||
const plugins_src = [
|
||||
`https://cdn.pydata.org/bokeh/release/bokeh-widgets-${bokeh_version}.min.js`,
|
||||
`https://cdn.pydata.org/bokeh/release/bokeh-tables-${bokeh_version}.min.js`,
|
||||
`https://cdn.pydata.org/bokeh/release/bokeh-gl-${bokeh_version}.min.js`,
|
||||
`https://cdn.pydata.org/bokeh/release/bokeh-api-${bokeh_version}.min.js`
|
||||
];
|
||||
|
||||
function load_plugins(): HTMLScriptElement[] {
|
||||
return plugins_src.map((src, i) => {
|
||||
const script = document.createElement("script");
|
||||
script.src = src;
|
||||
document.head.appendChild(script);
|
||||
|
||||
return script;
|
||||
});
|
||||
}
|
||||
|
||||
function load_bokeh(): HTMLScriptElement {
|
||||
const script = document.createElement("script");
|
||||
script.onload = handle_bokeh_loaded;
|
||||
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);
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
function load_plotly_css(): void {
|
||||
if (!plotly_global_style) {
|
||||
plotly_global_style = document.getElementById("plotly.js-style-global");
|
||||
const plotly_style_clone = plotly_global_style.cloneNode();
|
||||
target.appendChild(plotly_style_clone);
|
||||
for (const rule of plotly_global_style.sheet.cssRules) {
|
||||
plotly_style_clone.sheet.insertRule(rule.cssText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const main_script = bokeh_version ? load_bokeh() : null;
|
||||
|
||||
let plugin_scripts = [];
|
||||
|
||||
function handle_bokeh_loaded(): void {
|
||||
plugin_scripts = load_plugins();
|
||||
}
|
||||
|
||||
afterUpdate(() => {
|
||||
if (type == "plotly") {
|
||||
load_plotly_css();
|
||||
let plotObj = JSON.parse(plot);
|
||||
plotObj.layout.title
|
||||
? (plotObj.layout.margin = { autoexpand: true })
|
||||
: (plotObj.layout.margin = { l: 0, r: 0, b: 0, t: 0 });
|
||||
Plotly.react(plot_div, plotObj);
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (main_script in document.children) {
|
||||
document.removeChild(main_script);
|
||||
plugin_scripts.forEach((child) => document.removeChild(child));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if value && type == "plotly"}
|
||||
<div data-testid={"plotly"} bind:this={plot_div} />
|
||||
{:else if type == "bokeh"}
|
||||
<div data-testid={"bokeh"} id={div_id} class="gradio-bokeh" />
|
||||
{:else if type == "altair"}
|
||||
<div data-testid={"altair"} class="altair layout">
|
||||
<Vega {spec} options={{ actions: show_actions_button }} />
|
||||
{#if caption}
|
||||
<div class="caption layout">
|
||||
{caption}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if type == "matplotlib"}
|
||||
<div data-testid={"matplotlib"} class="matplotlib layout">
|
||||
<img src={plot} alt={`${value.chart} plot visualising provided data`} />
|
||||
</div>
|
||||
{#if value && PlotComponent}
|
||||
<svelte:component
|
||||
this={PlotComponent}
|
||||
{value}
|
||||
{target}
|
||||
{colors}
|
||||
{theme_mode}
|
||||
{caption}
|
||||
{bokeh_version}
|
||||
{show_actions_button}
|
||||
/>
|
||||
{:else}
|
||||
<Empty unpadded_box={true} size="large"><PlotIcon /></Empty>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.altair :global(canvas) {
|
||||
max-width: 100%;
|
||||
padding: 6px;
|
||||
}
|
||||
.altair :global(.vega-embed) {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.altair :global(.vega-actions) {
|
||||
right: 0px !important;
|
||||
}
|
||||
.gradio-bokeh {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.matplotlib img {
|
||||
object-fit: contain;
|
||||
}
|
||||
</style>
|
||||
|
107
js/plot/shared/plot_types/AltairPlot.svelte
Normal file
107
js/plot/shared/plot_types/AltairPlot.svelte
Normal file
@ -0,0 +1,107 @@
|
||||
<script lang="ts">
|
||||
//@ts-nocheck
|
||||
import { set_config } from "./altair_utils";
|
||||
import { afterUpdate, onDestroy } from "svelte";
|
||||
import type { TopLevelSpec as Spec } from "vega-lite";
|
||||
import vegaEmbed from "vega-embed";
|
||||
|
||||
export let value;
|
||||
export let target: HTMLDivElement;
|
||||
export let colors: string[] = [];
|
||||
export let caption: string;
|
||||
export let show_actions_button: bool;
|
||||
let element: HTMLElement;
|
||||
let parent_element: HTMLElement;
|
||||
|
||||
let computed_style = window.getComputedStyle(target);
|
||||
|
||||
let old_spec: Spec;
|
||||
let spec_width: number;
|
||||
$: plot = value?.plot;
|
||||
$: spec = JSON.parse(plot) as Spec;
|
||||
$: if (old_spec !== spec) {
|
||||
old_spec = spec;
|
||||
spec_width = spec.width;
|
||||
}
|
||||
|
||||
$: if (value.chart) {
|
||||
spec = set_config(spec, computed_style, value.chart as string, colors);
|
||||
}
|
||||
$: fit_width_to_parent =
|
||||
spec.encoding?.column?.field || spec.encoding?.row?.field ? false : true; // vega seems to glitch with width when orientation is set
|
||||
|
||||
const renderPlot = (): void => {
|
||||
if (fit_width_to_parent) {
|
||||
spec.width = Math.min(
|
||||
parent_element.offsetWidth,
|
||||
spec_width || parent_element.offsetWidth
|
||||
);
|
||||
}
|
||||
vegaEmbed(element, spec, { actions: show_actions_button });
|
||||
};
|
||||
let resizeObserver = new ResizeObserver(() => {
|
||||
if (fit_width_to_parent && spec.width !== parent_element.offsetWidth) {
|
||||
renderPlot();
|
||||
}
|
||||
});
|
||||
afterUpdate(() => {
|
||||
renderPlot();
|
||||
resizeObserver.observe(parent_element);
|
||||
});
|
||||
onDestroy(() => {
|
||||
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>
|
81
js/plot/shared/plot_types/BokehPlot.svelte
Normal file
81
js/plot/shared/plot_types/BokehPlot.svelte
Normal file
@ -0,0 +1,81 @@
|
||||
<script lang="ts">
|
||||
//@ts-nocheck
|
||||
import { onDestroy } from "svelte";
|
||||
|
||||
export let value;
|
||||
export let bokeh_version: string | null;
|
||||
const div_id = `bokehDiv-${Math.random().toString(5).substring(2)}`;
|
||||
|
||||
$: plot = value?.plot;
|
||||
|
||||
function embed_bokeh(_plot: Record<string, any>): void {
|
||||
if (document) {
|
||||
if (document.getElementById(div_id)) {
|
||||
document.getElementById(div_id).innerHTML = "";
|
||||
}
|
||||
}
|
||||
if (window.Bokeh) {
|
||||
load_bokeh();
|
||||
let plotObj = JSON.parse(_plot);
|
||||
window.Bokeh.embed.embed_item(plotObj, div_id);
|
||||
}
|
||||
}
|
||||
|
||||
$: embed_bokeh(plot);
|
||||
|
||||
const main_src = `https://cdn.bokeh.org/bokeh/release/bokeh-${bokeh_version}.min.js`;
|
||||
|
||||
const plugins_src = [
|
||||
`https://cdn.pydata.org/bokeh/release/bokeh-widgets-${bokeh_version}.min.js`,
|
||||
`https://cdn.pydata.org/bokeh/release/bokeh-tables-${bokeh_version}.min.js`,
|
||||
`https://cdn.pydata.org/bokeh/release/bokeh-gl-${bokeh_version}.min.js`,
|
||||
`https://cdn.pydata.org/bokeh/release/bokeh-api-${bokeh_version}.min.js`
|
||||
];
|
||||
|
||||
function load_plugins(): HTMLScriptElement[] {
|
||||
return plugins_src.map((src, i) => {
|
||||
const script = document.createElement("script");
|
||||
script.src = src;
|
||||
document.head.appendChild(script);
|
||||
|
||||
return script;
|
||||
});
|
||||
}
|
||||
|
||||
function load_bokeh(): HTMLScriptElement {
|
||||
const script = document.createElement("script");
|
||||
script.onload = handle_bokeh_loaded;
|
||||
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);
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
const main_script = bokeh_version ? load_bokeh() : null;
|
||||
|
||||
let plugin_scripts = [];
|
||||
|
||||
function handle_bokeh_loaded(): void {
|
||||
plugin_scripts = load_plugins();
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (main_script in document.children) {
|
||||
document.removeChild(main_script);
|
||||
plugin_scripts.forEach((child) => document.removeChild(child));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div data-testid={"bokeh"} id={div_id} class="gradio-bokeh" />
|
||||
|
||||
<style>
|
||||
.gradio-bokeh {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
24
js/plot/shared/plot_types/MatplotlibPlot.svelte
Normal file
24
js/plot/shared/plot_types/MatplotlibPlot.svelte
Normal file
@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
export let value;
|
||||
|
||||
$: plot = 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>
|
35
js/plot/shared/plot_types/PlotlyPlot.svelte
Normal file
35
js/plot/shared/plot_types/PlotlyPlot.svelte
Normal file
@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
//@ts-nocheck
|
||||
import Plotly from "plotly.js-dist-min";
|
||||
import { afterUpdate } from "svelte";
|
||||
|
||||
export let value;
|
||||
export let target;
|
||||
|
||||
$: plot = value?.plot;
|
||||
|
||||
let plot_div;
|
||||
let plotly_global_style;
|
||||
|
||||
function load_plotly_css(): void {
|
||||
if (!plotly_global_style) {
|
||||
plotly_global_style = document.getElementById("plotly.js-style-global");
|
||||
const plotly_style_clone = plotly_global_style.cloneNode();
|
||||
target.appendChild(plotly_style_clone);
|
||||
for (const rule of plotly_global_style.sheet.cssRules) {
|
||||
plotly_style_clone.sheet.insertRule(rule.cssText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterUpdate(() => {
|
||||
load_plotly_css();
|
||||
let plotObj = JSON.parse(plot);
|
||||
plotObj.layout.title
|
||||
? (plotObj.layout.margin = { autoexpand: true })
|
||||
: (plotObj.layout.margin = { l: 0, r: 0, b: 0, t: 0 });
|
||||
Plotly.react(plot_div, plotObj);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div data-testid={"plotly"} bind:this={plot_div} />
|
111
js/plot/shared/plot_types/altair_utils.ts
Normal file
111
js/plot/shared/plot_types/altair_utils.ts
Normal 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 };
|
||||
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;
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import type { Config as VegaConfig } from "vega";
|
||||
|
||||
export const dark = "#e2e8f0";
|
||||
export const light = "#111827";
|
||||
|
||||
export function create_config(darkmode: boolean): VegaConfig {
|
||||
return {
|
||||
axis: {
|
||||
labelFont: "sans-serif",
|
||||
labelColor: darkmode ? dark : light,
|
||||
titleFont: "sans-serif",
|
||||
titleColor: darkmode ? dark : light,
|
||||
tickColor: "#aaa",
|
||||
gridColor: "#aaa",
|
||||
titleFontWeight: "normal",
|
||||
labelFontWeight: "normal"
|
||||
},
|
||||
legend: {
|
||||
labelColor: darkmode ? dark : light,
|
||||
labelFont: "sans-serif",
|
||||
titleColor: darkmode ? dark : light,
|
||||
titleFont: "sans-serif",
|
||||
titleFontWeight: "normal",
|
||||
labelFontWeight: "normal"
|
||||
},
|
||||
title: {
|
||||
color: darkmode ? dark : light,
|
||||
font: "sans-serif",
|
||||
fontWeight: "normal",
|
||||
anchor: "middle"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function bar_plot_header_encoding(darkmode: boolean): {
|
||||
labelFont: string;
|
||||
labelColor: string;
|
||||
} {
|
||||
return { labelFont: "sans-serif", labelColor: darkmode ? dark : light };
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1564,12 +1564,12 @@ importers:
|
||||
plotly.js-dist-min:
|
||||
specifier: ^2.10.1
|
||||
version: 2.10.1
|
||||
svelte-vega:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(svelte@4.2.15)(vega-lite@5.12.0(vega@5.23.0))(vega@5.23.0)
|
||||
vega:
|
||||
specifier: ^5.22.1
|
||||
specifier: ^5.23.0
|
||||
version: 5.23.0
|
||||
vega-embed:
|
||||
specifier: ^6.25.0
|
||||
version: 6.25.0(vega-lite@5.12.0(vega@5.23.0))(vega@5.23.0)
|
||||
vega-lite:
|
||||
specifier: ^5.12.0
|
||||
version: 5.12.0(vega@5.23.0)
|
||||
@ -8755,13 +8755,6 @@ packages:
|
||||
svelte-range-slider-pips@2.0.1:
|
||||
resolution: {integrity: sha512-sCHvcTgi0ZYE4c/mwSsdALRsfuqEmpwTsSUdL+PUrumZ8u2gv1GKwZ3GohcAcTB6gfmqRBkyn6ujRXrOIga1gw==}
|
||||
|
||||
svelte-vega@2.0.0:
|
||||
resolution: {integrity: sha512-WnJM+hQNw15VAUtwT6oteog3+0KRw8i8K02gAB4VLM0RYs2NXxBZ1q/BdOvkl1XVnZytRVlLr1HQgxeZs7QwUA==}
|
||||
peerDependencies:
|
||||
svelte: ^3.54.0
|
||||
vega: '*'
|
||||
vega-lite: '*'
|
||||
|
||||
svelte2tsx@0.7.7:
|
||||
resolution: {integrity: sha512-HAIxtk5TUHXvCRKApKfxoh1BGT85S/17lS3DvbfxRKFd+Ghr5YScqBvd+sU+p7vJFw48LNkzdFk+ooNVk3e4kA==}
|
||||
peerDependencies:
|
||||
@ -8937,9 +8930,6 @@ packages:
|
||||
tslib@1.14.1:
|
||||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
||||
|
||||
tslib@2.4.1:
|
||||
resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
|
||||
|
||||
tslib@2.5.3:
|
||||
resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==}
|
||||
|
||||
@ -9179,13 +9169,11 @@ packages:
|
||||
vega-dataflow@5.7.5:
|
||||
resolution: {integrity: sha512-EdsIl6gouH67+8B0f22Owr2tKDiMPNNR8lEvJDcxmFw02nXd8juimclpLvjPQriqn6ta+3Dn5txqfD117H04YA==}
|
||||
|
||||
vega-embed@6.23.0:
|
||||
resolution: {integrity: sha512-8Iava57LdROsatqsOhMLErHYaBpZBB7yZJlSVU3/xOK3l8Ft5WFnj5fm3OOAVML97/0yULE7LRVjXW5hV3fSpg==}
|
||||
vega-embed@6.25.0:
|
||||
resolution: {integrity: sha512-pK99jEhZPNYgx4daiYDyNZ7f1h2ep5PyzMYN/qKzJNxzcaNf8wgmUjHrWeJSeMh8RNyw89VRphIleeg7LNLhDA==}
|
||||
peerDependencies:
|
||||
vega: ^5.21.0
|
||||
vega-lite: '*'
|
||||
bundledDependencies:
|
||||
- yallist
|
||||
|
||||
vega-encode@4.9.2:
|
||||
resolution: {integrity: sha512-c3J0LYkgYeXQxwnYkEzL15cCFBYPRaYUon8O2SZ6O4PhH4dfFTXBzSyT8+gh8AhBd572l2yGDfxpEYA6pOqdjg==}
|
||||
@ -9269,8 +9257,8 @@ packages:
|
||||
vega-time@2.1.1:
|
||||
resolution: {integrity: sha512-z1qbgyX0Af2kQSGFbApwBbX2meenGvsoX8Nga8uyWN8VIbiySo/xqizz1KrP6NbB6R+x5egKmkjdnyNThPeEWA==}
|
||||
|
||||
vega-tooltip@0.33.0:
|
||||
resolution: {integrity: sha512-jMcvH2lP20UfyvO2KAEdloiwRyasikaiLuNFhzwrrzf2RamGTxP4G7B2OZ2QENfrGUH05Z9ei5tn/eErdzOaZQ==}
|
||||
vega-tooltip@0.34.0:
|
||||
resolution: {integrity: sha512-TtxwkcLZ5aWQTvKGlfWDou8tISGuxmqAW1AgGZjrDpf75qsXvgtbPdRAAls2LZMqDxpr5T1kMEZs9XbSpiI8yw==}
|
||||
|
||||
vega-transforms@4.10.2:
|
||||
resolution: {integrity: sha512-sJELfEuYQ238PRG+GOqQch8D69RYnJevYSGLsRGQD2LxNz3j+GlUX6Pid+gUEH5HJy22Q5L0vsTl2ZNhIr4teQ==}
|
||||
@ -15226,7 +15214,7 @@ snapshots:
|
||||
'@formatjs/ecma402-abstract': 1.11.4
|
||||
'@formatjs/fast-memoize': 1.2.1
|
||||
'@formatjs/icu-messageformat-parser': 2.1.0
|
||||
tslib: 2.4.1
|
||||
tslib: 2.6.2
|
||||
|
||||
invariant@2.2.4:
|
||||
dependencies:
|
||||
@ -17442,14 +17430,6 @@ snapshots:
|
||||
|
||||
svelte-range-slider-pips@2.0.1: {}
|
||||
|
||||
svelte-vega@2.0.0(svelte@4.2.15)(vega-lite@5.12.0(vega@5.23.0))(vega@5.23.0):
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
svelte: 4.2.15
|
||||
vega: 5.23.0
|
||||
vega-embed: 6.23.0(vega-lite@5.12.0(vega@5.23.0))(vega@5.23.0)
|
||||
vega-lite: 5.12.0(vega@5.23.0)
|
||||
|
||||
svelte2tsx@0.7.7(svelte@4.2.15)(typescript@5.4.5):
|
||||
dependencies:
|
||||
dedent-js: 1.0.1
|
||||
@ -17682,8 +17662,6 @@ snapshots:
|
||||
|
||||
tslib@1.14.1: {}
|
||||
|
||||
tslib@2.4.1: {}
|
||||
|
||||
tslib@2.5.3: {}
|
||||
|
||||
tslib@2.6.2: {}
|
||||
@ -17920,7 +17898,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
vega-embed@6.23.0(vega-lite@5.12.0(vega@5.23.0))(vega@5.23.0):
|
||||
vega-embed@6.25.0(vega-lite@5.12.0(vega@5.23.0))(vega@5.23.0):
|
||||
dependencies:
|
||||
fast-json-patch: 3.1.1
|
||||
json-stringify-pretty-compact: 3.0.0
|
||||
@ -17931,7 +17909,7 @@ snapshots:
|
||||
vega-lite: 5.12.0(vega@5.23.0)
|
||||
vega-schema-url-parser: 2.2.0
|
||||
vega-themes: 2.14.0(vega-lite@5.12.0(vega@5.23.0))(vega@5.23.0)
|
||||
vega-tooltip: 0.33.0
|
||||
vega-tooltip: 0.34.0
|
||||
|
||||
vega-encode@4.9.2:
|
||||
dependencies:
|
||||
@ -18133,7 +18111,7 @@ snapshots:
|
||||
d3-time: 3.1.0
|
||||
vega-util: 1.17.2
|
||||
|
||||
vega-tooltip@0.33.0:
|
||||
vega-tooltip@0.34.0:
|
||||
dependencies:
|
||||
vega-util: 1.17.2
|
||||
|
||||
|
@ -19,7 +19,7 @@ class TestBarPlot:
|
||||
"bokeh_version": "3.0.3",
|
||||
"show_actions_button": False,
|
||||
"proxy_url": None,
|
||||
"show_label": True,
|
||||
"show_label": False,
|
||||
"container": True,
|
||||
"min_width": 160,
|
||||
"scale": None,
|
||||
|
@ -19,7 +19,7 @@ class TestLinePlot:
|
||||
"bokeh_version": "3.0.3",
|
||||
"show_actions_button": False,
|
||||
"proxy_url": None,
|
||||
"show_label": True,
|
||||
"show_label": False,
|
||||
"container": True,
|
||||
"min_width": 160,
|
||||
"scale": None,
|
||||
|
@ -20,7 +20,7 @@ class TestScatterPlot:
|
||||
"bokeh_version": "3.0.3",
|
||||
"show_actions_button": False,
|
||||
"proxy_url": None,
|
||||
"show_label": True,
|
||||
"show_label": False,
|
||||
"container": True,
|
||||
"min_width": 160,
|
||||
"scale": None,
|
||||
|
Loading…
Reference in New Issue
Block a user