diff --git a/reflex/__init__.py b/reflex/__init__.py index 1cca8046f..f61f098b9 100644 --- a/reflex/__init__.py +++ b/reflex/__init__.py @@ -14,7 +14,6 @@ from .compiler.utils import get_asset_path from .components import * from .components.base.script import client_side from .components.component import custom_component as memo -from .components.graphing.victory import data as data from .config import Config as Config from .config import DBConfig as DBConfig from .constants import Env as Env diff --git a/reflex/components/__init__.py b/reflex/components/__init__.py index f9a580032..4dfe5d9c9 100644 --- a/reflex/components/__init__.py +++ b/reflex/components/__init__.py @@ -140,21 +140,7 @@ slider_track = SliderTrack.create switch = Switch.create text_area = TextArea.create upload = Upload.create -area = Area.create -bar = Bar.create -box_plot = BoxPlot.create -candlestick = Candlestick.create -chart = Chart.create -chart_group = ChartGroup.create -chart_stack = ChartStack.create -error_bar = ErrorBar.create -histogram = Histogram.create -line = Line.create -pie = Pie.create -plotly = Plotly.create -polar = Polar.create -scatter = Scatter.create -voronoi = Voronoi.create + box = Box.create center = Center.create circle = Circle.create @@ -246,3 +232,44 @@ kbd = KeyboardKey.create color_mode_button = ColorModeButton.create color_mode_icon = ColorModeIcon.create color_mode_switch = ColorModeSwitch.create + +area_chart = AreaChart.create +bar_chart = BarChart.create +line_chart = LineChart.create +composed_chart = ComposedChart.create +pie_chart = PieChart.create +radar_chart = RadarChart.create +radial_bar_chart = RadialBarChart.create +scatter_chart = ScatterChart.create +funnel_chart = FunnelChart.create +treemap = Treemap.create + + +area = Area.create +bar = Bar.create +line = Line.create +scatter = Scatter.create +x_axis = XAxis.create +y_axis = YAxis.create +z_axis = ZAxis.create +brush = Brush.create +cartesian_axis = CartesianAxis.create +cartesian_grid = CartesianGrid.create +reference_line = ReferenceLine.create +reference_dot = ReferenceDot.create +reference_area = ReferenceArea.create +error_bar = ErrorBar.create +funnel = Funnel.create + +responsive_container = ResponsiveContainer.create +legend = Legend.create +graphing_tooltip = GraphingTooltip.create +label = Label.create +label_list = LabelList.create + +pie = Pie.create +radar = Radar.create +radial_bar = RadialBar.create +polar_angle_axis = PolarAngleAxis.create +polar_grid = PolarGrid.create +polar_radius_axis = PolarRadiusAxis.create diff --git a/reflex/components/graphing/__init__.py b/reflex/components/graphing/__init__.py index dd48762e7..6a29ac883 100644 --- a/reflex/components/graphing/__init__.py +++ b/reflex/components/graphing/__init__.py @@ -1,21 +1,6 @@ """Convenience functions to define layout components.""" from .plotly import Plotly -from .victory import ( - Area, - Bar, - BoxPlot, - Candlestick, - Chart, - ChartGroup, - ChartStack, - ErrorBar, - Histogram, - Line, - Pie, - Polar, - Scatter, - Voronoi, -) +from .recharts import * __all__ = [f for f in dir() if f[0].isupper()] # type: ignore diff --git a/reflex/components/graphing/recharts/__init__.py b/reflex/components/graphing/recharts/__init__.py new file mode 100644 index 000000000..a14ee7d76 --- /dev/null +++ b/reflex/components/graphing/recharts/__init__.py @@ -0,0 +1,41 @@ +"""Recharts components.""" + +from .cartesian import ( + Area, + Bar, + Brush, + Cartesian, + CartesianAxis, + CartesianGrid, + ErrorBar, + Funnel, + Line, + ReferenceArea, + ReferenceDot, + ReferenceLine, + Scatter, + XAxis, + YAxis, + ZAxis, +) +from .charts import ( + AreaChart, + BarChart, + ComposedChart, + FunnelChart, + LineChart, + PieChart, + RadarChart, + RadialBarChart, + ScatterChart, + Treemap, +) +from .general import GraphingTooltip, Label, LabelList, Legend, ResponsiveContainer +from .polar import ( + Pie, + PolarAngleAxis, + PolarGrid, + PolarRadiusAxis, + Radar, + RadialBar, +) diff --git a/reflex/components/graphing/recharts/cartesian.py b/reflex/components/graphing/recharts/cartesian.py new file mode 100644 index 000000000..bed45fcf2 --- /dev/null +++ b/reflex/components/graphing/recharts/cartesian.py @@ -0,0 +1,530 @@ +"""Cartesian charts in Recharts.""" +from __future__ import annotations + +from typing import Any, Dict, List, Union + +from reflex.constants import EventTriggers +from reflex.vars import Var + +from .recharts import Recharts + + +class Axis(Recharts): + """A base class for axes in Recharts.""" + + # The key of a group of data which should be unique in an area chart. + data_key: Var[Union[str, int]] + + # If set true, the axis do not display in the chart. + hide: Var[bool] + + # The orientation of axis 'top' | 'bottom' + orientation: Var[str] + + # The type of axis 'number' | 'category' + type_: Var[str] + + # Allow the ticks of XAxis to be decimals or not. + allow_decimals: Var[bool] + + # When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. + allow_data_overflow: Var[bool] + + # Allow the axis has duplicated categorys or not when the type of axis is "category". + allow_duplicated_category: Var[bool] + + # If set false, no axis line will be drawn. If set a object, the option is the configuration of axis line. + axis_line: Var[bool] + + # If set false, no axis tick lines will be drawn. If set a object, the option is the configuration of tick lines. + tick_line: Var[bool] + + # If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. + mirror: Var[bool] + + # Reverse the ticks or not. + reversed: Var[bool] + + # If 'auto' set, the scale function is decided by the type of chart, and the props type. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold' | Function + scale: Var[str] + + # The unit of data displayed in the axis. This option will be used to represent an index unit in a scatter chart. + unit: Var[Union[str, int]] + + # The name of data displayed in the axis. This option will be used to represent an index in a scatter chart. + name: Var[Union[str, int]] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_OVER: lambda: [], + EventTriggers.ON_MOUSE_OUT: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class XAxis(Axis): + """An XAxis component in Recharts.""" + + tag = "XAxis" + + +class YAxis(Axis): + """A YAxis component in Recharts.""" + + tag = "YAxis" + + # The key of data displayed in the axis. + data_key: Var[Union[str, int]] + + +class ZAxis(Recharts): + """A ZAxis component in Recharts.""" + + tag = "ZAxis" + + # The key of data displayed in the axis. + data_key: Var[Union[str, int]] + + # The range of axis. + range: Var[List[int]] + + # The unit of data displayed in the axis. This option will be used to represent an index unit in a scatter chart. + unit: Var[Union[str, int]] + + # The name of data displayed in the axis. This option will be used to represent an index in a scatter chart. + name: Var[Union[str, int]] + + # If 'auto' set, the scale function is decided by the type of chart, and the props type. + scale: Var[str] + + +class Brush(Recharts): + """A Brush component in Recharts.""" + + tag = "Brush" + + # Stroke color + stroke: Var[str] + + # The key of data displayed in the axis. + data_key: Var[Union[str, int]] + + # The x-coordinate of brush. + x: Var[int] + + # The y-coordinate of brush. + y: Var[int] + + # The width of brush. + width: Var[int] + + # The height of brush. + height: Var[int] + + # The data domain of brush, [min, max]. + data: Var[List[Any]] + + # The width of each traveller. + traveller_width: Var[int] + + # The data with gap of refreshing chart. If the option is not set, the chart will be refreshed every time + gap: Var[int] + + # The default start index of brush. If the option is not set, the start index will be 0. + start_index: Var[int] + + # The default end index of brush. If the option is not set, the end index will be 1. + end_index: Var[int] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CHANGE: lambda: [], + } + + +class Cartesian(Recharts): + """A base class for cartesian charts in Recharts.""" + + # The layout of bar in the chart, usually inherited from parent. 'horizontal' | 'vertical' + layout: Var[str] + + # The key of a group of data which should be unique in an area chart. + data_key: Var[Union[str, int]] + + # The id of x-axis which is corresponding to the data. + x_axis_id: Var[Union[str, int]] + + # The id of y-axis which is corresponding to the data. + y_axis_id: Var[Union[str, int]] + + # The type of icon in legend. If set to 'none', no legend item will be rendered. 'line' | 'plainline' | 'square' | 'rect'| 'circle' | 'cross' | 'diamond' | 'square' | 'star' | 'triangle' | 'wye' | 'none'optional + legend_type: Var[str] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_OVER: lambda: [], + EventTriggers.ON_MOUSE_OUT: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class Area(Cartesian): + """An Area component in Recharts.""" + + tag = "Area" + + # The color of the line stroke. + stroke: Var[str] + + # The width of the line stroke. + stroke_width: Var[int] + + # The color of the area fill. + fill: Var[str] + + # The interpolation type of area. And customized interpolation function can be set to type. 'basis' | 'basisClosed' | 'basisOpen' | 'bumpX' | 'bumpY' | 'bump' | 'linear' | 'linearClosed' | 'natural' | 'monotoneX' | 'monotoneY' | 'monotone' | 'step' | 'stepBefore' | 'stepAfter' | + type_: Var[str] + + # If false set, dots will not be drawn. If true set, dots will be drawn which have the props calculated internally. + dot: Var[bool] + + # The dot is shown when user enter an area chart and this chart has tooltip. If false set, no active dot will not be drawn. If true set, active dot will be drawn which have the props calculated internally. + active_dot: Var[bool] + + # If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. + label: Var[bool] + + # The stack id of area, when two areas have the same value axis and same stackId, then the two areas area stacked in order. + stack_id: Var[str] + + # Valid children components + valid_children: List[str] = ["LabelList"] + + +class Bar(Cartesian): + """A Bar component in Recharts.""" + + tag = "Bar" + + # The color of the line stroke. + stroke: Var[str] + + # The width of the line stroke. + stroke_width: Var[int] + + # The width of the line stroke. + fill: Var[str] + + # If false set, background of bars will not be drawn. If true set, background of bars will be drawn which have the props calculated internally. + background: Var[bool] + + # If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. + label: Var[bool] + + # The stack id of bar, when two areas have the same value axis and same stackId, then the two areas area stacked in order. + stack_id: Var[str] + + # Size of the bar + bar_size: Var[int] + + # Max size of the bar + max_bar_size: Var[int] + + # Valid children components + valid_children: List[str] = ["Cell", "LabelList", "ErrorBar"] + + +class Line(Cartesian): + """A Line component in Recharts.""" + + tag = "Line" + + # The interpolation type of line. And customized interpolation function can be set to type. It's the same as type in Area. + type_: Var[str] + + # The color of the line stroke. + stroke: Var[str] + + # The width of the line stroke. + stoke_width: Var[int] + + # The dot is shown when mouse enter a line chart and this chart has tooltip. If false set, no active dot will not be drawn. If true set, active dot will be drawn which have the props calculated internally. + dot: Var[bool] + + # The dot is shown when user enter an area chart and this chart has tooltip. If false set, no active dot will not be drawn. If true set, active dot will be drawn which have the props calculated internally. + active_dot: Var[bool] + + # If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. + label: Var[bool] + + # Hides the line when true, useful when toggling visibility state via legend. + hide: Var[bool] + + # Whether to connect a graph line across null points. + connect_nulls: Var[bool] + + # Valid children components + valid_children: List[str] = ["LabelList", "ErrorBar"] + + +class Scatter(Cartesian): + """A Scatter component in Recharts.""" + + tag = "Scatter" + + # The source data, in which each element is an object. + data: Var[List[Dict[str, Any]]] + + # The id of z-axis which is corresponding to the data. + z_axis_id: Var[str] + + # If false set, line will not be drawn. If true set, line will be drawn which have the props calculated internally. + line: Var[bool] + + # If a string set, specified symbol will be used to show scatter item. 'circle' | 'cross' | 'diamond' | 'square' | 'star' | 'triangle' | 'wye' + shape: Var[str] + + # If 'joint' set, line will generated by just jointing all the points. If 'fitting' set, line will be generated by fitting algorithm. 'joint' | 'fitting' + line_type: Var[str] + + # The fill + fill: Var[str] + + # the name + name: Var[Union[str, int]] + + # Valid children components. + valid_children: List[str] = ["LabelList", "ErrorBar"] + + +class Funnel(Cartesian): + """A Funnel component in Recharts.""" + + tag = "Funnel" + + # The source data, in which each element is an object. + data: Var[List[Dict[str, Any]]] + + # Specifies when the animation should begin, the unit of this option is ms. + animation_begin: Var[int] + + # Specifies the duration of animation, the unit of this option is ms. + animation_duration: Var[int] + + # The type of easing function. 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear' + animation_easing: Var[str] + + # Valid children components + valid_children: List[str] = ["LabelList", "Cell"] + + +class ErrorBar(Recharts): + """An ErrorBar component in Recharts.""" + + tag = "ErrorBar" + + # The direction of error bar. 'x' | 'y' | 'both' + direction: Var[str] + + # The key of a group of data which should be unique in an area chart. + data_key: Var[Union[str, int]] + + # The width of the error bar ends. + width: Var[int] + + # The stroke color of error bar. + stroke: Var[str] + + # The stroke width of error bar. + stroke_width: Var[int] + + +class Reference(Recharts): + """A base class for reference components in Reference.""" + + # The id of x-axis which is corresponding to the data. + x_axis_id: Var[Union[str, int]] + + # The id of y-axis which is corresponding to the data. + y_axis_id: Var[Union[str, int]] + + # If set a string or a number, a vertical line perpendicular to the x-axis specified by xAxisId will be drawn. If the specified x-axis is a number axis, the type of x must be Number. If the specified x-axis is a category axis, the value of x must be one of the categorys, otherwise no line will be drawn. + x: Var[str] + + # If set a string or a number, a horizontal line perpendicular to the y-axis specified by yAxisId will be drawn. If the specified y-axis is a number axis, the type of y must be Number. If the specified y-axis is a category axis, the value of y must be one of the categorys, otherwise no line will be drawn. + y: Var[str] + + # Defines how to draw the reference line if it falls partly outside the canvas. If set to 'discard', the reference line will not be drawn at all. If set to 'hidden', the reference line will be clipped to the canvas. If set to 'visible', the reference line will be drawn completely. If set to 'extendDomain', the domain of the overflown axis will be extended such that the reference line fits into the canvas. + if_overflow: Var[str] + + # If set true, the line will be rendered in front of bars in BarChart, etc. + is_front: Var[bool] + + +class ReferenceLine(Reference): + """A ReferenceLine component in Recharts.""" + + tag = "ReferenceLine" + + # The width of the stroke. + stroke_width: Var[int] + + # Valid children components + valid_children: List[str] = ["Label"] + + +class ReferenceDot(Reference): + """A ReferenceDot component in Recharts.""" + + tag = "ReferenceDot" + + # Valid children components + valid_children: List[str] = ["Label"] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_OVER: lambda: [], + EventTriggers.ON_MOUSE_OUT: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class ReferenceArea(Recharts): + """A ReferenceArea component in Recharts.""" + + tag = "ReferenceArea" + + # Stroke color + stroke: Var[str] + + # Fill color + fill: Var[str] + + # The opacity of area. + fill_opacity: Var[float] + + # The id of x-axis which is corresponding to the data. + x_axis_id: Var[Union[str, int]] + + # The id of y-axis which is corresponding to the data. + y_axis_id: Var[Union[str, int]] + + # A boundary value of the area. If the specified x-axis is a number axis, the type of x must be Number. If the specified x-axis is a category axis, the value of x must be one of the categorys. If one of x1 or x2 is invalidate, the area will cover along x-axis. + x1: Var[Union[str, int]] + + # A boundary value of the area. If the specified x-axis is a number axis, the type of x must be Number. If the specified x-axis is a category axis, the value of x must be one of the categorys. If one of x1 or x2 is invalidate, the area will cover along x-axis. + x2: Var[Union[str, int]] + + # A boundary value of the area. If the specified y-axis is a number axis, the type of y must be Number. If the specified y-axis is a category axis, the value of y must be one of the categorys. If one of y1 or y2 is invalidate, the area will cover along y-axis. + y1: Var[Union[str, int]] + + # A boundary value of the area. If the specified y-axis is a number axis, the type of y must be Number. If the specified y-axis is a category axis, the value of y must be one of the categorys. If one of y1 or y2 is invalidate, the area will cover along y-axis. + y2: Var[Union[str, int]] + + # Defines how to draw the reference line if it falls partly outside the canvas. If set to 'discard', the reference line will not be drawn at all. If set to 'hidden', the reference line will be clipped to the canvas. If set to 'visible', the reference line will be drawn completely. If set to 'extendDomain', the domain of the overflown axis will be extended such that the reference line fits into the canvas. + if_overflow: Var[str] + + # If set true, the line will be rendered in front of bars in BarChart, etc. + is_front: Var[bool] + + # Valid children components + valid_children: List[str] = ["Label"] + + +class Grid(Recharts): + """A base class for grid components in Recharts.""" + + # The x-coordinate of grid. + x: Var[int] + + # The y-coordinate of grid. + y: Var[int] + + # The width of grid. + width: Var[int] + + # The height of grid. + height: Var[int] + + +class CartesianGrid(Grid): + """A CartesianGrid component in Recharts.""" + + tag = "CartesianGrid" + + # The horizontal line configuration. + horizontal: Var[Dict[str, Any]] + + # The vertical line configuration. + vertical: Var[Dict[str, Any]] + + # The background of grid. + fill: Var[str] + + # The opacity of the background used to fill the space between grid lines + fill_opacity: Var[float] + + # The pattern of dashes and gaps used to paint the lines of the grid + stroke_dasharray: Var[str] + + +class CartesianAxis(Grid): + """A CartesianAxis component in Recharts.""" + + tag = "CartesianAxis" + + # The orientation of axis 'top' | 'bottom' | 'left' | 'right' + orientation: Var[str] + + # If set false, no axis line will be drawn. If set a object, the option is the configuration of axis line. + axis_line: Var[bool] + + # If set false, no axis tick lines will be drawn. If set a object, the option is the configuration of tick lines. + tick_line: Var[bool] + + # The length of tick line. + tick_size: Var[int] + + # If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. + interval: Var[str] + + # If set false, no ticks will be drawn. + ticks: Var[bool] + + # If set a string or a number, default label will be drawn, and the option is content. + label: Var[str] + + # If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. + mirror: Var[bool] + + # The margin between tick line and tick. + tick_margin: Var[int] diff --git a/reflex/components/graphing/recharts/charts.py b/reflex/components/graphing/recharts/charts.py new file mode 100644 index 000000000..16e0caf74 --- /dev/null +++ b/reflex/components/graphing/recharts/charts.py @@ -0,0 +1,456 @@ +"""A module that defines the chart components in Recharts.""" +from __future__ import annotations + +from typing import Any, Dict, List, Union + +from reflex.components.component import Component +from reflex.components.graphing.recharts.general import ResponsiveContainer +from reflex.constants import EventTriggers +from reflex.vars import Var + +from .recharts import RechartsCharts + + +class ChartBase(RechartsCharts): + """A component that wraps a Recharts charts.""" + + # The source data, in which each element is an object. + data: Var[List[Dict[str, Any]]] + + # If any two categorical charts(rx.line_chart, rx.area_chart, rx.bar_chart, rx.composed_chart) have the same sync_id, these two charts can sync the position GraphingTooltip, and the start_index, end_index of Brush. + sync_id: Var[str] + + # When sync_id is provided, allows customisation of how the charts will synchronize GraphingTooltips and brushes. Using 'index' (default setting), other charts will reuse current datum's index within the data array. In cases where data does not have the same length, this might yield unexpected results. In that case use 'value' which will try to match other charts values, or a fully custom function which will receive tick, data as argument and should return an index. 'index' | 'value' | function + sync_method: Var[str] + + # The width of chart container. String or Integer + width: Var[Union[str, int]] = "100%" # type: ignore + + # The height of chart container. + height: Var[Union[str, int]] = "100%" # type: ignore + + # The layout of area in the chart. 'horizontal' | 'vertical' + layout: Var[str] + + # The sizes of whitespace around the chart. + margin: Var[Dict[str, Any]] + + # The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand' | 'none' | 'wiggle' | 'silhouette' + stack_offset: Var[str] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + @classmethod + def create(cls, *children, **props) -> Component: + """Create a chart component. + + Args: + *children: The children of the chart component. + **props: The properties of the chart component. + + Returns: + The chart component wrapped in a responsive container. + """ + return ResponsiveContainer.create( + super().create(*children, **props), + width=props.pop("width", "100%"), + height=props.pop("height", "100%"), + ) + + +class AreaChart(ChartBase): + """An Area chart component in Recharts.""" + + tag = "AreaChart" + + # The base value of area. Number | 'dataMin' | 'dataMax' | 'auto' + base_value: Var[Union[int, str]] + + # The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. + stack_offset: Var[str] + + # Valid children components + valid_children: List[str] = [ + "XAxis", + "YAxis", + "ReferenceArea", + "ReferenceDot", + "ReferenceLine", + "Brush", + "CartesianGrid", + "Legend", + "GraphingTooltip", + "Area", + ] + + +class BarChart(ChartBase): + """A Bar chart component in Recharts.""" + + tag = "BarChart" + + # The gap between two bar categories, which can be a percent value or a fixed value. Percentage | Number + bar_category_gap: Var[Union[str, int]] # type: ignore + + # The gap between two bars in the same category, which can be a percent value or a fixed value. Percentage | Number + bar_gap: Var[Union[str, int]] # type: ignore + + # The width of all the bars in the chart. Number + bar_size: Var[int] + + # The maximum width of all the bars in a horizontal BarChart, or maximum height in a vertical BarChart. + max_bar_size: Var[int] + + # The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. + stack_offset: Var[str] + + # If false set, stacked items will be rendered left to right. If true set, stacked items will be rendered right to left. (Render direction affects SVG layering, not x position.) + reverse_stack_order: Var[bool] + + # Valid children components + valid_children: List[str] = [ + "XAxis", + "YAxis", + "ReferenceArea", + "ReferenceDot", + "ReferenceLine", + "Brush", + "CartesianGrid", + "Legend", + "GraphingTooltip", + "Bar", + ] + + +class LineChart(ChartBase): + """A Line chart component in Recharts.""" + + tag = "LineChart" + + # Valid children components + valid_children: List[str] = [ + "XAxis", + "YAxis", + "ReferenceArea", + "ReferenceDot", + "ReferenceLine", + "Brush", + "CartesianGrid", + "Legend", + "GraphingTooltip", + "Line", + ] + + +class ComposedChart(ChartBase): + """A Composed chart component in Recharts.""" + + tag = "ComposedChart" + + # The base value of area. Number | 'dataMin' | 'dataMax' | 'auto' + base_value: Var[Union[int, str]] + + # The gap between two bar categories, which can be a percent value or a fixed value. Percentage | Number + bar_category_gap: Var[Union[str, int]] # type: ignore + + # The gap between two bars in the same category, which can be a percent value or a fixed value. Percentage | Number + bar_gap: Var[int] + + # The width of all the bars in the chart. Number + bar_size: Var[int] + + # If false set, stacked items will be rendered left to right. If true set, stacked items will be rendered right to left. (Render direction affects SVG layering, not x position.) + reverse_stack_order: Var[bool] + + # Valid children components + valid_children: List[str] = [ + "XAxis", + "YAxis", + "ReferenceArea", + "ReferenceDot", + "ReferenceLine", + "Brush", + "CartesianGrid", + "Legend", + "GraphingTooltip", + "Area", + "Line", + "Bar", + ] + + +class PieChart(ChartBase): + """A Pie chart component in Recharts.""" + + tag = "PieChart" + + # Valid children components + valid_children: List[str] = [ + "PolarAngleAxis", + "PolarRadiusAxis", + "PolarGrid", + "Legend", + "GraphingTooltip", + "Pie", + ] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class RadarChart(ChartBase): + """A Radar chart component in Recharts.""" + + tag = "RadarChart" + + # The The x-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of width. Number | Percentage + cx: Var[Union[int, str]] + + # The The y-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of height. Number | Percentage + cy: Var[Union[int, str]] + + # The angle of first radial direction line. + start_angle: Var[int] + + # The angle of last point in the circle which should be startAngle - 360 or startAngle + 360. We'll calculate the direction of chart by 'startAngle' and 'endAngle'. + end_angle: Var[int] + + # The inner radius of first circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number | Percentage + inner_radius: Var[Union[int, str]] + + # The outer radius of last circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number | Percentage + outer_radius: Var[Union[int, str]] + + # Valid children components + valid_children: List[str] = [ + "PolarAngleAxis", + "PolarRadiusAxis", + "PolarGrid", + "Legend", + "GraphingTooltip", + "Radar", + ] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class RadialBarChart(ChartBase): + """A RadialBar chart component in Recharts.""" + + tag = "RadialBarChart" + + # The The x-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of width. Number | Percentage + cx: Var[Union[int, str]] + + # The The y-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of height. Number | Percentage + cy: Var[Union[int, str]] + + # The angle of first radial direction line. + start_angle: Var[int] + + # The angle of last point in the circle which should be startAngle - 360 or startAngle + 360. We'll calculate the direction of chart by 'startAngle' and 'endAngle'. + end_angle: Var[int] + + # The inner radius of first circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number | Percentage + inner_radius: Var[Union[int, str]] + + # The outer radius of last circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number | Percentage + outer_radius: Var[Union[int, str]] + + # The gap between two bar categories, which can be a percent value or a fixed value. Percentage | Number + bar_category_gap: Var[Union[int, str]] + + # The gap between two bars in the same category, which can be a percent value or a fixed value. Percentage | Number + bar_gap: Var[str] + + # The size of each bar. If the barSize is not specified, the size of bar will be calculated by the barCategoryGap, barGap and the quantity of bar groups. + bar_size: Var[int] + + # Valid children components + valid_children: List[str] = [ + "PolarAngleAxis", + "PolarRadiusAxis", + "PolarGrid", + "Legend", + "GraphingTooltip", + "RadialBar", + ] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class ScatterChart(ChartBase): + """A Scatter chart component in Recharts.""" + + tag = "ScatterChart" + + # Valid children components + valid_children: List[str] = [ + "XAxis", + "YAxis", + "ZAxis", + "ReferenceArea", + "ReferenceDot", + "ReferenceLine", + "Brush", + "CartesianGrid", + "Legend", + "GraphingTooltip", + "Scatter", + ] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_OVER: lambda: [], + EventTriggers.ON_MOUSE_OUT: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class FunnelChart(RechartsCharts): + """A Funnel chart component in Recharts.""" + + tag = "FunnelChart" + + # The source data, in which each element is an object. + data: Var[List[Dict[str, Any]]] + + # If any two categorical charts(rx.line_chart, rx.area_chart, rx.bar_chart, rx.composed_chart) have the same sync_id, these two charts can sync the position GraphingTooltip, and the start_index, end_index of Brush. + sync_id: Var[str] + + # When sync_id is provided, allows customisation of how the charts will synchronize GraphingTooltips and brushes. Using 'index' (default setting), other charts will reuse current datum's index within the data array. In cases where data does not have the same length, this might yield unexpected results. In that case use 'value' which will try to match other charts values, or a fully custom function which will receive tick, data as argument and should return an index. 'index' | 'value' | function + sync_method: Var[str] + + # The width of chart container. String or Integer + width: Var[Union[str, int]] = "100%" # type: ignore + + # The height of chart container. + height: Var[Union[str, int]] = "100%" # type: ignore + + # The layout of area in the chart. 'horizontal' | 'vertical' + layout: Var[str] + + # The sizes of whitespace around the chart. + margin: Var[Dict[str, Any]] + + # The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand' | 'none' | 'wiggle' | 'silhouette' + stack_offset: Var[str] + + # The layout of bars in the chart. centeric + layout: Var[str] + + # Valid children components + valid_children: List[str] = ["Legend", "GraphingTooltip", "Funnel"] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class Treemap(RechartsCharts): + """A Treemap chart component in Recharts.""" + + tag = "Treemap" + + # The width of chart container. String or Integer + width: Var[Union[str, int]] = "100%" # type: ignore + + # The height of chart container. + height: Var[Union[str, int]] = "100%" # type: ignore + + # data of treemap. Array + data: Var[List[Dict[str, Any]]] + + # The key of a group of data which should be unique in a treemap. String | Number | Function + data_key: Var[Union[str, int]] + + # The treemap will try to keep every single rectangle's aspect ratio near the aspectRatio given. Number + aspect_ratio: Var[int] + + # If set false, animation of area will be disabled. + is_animation_active: Var[bool] + + # Specifies when the animation should begin, the unit of this option is ms. + animation_begin: Var[int] + + # Specifies the duration of animation, the unit of this option is ms. + animation_duration: Var[int] + + # The type of easing function. 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear' + animation_easing: Var[str] + + @classmethod + def create(cls, *children, **props) -> Component: + """Create a chart component. + + Args: + *children: The children of the chart component. + **props: The properties of the chart component. + + Returns: + The Treemap component wrapped in a responsive container. + """ + return ResponsiveContainer.create( + super().create(*children, **props), + width=props.pop("width", "100%"), + height=props.pop("height", "100%"), + ) diff --git a/reflex/components/graphing/recharts/general.py b/reflex/components/graphing/recharts/general.py new file mode 100644 index 000000000..16f96b31f --- /dev/null +++ b/reflex/components/graphing/recharts/general.py @@ -0,0 +1,166 @@ +"""General components for Recharts.""" +from __future__ import annotations + +from typing import Any, Dict, List, Union + +from reflex.constants import EventTriggers +from reflex.vars import Var + +from .recharts import Recharts + + +class ResponsiveContainer(Recharts): + """A base class for responsive containers in Recharts.""" + + tag = "ResponsiveContainer" + + # The aspect ratio of the container. The final aspect ratio of the SVG element will be (width / height) * aspect. Number + aspect: Var[int] + + # The width of chart container. Can be a number or string + width: Var[Union[int, str]] + + # The height of chart container. Number + height: Var[Union[int, str]] + + # The minimum width of chart container. + min_width: Var[int] + + # The minimum height of chart container. Number + min_height: Var[int] + + # If specified a positive number, debounced function will be used to handle the resize event. + debounce: Var[int] + + # Valid children components + valid_children: List[str] = [ + "AreaChart", + "BarChart", + "LineChart", + "PieChart", + "RadarChart", + "RadialBarChart", + "ScatterChart", + "Treemap", + "ComposedChart", + ] + + +class Legend(Recharts): + """A Legend component in Recharts.""" + + tag = "Legend" + + # The width of legend container. Number + width: Var[int] + + # The height of legend container. Number + height: Var[int] + + # The layout of legend items. 'horizontal' | 'vertical' + layout: Var[str] + + # The alignment of legend items in 'horizontal' direction, which can be 'left', 'center', 'right'. + align: Var[str] + + # The alignment of legend items in 'vertical' direction, which can be 'top', 'middle', 'bottom'. + vertical_align: Var[str] + + # The size of icon in each legend item. + icon_size: Var[int] + + # The type of icon in each legend item. 'line' | 'plainline' | 'square' | 'rect' | 'circle' | 'cross' | 'diamond' | 'star' | 'triangle' | 'wye' + icon_type: Var[str] + + # The width of chart container, usually calculated internally. + chart_width: Var[int] + + # The height of chart container, usually calculated internally. + chart_height: Var[int] + + # The margin of chart container, usually calculated internally. + margin: Var[Dict[str, Any]] + + def get_event_triggers(self) -> dict[str, Union[Var, Any]]: + """Get the event triggers that pass the component's value to the handler. + + Returns: + A dict mapping the event trigger to the var that is passed to the handler. + """ + return { + EventTriggers.ON_CLICK: lambda: [], + EventTriggers.ON_MOUSE_MOVE: lambda: [], + EventTriggers.ON_MOUSE_OVER: lambda: [], + EventTriggers.ON_MOUSE_OUT: lambda: [], + EventTriggers.ON_MOUSE_ENTER: lambda: [], + EventTriggers.ON_MOUSE_LEAVE: lambda: [], + } + + +class GraphingTooltip(Recharts): + """A Tooltip component in Recharts.""" + + tag = "Tooltip" + + # The separator between name and value. + separator: Var[str] + + # The offset size of tooltip. Number + offset: Var[int] + + # When an item of the payload has value null or undefined, this item won't be displayed. + filter_null: Var[bool] + + # If set false, no cursor will be drawn when tooltip is active. + cursor: Var[bool] + + # The box of viewing area, which has the shape of {x: someVal, y: someVal, width: someVal, height: someVal}, usually calculated internally. + view_box: Var[Dict[str, Any]] + + # If set true, the tooltip is displayed. If set false, the tooltip is hidden, usually calculated internally. + active: Var[bool] + + # If this field is set, the tooltip position will be fixed and will not move anymore. + position: Var[Dict[str, Any]] + + # The coordinate of tooltip which is usually calculated internally. + coordinate: Var[Dict[str, Any]] + + +class Label(Recharts): + """A Label component in Recharts.""" + + tag = "Label" + + # The box of viewing area, which has the shape of {x: someVal, y: someVal, width: someVal, height: someVal}, usually calculated internally. + view_box: Var[Dict[str, Any]] + + # The value of label, which can be specified by this props or the children of