Spaces:
Sleeping
Sleeping
"""gr.BarPlot() component.""" | |
from __future__ import annotations | |
import warnings | |
from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence | |
from gradio_client.documentation import document | |
from gradio.components.base import Component | |
from gradio.components.plot import AltairPlot, AltairPlotData, Plot | |
if TYPE_CHECKING: | |
import pandas as pd | |
from gradio.components import Timer | |
class BarPlot(Plot): | |
""" | |
Creates a bar plot component to display data from a pandas DataFrame (as output). As this component does | |
not accept user input, it is rarely used as an input component. | |
Demos: bar_plot | |
""" | |
data_model = AltairPlotData | |
def __init__( | |
self, | |
value: pd.DataFrame | Callable | None = None, | |
x: str | None = None, | |
y: str | None = None, | |
*, | |
color: str | None = None, | |
vertical: bool = True, | |
group: str | None = None, | |
title: str | None = None, | |
tooltip: list[str] | str | None = None, | |
x_title: str | None = None, | |
y_title: str | None = None, | |
x_label_angle: float | None = None, | |
y_label_angle: float | None = None, | |
color_legend_title: str | None = None, | |
group_title: str | None = None, | |
color_legend_position: Literal[ | |
"left", | |
"right", | |
"top", | |
"bottom", | |
"top-left", | |
"top-right", | |
"bottom-left", | |
"bottom-right", | |
"none", | |
] | |
| None = None, | |
height: int | None = None, | |
width: int | None = None, | |
y_lim: list[int] | None = None, | |
caption: str | None = None, | |
interactive: bool | None = True, | |
label: str | None = None, | |
show_label: bool | None = None, | |
container: bool = True, | |
scale: int | None = None, | |
min_width: int = 160, | |
every: Timer | float | None = None, | |
inputs: Component | Sequence[Component] | set[Component] | None = None, | |
visible: bool = True, | |
elem_id: str | None = None, | |
elem_classes: list[str] | str | None = None, | |
render: bool = True, | |
key: int | str | None = None, | |
sort: Literal["x", "y", "-x", "-y"] | None = None, | |
show_actions_button: bool = False, | |
): | |
""" | |
Parameters: | |
value: The pandas dataframe containing the data to display in a scatter plot. If a callable is provided, the function will be called whenever the app loads to set the initial value of the plot. | |
x: Column corresponding to the x axis. | |
y: Column corresponding to the y axis. | |
color: The column to determine the bar color. Must be categorical (discrete values). | |
vertical: If True, the bars will be displayed vertically. If False, the x and y axis will be switched, displaying the bars horizontally. Default is True. | |
group: The column with which to split the overall plot into smaller subplots. | |
title: The title to display on top of the chart. | |
tooltip: The column (or list of columns) to display on the tooltip when a user hovers over a bar. | |
x_title: The title given to the x axis. By default, uses the value of the x parameter. | |
y_title: The title given to the y axis. By default, uses the value of the y parameter. | |
x_label_angle: The angle (in degrees) of the x axis labels. Positive values are clockwise, and negative values are counter-clockwise. | |
y_label_angle: The angle (in degrees) of the y axis labels. Positive values are clockwise, and negative values are counter-clockwise. | |
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 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. | |
label: The (optional) label to display on the top left corner of the plot. | |
show_label: Whether the label should be displayed. | |
every: Continously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer. | |
inputs: Components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change. | |
visible: Whether the plot should be visible. | |
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. | |
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles. | |
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later. | |
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved. | |
sort: Specifies the sorting axis as either "x", "y", "-x" or "-y". If None, no sorting is applied. | |
show_actions_button: Whether to show the actions button on the top right corner of the plot. | |
""" | |
self.x = x | |
self.y = y | |
self.color = color | |
self.vertical = vertical | |
self.group = group | |
self.group_title = group_title | |
self.tooltip = tooltip | |
self.title = title | |
self.x_title = x_title | |
self.y_title = y_title | |
self.x_label_angle = x_label_angle | |
self.y_label_angle = y_label_angle | |
self.color_legend_title = color_legend_title | |
self.group_title = group_title | |
self.color_legend_position = color_legend_position | |
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, | |
show_label=show_label, | |
container=container, | |
scale=scale, | |
min_width=min_width, | |
visible=visible, | |
elem_id=elem_id, | |
elem_classes=elem_classes, | |
render=render, | |
key=key, | |
every=every, | |
inputs=inputs, | |
) | |
def get_block_name(self) -> str: | |
return "plot" | |
def create_plot( | |
value: pd.DataFrame, | |
x: str, | |
y: str, | |
color: str | None = None, | |
vertical: bool = True, | |
group: str | None = None, | |
title: str | None = None, | |
tooltip: list[str] | str | None = None, | |
x_title: str | None = None, | |
y_title: str | None = None, | |
x_label_angle: float | None = None, | |
y_label_angle: float | None = None, | |
color_legend_title: str | None = None, | |
group_title: str | None = None, | |
color_legend_position: Literal[ | |
"left", | |
"right", | |
"top", | |
"bottom", | |
"top-left", | |
"top-right", | |
"bottom-left", | |
"bottom-right", | |
"none", | |
] | |
| 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, | |
): | |
"""Helper for creating the bar plot.""" | |
import altair as alt | |
interactive = True if interactive is None else interactive | |
orientation = {"field": group, "title": group_title} if group else {} | |
x_title = x_title or x | |
y_title = y_title or y | |
# If horizontal, switch x and y | |
if not vertical: | |
y, x = x, y | |
x = f"sum({x}):Q" | |
y_title, x_title = x_title, y_title | |
orientation = {"row": alt.Row(**orientation)} if orientation else {} # type: ignore | |
x_lim = y_lim | |
y_lim = None | |
else: | |
y = f"sum({y}):Q" | |
x_lim = None | |
orientation = {"column": alt.Column(**orientation)} if orientation else {} # type: ignore | |
encodings = dict( | |
x=alt.X( | |
x, # type: ignore | |
title=x_title, # type: ignore | |
scale=AltairPlot.create_scale(x_lim), # type: ignore | |
axis=alt.Axis(labelAngle=x_label_angle) | |
if x_label_angle is not None | |
else alt.Axis(), | |
sort=sort if vertical and sort is not None else None, | |
), | |
y=alt.Y( | |
y, # type: ignore | |
title=y_title, # type: ignore | |
scale=AltairPlot.create_scale(y_lim), # type: ignore | |
axis=alt.Axis(labelAngle=y_label_angle) | |
if y_label_angle is not None | |
else alt.Axis(), | |
sort=sort if not vertical and sort is not None else None, | |
), | |
**orientation, | |
) | |
properties = {} | |
if title: | |
properties["title"] = title | |
if height: | |
properties["height"] = height | |
if width: | |
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"] = { | |
"field": color, | |
"type": "nominal", | |
"scale": {"domain": domain, "range": range_}, | |
"legend": AltairPlot.create_legend( | |
position=color_legend_position, title=color_legend_title | |
), | |
} | |
if tooltip: | |
encodings["tooltip"] = tooltip # type: ignore | |
chart = ( | |
alt.Chart(value) # type: ignore | |
.mark_bar() # type: ignore | |
.encode(**encodings) | |
.properties(background="transparent", **properties) | |
) | |
if interactive: | |
chart = chart.interactive() | |
return chart | |
def preprocess(self, payload: AltairPlotData) -> AltairPlotData: | |
""" | |
Parameters: | |
payload: The data to display in a bar plot. | |
Returns: | |
(Rarely used) passes the data displayed in the bar plot as an AltairPlotData dataclass, which includes the plot information as a JSON string, as well as the type of plot (in this case, "bar"). | |
""" | |
return payload | |
def postprocess(self, value: pd.DataFrame | None) -> AltairPlotData | None: | |
""" | |
Parameters: | |
value: Expects a pandas DataFrame containing the data to display in the bar plot. The DataFrame should contain at least two columns, one for the x-axis (corresponding to this component's `x` argument) and one for the y-axis (corresponding to `y`). | |
Returns: | |
The data to display in a bar plot, in the form of an AltairPlotData dataclass, which includes the plot information as a JSON string, as well as the type of plot (in this case, "bar"). | |
""" | |
# if None or update | |
if value is None: | |
return value | |
if self.x is None or self.y is None: | |
raise ValueError("No value provided for required parameters `x` and `y`.") | |
chart = self.create_plot( | |
value=value, | |
x=self.x, | |
y=self.y, | |
color=self.color, | |
vertical=self.vertical, | |
group=self.group, | |
title=self.title, | |
tooltip=self.tooltip, | |
x_title=self.x_title, | |
y_title=self.y_title, | |
x_label_angle=self.x_label_angle, | |
y_label_angle=self.y_label_angle, | |
color_legend_title=self.color_legend_title, | |
color_legend_position=self.color_legend_position, # type: ignore | |
group_title=self.group_title, | |
y_lim=self.y_lim, | |
interactive=self.interactive_chart, | |
height=self.height, | |
width=self.width, | |
sort=self.sort, # type: ignore | |
) | |
return AltairPlotData(type="altair", plot=chart.to_json(), chart="bar") | |
def example_payload(self) -> Any: | |
return None | |
def example_value(self) -> Any: | |
import pandas as pd | |
return pd.DataFrame({self.x: [1, 2, 3], self.y: [4, 5, 6]}) | |