flet-charts 0.70.0.dev6316__tar.gz → 0.70.0.dev6333__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flet-charts might be problematic. Click here for more details.
- {flet_charts-0.70.0.dev6316/src/flet_charts.egg-info → flet_charts-0.70.0.dev6333}/PKG-INFO +10 -9
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/README.md +8 -7
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/pyproject.toml +2 -2
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/__init__.py +13 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/bar_chart.py +1 -1
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/candlestick_chart.py +8 -5
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/matplotlib_chart.py +54 -12
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/matplotlib_chart_with_toolbar.py +18 -3
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/plotly_chart.py +14 -4
- flet_charts-0.70.0.dev6333/src/flet_charts/radar_chart.py +214 -0
- flet_charts-0.70.0.dev6333/src/flet_charts/radar_data_set.py +66 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/scatter_chart_spot.py +1 -1
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333/src/flet_charts.egg-info}/PKG-INFO +10 -9
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts.egg-info/SOURCES.txt +4 -0
- flet_charts-0.70.0.dev6333/src/flet_charts.egg-info/requires.txt +1 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/candlestick_chart.dart +9 -16
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/extension.dart +3 -0
- flet_charts-0.70.0.dev6333/src/flutter/flet_charts/lib/src/radar_chart.dart +104 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/utils/bar_chart.dart +12 -18
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/utils/candlestick_chart.dart +12 -11
- flet_charts-0.70.0.dev6333/src/flutter/flet_charts/lib/src/utils/radar_chart.dart +90 -0
- flet_charts-0.70.0.dev6316/src/flet_charts.egg-info/requires.txt +0 -1
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/LICENSE +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/setup.cfg +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/bar_chart_group.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/bar_chart_rod.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/bar_chart_rod_stack_item.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/candlestick_chart_spot.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/chart_axis.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/line_chart.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/line_chart_data.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/line_chart_data_point.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/matplotlib_backends/backend_flet_agg.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/pie_chart.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/pie_chart_section.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/scatter_chart.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/types.py +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts.egg-info/dependency_links.txt +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts.egg-info/top_level.txt +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/CHANGELOG.md +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/LICENSE +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/analysis_options.yaml +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/flet_charts.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/bar_chart.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/line_chart.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/pie_chart.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/scatter_chart.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/utils/charts.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/utils/line_chart.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/utils/pie_chart.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/lib/src/utils/scatter_chart.dart +0 -0
- {flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/pubspec.yaml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-charts
|
|
3
|
-
Version: 0.70.0.
|
|
3
|
+
Version: 0.70.0.dev6333
|
|
4
4
|
Summary: Interactive chart controls for Flet apps.
|
|
5
5
|
Author-email: Flet contributors <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -11,7 +11,7 @@ Project-URL: Issues, https://github.com/flet-dev/flet/issues
|
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: flet==0.70.0.
|
|
14
|
+
Requires-Dist: flet==0.70.0.dev6333
|
|
15
15
|
Dynamic: license-file
|
|
16
16
|
|
|
17
17
|
# flet-charts
|
|
@@ -57,10 +57,11 @@ For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/
|
|
|
57
57
|
|
|
58
58
|
### Available charts
|
|
59
59
|
|
|
60
|
-
- `BarChart`
|
|
61
|
-
- `CandlestickChart`
|
|
62
|
-
- `LineChart`
|
|
63
|
-
- `MatplotlibChart`
|
|
64
|
-
- `PieChart`
|
|
65
|
-
- `PlotlyChart`
|
|
66
|
-
- `
|
|
60
|
+
- [`BarChart`](https://docs.flet.dev/charts/bar_chart/)
|
|
61
|
+
- [`CandlestickChart`](https://docs.flet.dev/charts/candlestick_chart/)
|
|
62
|
+
- [`LineChart`](https://docs.flet.dev/charts/line_chart/)
|
|
63
|
+
- [`MatplotlibChart`](https://docs.flet.dev/charts/matplotlib_chart/)
|
|
64
|
+
- [`PieChart`](https://docs.flet.dev/charts/pie_chart/)
|
|
65
|
+
- [`PlotlyChart`](https://docs.flet.dev/charts/plotly_chart/)
|
|
66
|
+
- [`RadarChart`](https://docs.flet.dev/charts/radar_chart/)
|
|
67
|
+
- [`ScatterChart`](https://docs.flet.dev/charts/scatter_chart/)
|
|
@@ -41,10 +41,11 @@ For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/
|
|
|
41
41
|
|
|
42
42
|
### Available charts
|
|
43
43
|
|
|
44
|
-
- `BarChart`
|
|
45
|
-
- `CandlestickChart`
|
|
46
|
-
- `LineChart`
|
|
47
|
-
- `MatplotlibChart`
|
|
48
|
-
- `PieChart`
|
|
49
|
-
- `PlotlyChart`
|
|
50
|
-
- `
|
|
44
|
+
- [`BarChart`](https://docs.flet.dev/charts/bar_chart/)
|
|
45
|
+
- [`CandlestickChart`](https://docs.flet.dev/charts/candlestick_chart/)
|
|
46
|
+
- [`LineChart`](https://docs.flet.dev/charts/line_chart/)
|
|
47
|
+
- [`MatplotlibChart`](https://docs.flet.dev/charts/matplotlib_chart/)
|
|
48
|
+
- [`PieChart`](https://docs.flet.dev/charts/pie_chart/)
|
|
49
|
+
- [`PlotlyChart`](https://docs.flet.dev/charts/plotly_chart/)
|
|
50
|
+
- [`RadarChart`](https://docs.flet.dev/charts/radar_chart/)
|
|
51
|
+
- [`ScatterChart`](https://docs.flet.dev/charts/scatter_chart/)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flet-charts"
|
|
3
|
-
version = "0.70.0.
|
|
3
|
+
version = "0.70.0.dev6333"
|
|
4
4
|
description = "Interactive chart controls for Flet apps."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Flet contributors", email = "hello@flet.dev" }]
|
|
7
7
|
license = "Apache-2.0"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
|
-
"flet==0.70.0.
|
|
10
|
+
"flet==0.70.0.dev6333",
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
[project.urls]
|
|
@@ -37,6 +37,13 @@ from flet_charts.matplotlib_chart_with_toolbar import MatplotlibChartWithToolbar
|
|
|
37
37
|
from flet_charts.pie_chart import PieChart, PieChartEvent
|
|
38
38
|
from flet_charts.pie_chart_section import PieChartSection
|
|
39
39
|
from flet_charts.plotly_chart import PlotlyChart
|
|
40
|
+
from flet_charts.radar_chart import (
|
|
41
|
+
RadarChart,
|
|
42
|
+
RadarChartEvent,
|
|
43
|
+
RadarChartTitle,
|
|
44
|
+
RadarShape,
|
|
45
|
+
)
|
|
46
|
+
from flet_charts.radar_data_set import RadarDataSet, RadarDataSetEntry
|
|
40
47
|
from flet_charts.scatter_chart import (
|
|
41
48
|
ScatterChart,
|
|
42
49
|
ScatterChartEvent,
|
|
@@ -95,6 +102,12 @@ __all__ = [
|
|
|
95
102
|
"PieChartEvent",
|
|
96
103
|
"PieChartSection",
|
|
97
104
|
"PlotlyChart",
|
|
105
|
+
"RadarChart",
|
|
106
|
+
"RadarChartEvent",
|
|
107
|
+
"RadarChartTitle",
|
|
108
|
+
"RadarDataSet",
|
|
109
|
+
"RadarDataSetEntry",
|
|
110
|
+
"RadarShape",
|
|
98
111
|
"ScatterChart",
|
|
99
112
|
"ScatterChartEvent",
|
|
100
113
|
"ScatterChartSpot",
|
|
@@ -180,7 +180,7 @@ class BarChart(ft.LayoutControl):
|
|
|
180
180
|
|
|
181
181
|
group_alignment: ft.MainAxisAlignment = ft.MainAxisAlignment.SPACE_EVENLY
|
|
182
182
|
"""
|
|
183
|
-
|
|
183
|
+
The alignment of the bar [`groups`][..] within this chart.
|
|
184
184
|
|
|
185
185
|
If set to [`MainAxisAlignment.CENTER`][flet.MainAxisAlignment.CENTER],
|
|
186
186
|
the space between the `groups` can be specified using [`group_spacing`][..].
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/candlestick_chart.py
RENAMED
|
@@ -17,12 +17,14 @@ __all__ = [
|
|
|
17
17
|
class CandlestickChartTooltip:
|
|
18
18
|
"""Configuration of the tooltip for [`CandlestickChart`][(p).]s."""
|
|
19
19
|
|
|
20
|
-
bgcolor: ft.ColorValue = "#
|
|
20
|
+
bgcolor: ft.ColorValue = "#FFFFECEF"
|
|
21
21
|
"""
|
|
22
22
|
Background color applied to the tooltip bubble.
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
|
-
border_radius:
|
|
25
|
+
border_radius: ft.BorderRadiusValue = field(
|
|
26
|
+
default_factory=lambda: ft.BorderRadius.all(4)
|
|
27
|
+
)
|
|
26
28
|
"""
|
|
27
29
|
Corner radius of the tooltip bubble.
|
|
28
30
|
"""
|
|
@@ -159,9 +161,10 @@ class CandlestickChart(ft.LayoutControl):
|
|
|
159
161
|
Enables automatic tooltips and highlighting when hovering the chart.
|
|
160
162
|
"""
|
|
161
163
|
|
|
162
|
-
|
|
164
|
+
show_tooltips_for_selected_spots_only: bool = False
|
|
163
165
|
"""
|
|
164
|
-
|
|
166
|
+
Whether to permanently and only show the tooltips of spots with their
|
|
167
|
+
[`selected`][(p).CandlestickChartSpot.selected] property set to `True`.
|
|
165
168
|
"""
|
|
166
169
|
|
|
167
170
|
long_press_duration: Optional[ft.DurationValue] = None
|
|
@@ -169,7 +172,7 @@ class CandlestickChart(ft.LayoutControl):
|
|
|
169
172
|
The duration of a long press on the chart.
|
|
170
173
|
"""
|
|
171
174
|
|
|
172
|
-
touch_spot_threshold:
|
|
175
|
+
touch_spot_threshold: ft.Number = 4
|
|
173
176
|
"""
|
|
174
177
|
The distance threshold to consider a touch near a candlestick.
|
|
175
178
|
"""
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/matplotlib_chart.py
RENAMED
|
@@ -2,18 +2,22 @@ import asyncio
|
|
|
2
2
|
import logging
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from io import BytesIO
|
|
5
|
-
from typing import Optional
|
|
5
|
+
from typing import Any, Optional
|
|
6
6
|
|
|
7
7
|
import flet as ft
|
|
8
8
|
import flet.canvas as fc
|
|
9
9
|
|
|
10
|
+
_MATPLOTLIB_IMPORT_ERROR: Optional[ImportError] = None
|
|
11
|
+
|
|
10
12
|
try:
|
|
11
|
-
import matplotlib
|
|
12
|
-
from matplotlib.figure import Figure
|
|
13
|
-
except ImportError as e:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
import matplotlib # type: ignore[import]
|
|
14
|
+
from matplotlib.figure import Figure # type: ignore[import]
|
|
15
|
+
except ImportError as e: # pragma: no cover - depends on optional dependency
|
|
16
|
+
matplotlib = None # type: ignore[assignment]
|
|
17
|
+
Figure = Any # type: ignore[assignment]
|
|
18
|
+
_MATPLOTLIB_IMPORT_ERROR = e
|
|
19
|
+
else:
|
|
20
|
+
matplotlib.use("module://flet_charts.matplotlib_backends.backend_flet_agg")
|
|
17
21
|
|
|
18
22
|
__all__ = [
|
|
19
23
|
"MatplotlibChart",
|
|
@@ -23,8 +27,6 @@ __all__ = [
|
|
|
23
27
|
|
|
24
28
|
logger = logging.getLogger("flet-charts.matplotlib")
|
|
25
29
|
|
|
26
|
-
matplotlib.use("module://flet_charts.matplotlib_backends.backend_flet_agg")
|
|
27
|
-
|
|
28
30
|
figure_cursors = {
|
|
29
31
|
"default": None,
|
|
30
32
|
"pointer": ft.MouseCursor.CLICK,
|
|
@@ -36,6 +38,13 @@ figure_cursors = {
|
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
|
|
41
|
+
def _require_matplotlib() -> None:
|
|
42
|
+
if matplotlib is None:
|
|
43
|
+
raise ModuleNotFoundError(
|
|
44
|
+
'Install "matplotlib" Python package to use MatplotlibChart control.'
|
|
45
|
+
) from _MATPLOTLIB_IMPORT_ERROR
|
|
46
|
+
|
|
47
|
+
|
|
39
48
|
@dataclass
|
|
40
49
|
class MatplotlibChartMessageEvent(ft.Event["MatplotlibChart"]):
|
|
41
50
|
message: str
|
|
@@ -86,6 +95,10 @@ class MatplotlibChart(ft.GestureDetector):
|
|
|
86
95
|
Triggers when toolbar buttons status is updated.
|
|
87
96
|
"""
|
|
88
97
|
|
|
98
|
+
def init(self):
|
|
99
|
+
_require_matplotlib()
|
|
100
|
+
super().init()
|
|
101
|
+
|
|
89
102
|
def build(self):
|
|
90
103
|
self.mouse_cursor = ft.MouseCursor.WAIT
|
|
91
104
|
self.__started = False
|
|
@@ -95,7 +108,7 @@ class MatplotlibChart(ft.GestureDetector):
|
|
|
95
108
|
|
|
96
109
|
self.canvas = fc.Canvas(
|
|
97
110
|
# resize_interval=10,
|
|
98
|
-
on_resize=self.
|
|
111
|
+
on_resize=self._on_canvas_resize,
|
|
99
112
|
expand=True,
|
|
100
113
|
)
|
|
101
114
|
self.keyboard_listener = ft.KeyboardListener(
|
|
@@ -246,29 +259,55 @@ class MatplotlibChart(ft.GestureDetector):
|
|
|
246
259
|
)
|
|
247
260
|
|
|
248
261
|
def will_unmount(self):
|
|
262
|
+
"""
|
|
263
|
+
Called when the control is about to be removed from the page.
|
|
264
|
+
"""
|
|
249
265
|
self.figure.canvas.manager.remove_web_socket(self)
|
|
250
266
|
|
|
251
267
|
def home(self):
|
|
268
|
+
"""
|
|
269
|
+
Resets the view to the original state.
|
|
270
|
+
"""
|
|
252
271
|
logger.debug("home)")
|
|
253
272
|
self.send_message({"type": "toolbar_button", "name": "home"})
|
|
254
273
|
|
|
255
274
|
def back(self):
|
|
275
|
+
"""
|
|
276
|
+
Goes back to the previous view.
|
|
277
|
+
"""
|
|
256
278
|
logger.debug("back()")
|
|
257
279
|
self.send_message({"type": "toolbar_button", "name": "back"})
|
|
258
280
|
|
|
259
281
|
def forward(self):
|
|
282
|
+
"""
|
|
283
|
+
Goes forward to the next view.
|
|
284
|
+
"""
|
|
260
285
|
logger.debug("forward)")
|
|
261
286
|
self.send_message({"type": "toolbar_button", "name": "forward"})
|
|
262
287
|
|
|
263
288
|
def pan(self):
|
|
289
|
+
"""
|
|
290
|
+
Activates the pan tool.
|
|
291
|
+
"""
|
|
264
292
|
logger.debug("pan()")
|
|
265
293
|
self.send_message({"type": "toolbar_button", "name": "pan"})
|
|
266
294
|
|
|
267
295
|
def zoom(self):
|
|
296
|
+
"""
|
|
297
|
+
Activates the zoom tool.
|
|
298
|
+
"""
|
|
268
299
|
logger.debug("zoom()")
|
|
269
300
|
self.send_message({"type": "toolbar_button", "name": "zoom"})
|
|
270
301
|
|
|
271
|
-
def download(self, format):
|
|
302
|
+
def download(self, format) -> bytes:
|
|
303
|
+
"""
|
|
304
|
+
Downloads the current figure in the specified format.
|
|
305
|
+
Args:
|
|
306
|
+
format (str): The format to download the figure in (e.g., 'png',
|
|
307
|
+
'jpg', 'svg', etc.).
|
|
308
|
+
Returns:
|
|
309
|
+
bytes: The figure image in the specified format as a byte array.
|
|
310
|
+
"""
|
|
272
311
|
logger.debug(f"Download in format: {format}")
|
|
273
312
|
buff = BytesIO()
|
|
274
313
|
self.figure.savefig(buff, format=format, dpi=self.figure.dpi * self.__dpr)
|
|
@@ -347,23 +386,26 @@ class MatplotlibChart(ft.GestureDetector):
|
|
|
347
386
|
)
|
|
348
387
|
|
|
349
388
|
def send_message(self, message):
|
|
389
|
+
"""Sends a message to the figure's canvas manager."""
|
|
350
390
|
logger.debug(f"send_message({message})")
|
|
351
391
|
manager = self.figure.canvas.manager
|
|
352
392
|
if manager is not None:
|
|
353
393
|
manager.handle_json(message)
|
|
354
394
|
|
|
355
395
|
def send_json(self, content):
|
|
396
|
+
"""Sends a JSON message to the front end."""
|
|
356
397
|
logger.debug(f"send_json: {content}")
|
|
357
398
|
self._main_loop.call_soon_threadsafe(
|
|
358
399
|
lambda: self._receive_queue.put_nowait((False, content))
|
|
359
400
|
)
|
|
360
401
|
|
|
361
402
|
def send_binary(self, blob):
|
|
403
|
+
"""Sends a binary message to the front end."""
|
|
362
404
|
self._main_loop.call_soon_threadsafe(
|
|
363
405
|
lambda: self._receive_queue.put_nowait((True, blob))
|
|
364
406
|
)
|
|
365
407
|
|
|
366
|
-
async def
|
|
408
|
+
async def _on_canvas_resize(self, e: fc.CanvasResizeEvent):
|
|
367
409
|
logger.debug(f"on_canvas_resize: {e.width}, {e.height}")
|
|
368
410
|
|
|
369
411
|
if not self.__started:
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
from dataclasses import field
|
|
2
|
-
|
|
3
|
-
from matplotlib.figure import Figure
|
|
2
|
+
from typing import Any, Optional
|
|
4
3
|
|
|
5
4
|
import flet as ft
|
|
6
5
|
import flet_charts
|
|
7
6
|
|
|
7
|
+
_MATPLOTLIB_IMPORT_ERROR: Optional[ImportError] = None
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from matplotlib.figure import Figure # type: ignore
|
|
11
|
+
except ImportError as e: # pragma: no cover - depends on optional dependency
|
|
12
|
+
Figure = Any # type: ignore[assignment]
|
|
13
|
+
_MATPLOTLIB_IMPORT_ERROR = e
|
|
14
|
+
|
|
8
15
|
_download_formats = [
|
|
9
16
|
"eps",
|
|
10
17
|
"jpeg",
|
|
@@ -19,6 +26,13 @@ _download_formats = [
|
|
|
19
26
|
]
|
|
20
27
|
|
|
21
28
|
|
|
29
|
+
def _require_matplotlib() -> None:
|
|
30
|
+
if _MATPLOTLIB_IMPORT_ERROR is not None:
|
|
31
|
+
raise ModuleNotFoundError(
|
|
32
|
+
'Install "matplotlib" Python package to use MatplotlibChart control.'
|
|
33
|
+
) from _MATPLOTLIB_IMPORT_ERROR
|
|
34
|
+
|
|
35
|
+
|
|
22
36
|
@ft.control(kw_only=True, isolated=True)
|
|
23
37
|
class MatplotlibChartWithToolbar(ft.Column):
|
|
24
38
|
figure: Figure = field(metadata={"skip": True})
|
|
@@ -28,6 +42,7 @@ class MatplotlibChartWithToolbar(ft.Column):
|
|
|
28
42
|
"""
|
|
29
43
|
|
|
30
44
|
def build(self):
|
|
45
|
+
_require_matplotlib()
|
|
31
46
|
self.mpl = flet_charts.MatplotlibChart(
|
|
32
47
|
figure=self.figure,
|
|
33
48
|
expand=True,
|
|
@@ -63,7 +78,7 @@ class MatplotlibChartWithToolbar(ft.Column):
|
|
|
63
78
|
self.msg = ft.Text()
|
|
64
79
|
self.controls = [
|
|
65
80
|
ft.Row(
|
|
66
|
-
[
|
|
81
|
+
controls=[
|
|
67
82
|
self.home_btn,
|
|
68
83
|
self.back_btn,
|
|
69
84
|
self.fwd_btn,
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import xml.etree.ElementTree as ET
|
|
3
3
|
from dataclasses import field
|
|
4
|
+
from typing import Any, Optional
|
|
4
5
|
|
|
5
6
|
import flet as ft
|
|
6
7
|
|
|
8
|
+
_PLOTLY_IMPORT_ERROR: Optional[ImportError] = None
|
|
9
|
+
|
|
7
10
|
try:
|
|
8
11
|
from plotly.graph_objects import Figure
|
|
9
|
-
except ImportError as e:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
) from e
|
|
12
|
+
except ImportError as e: # pragma: no cover - depends on optional dependency
|
|
13
|
+
Figure = Any # type: ignore[assignment]
|
|
14
|
+
_PLOTLY_IMPORT_ERROR = e
|
|
13
15
|
|
|
14
16
|
__all__ = ["PlotlyChart"]
|
|
15
17
|
|
|
16
18
|
|
|
19
|
+
def _require_plotly() -> None:
|
|
20
|
+
if _PLOTLY_IMPORT_ERROR is not None:
|
|
21
|
+
raise ModuleNotFoundError(
|
|
22
|
+
'Install "plotly" Python package to use PlotlyChart control.'
|
|
23
|
+
) from _PLOTLY_IMPORT_ERROR
|
|
24
|
+
|
|
25
|
+
|
|
17
26
|
@ft.control(kw_only=True)
|
|
18
27
|
class PlotlyChart(ft.Container):
|
|
19
28
|
"""
|
|
@@ -41,6 +50,7 @@ class PlotlyChart(ft.Container):
|
|
|
41
50
|
"""
|
|
42
51
|
|
|
43
52
|
def init(self):
|
|
53
|
+
_require_plotly()
|
|
44
54
|
self.alignment = ft.Alignment.CENTER
|
|
45
55
|
self.__img = ft.Image(fit=ft.BoxFit.FILL)
|
|
46
56
|
self.content = self.__img
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import flet as ft
|
|
6
|
+
from flet_charts.radar_data_set import RadarDataSet
|
|
7
|
+
from flet_charts.types import ChartEventType
|
|
8
|
+
|
|
9
|
+
__all__ = ["RadarChart", "RadarChartEvent", "RadarChartTitle", "RadarShape"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RadarShape(Enum):
|
|
13
|
+
"""Shape of the radar grid and data polygons."""
|
|
14
|
+
|
|
15
|
+
CIRCLE = "circle"
|
|
16
|
+
"""Draws radial circles for the grid and data outlines."""
|
|
17
|
+
|
|
18
|
+
POLYGON = "polygon"
|
|
19
|
+
"""Draws straight-edged polygons for the grid and data outlines."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@ft.control("RadarChartTitle")
|
|
23
|
+
class RadarChartTitle(ft.BaseControl):
|
|
24
|
+
"""
|
|
25
|
+
Custom title configuration displayed around a [`RadarChart`][(p).].
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
text: str = ""
|
|
29
|
+
"""
|
|
30
|
+
The text displayed for the title.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
angle: ft.Number = 0
|
|
34
|
+
"""
|
|
35
|
+
Rotation angle (in degrees) applied to the title.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
position_percentage_offset: Optional[ft.Number] = None
|
|
39
|
+
"""
|
|
40
|
+
Defines the relative distance of this title from the chart center.
|
|
41
|
+
|
|
42
|
+
- `0` draws this title near the inside edge of each section.
|
|
43
|
+
- `1` draws this title near the outside edge of each section.
|
|
44
|
+
|
|
45
|
+
Must be between `0` and `1` (inclusive), if set.
|
|
46
|
+
|
|
47
|
+
Note:
|
|
48
|
+
If set, it takes precedence over the parent
|
|
49
|
+
[`RadarChart.title_position_percentage_offset`][(p).] value.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
text_spans: Optional[list[ft.TextSpan]] = None
|
|
53
|
+
"""
|
|
54
|
+
Inline spans appended to the title.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class RadarChartEvent(ft.Event["RadarChart"]):
|
|
60
|
+
"""
|
|
61
|
+
Event raised for interactions with a [`RadarChart`][(p).].
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
type: ChartEventType
|
|
65
|
+
"""
|
|
66
|
+
The touch or pointer event that occurred.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
data_set_index: Optional[int] = None
|
|
70
|
+
"""
|
|
71
|
+
The index of the touched data set, if any.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
entry_index: Optional[int] = None
|
|
75
|
+
"""
|
|
76
|
+
The index of the touched radar entry, if any.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
entry_value: Optional[ft.Number] = None
|
|
80
|
+
"""
|
|
81
|
+
The value of the touched radar entry, if any.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@ft.control("RadarChart")
|
|
86
|
+
class RadarChart(ft.LayoutControl):
|
|
87
|
+
"""
|
|
88
|
+
A radar chart made of multiple datasets.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
data_sets: list[RadarDataSet] = field(default_factory=list)
|
|
92
|
+
"""
|
|
93
|
+
A list of [`RadarDataSet`][(p).] controls rendered on the chart.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
titles: list[RadarChartTitle] = field(default_factory=list)
|
|
97
|
+
"""
|
|
98
|
+
The titles shown around this chart, matching the number of entries per set.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
title_text_style: Optional[ft.TextStyle] = None
|
|
102
|
+
"""
|
|
103
|
+
The text style applied to titles around this chart.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
title_position_percentage_offset: ft.Number = 0.2
|
|
107
|
+
"""
|
|
108
|
+
Defines the relative distance of titles from the chart center.
|
|
109
|
+
|
|
110
|
+
- `0` draws titles near the inside edge of each section.
|
|
111
|
+
- `1` draws titles near the outside edge of each section.
|
|
112
|
+
|
|
113
|
+
Must be between `0` and `1` (inclusive).
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
ValueError: If set to a value less than `0` or greater than `1`.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
radar_bgcolor: ft.ColorValue = ft.Colors.TRANSPARENT
|
|
120
|
+
"""
|
|
121
|
+
The background color of the radar area.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
radar_border_side: ft.BorderSide = field(
|
|
125
|
+
default_factory=lambda: ft.BorderSide(width=2.0)
|
|
126
|
+
)
|
|
127
|
+
"""
|
|
128
|
+
The outline drawn around the radar area.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
radar_shape: RadarShape = RadarShape.POLYGON
|
|
132
|
+
"""
|
|
133
|
+
The shape of the radar area.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
border: Optional[ft.Border] = None
|
|
137
|
+
"""
|
|
138
|
+
The border drawn around this chart.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
center_min_value: bool = False
|
|
142
|
+
"""
|
|
143
|
+
Whether minimum entry values should be positioned at the center of this chart.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
tick_count: ft.Number = 1
|
|
147
|
+
"""
|
|
148
|
+
Number of tick rings drawn from the centre to the edge.
|
|
149
|
+
|
|
150
|
+
Must be greater than or equal to `1`.
|
|
151
|
+
|
|
152
|
+
Raises:
|
|
153
|
+
ValueError: If set to a value less than `1`.
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
ticks_text_style: Optional[ft.TextStyle] = None
|
|
157
|
+
"""
|
|
158
|
+
The text style used to draw tick labels.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
tick_border_side: ft.BorderSide = field(
|
|
162
|
+
default_factory=lambda: ft.BorderSide(width=2.0)
|
|
163
|
+
)
|
|
164
|
+
"""
|
|
165
|
+
The style of the tick rings.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
grid_border_side: ft.BorderSide = field(
|
|
169
|
+
default_factory=lambda: ft.BorderSide(width=2.0)
|
|
170
|
+
)
|
|
171
|
+
"""
|
|
172
|
+
The style of the radar grid lines.
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
animation: ft.AnimationValue = field(
|
|
176
|
+
default_factory=lambda: ft.Animation(
|
|
177
|
+
duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
"""
|
|
181
|
+
Controls the implicit animation applied when updating this chart.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
interactive: bool = True
|
|
185
|
+
"""
|
|
186
|
+
Enables touch interactions and event notifications.
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
long_press_duration: Optional[ft.DurationValue] = None
|
|
190
|
+
"""
|
|
191
|
+
The duration before a long-press event fires.
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
touch_spot_threshold: ft.Number = 10
|
|
195
|
+
"""
|
|
196
|
+
The radius (in logical pixels) used to detect nearby entries for touches.
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
on_event: Optional[ft.EventHandler[RadarChartEvent]] = None
|
|
200
|
+
"""
|
|
201
|
+
Called when the chart is interacted with.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
def init(self):
|
|
205
|
+
super().init()
|
|
206
|
+
entries_lengths = {len(ds.entries) for ds in self.data_sets}
|
|
207
|
+
if len(entries_lengths) > 1:
|
|
208
|
+
raise ValueError(
|
|
209
|
+
"All data sets in the data_sets list must have equal number of entries"
|
|
210
|
+
)
|
|
211
|
+
if not (0 <= self.title_position_percentage_offset <= 1):
|
|
212
|
+
raise ValueError("title_position_percentage_offset must be between 0 and 1")
|
|
213
|
+
if self.tick_count is not None and self.tick_count < 1:
|
|
214
|
+
raise ValueError("tick_count must be greater than or equal to 1")
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from dataclasses import field
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import flet as ft
|
|
5
|
+
|
|
6
|
+
__all__ = ["RadarDataSet", "RadarDataSetEntry"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@ft.control("RadarDataSetEntry")
|
|
10
|
+
class RadarDataSetEntry(ft.BaseControl):
|
|
11
|
+
"""
|
|
12
|
+
A single data point rendered on a [`RadarChart`][(p).].
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
value: ft.Number
|
|
16
|
+
"""
|
|
17
|
+
The numeric value drawn for this entry.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@ft.control("RadarDataSet")
|
|
22
|
+
class RadarDataSet(ft.BaseControl):
|
|
23
|
+
"""
|
|
24
|
+
A collection of [`RadarDataSetEntry`][(p).] drawn as a filled radar shape.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
entries: list[RadarDataSetEntry] = field(default_factory=list)
|
|
28
|
+
"""
|
|
29
|
+
The data points that compose this set.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
fill_color: ft.ColorValue = ft.Colors.CYAN
|
|
33
|
+
"""
|
|
34
|
+
The color used to fill this dataset.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
fill_gradient: Optional[ft.Gradient] = None
|
|
38
|
+
"""
|
|
39
|
+
The gradient used to fill this dataset.
|
|
40
|
+
|
|
41
|
+
Takes precedence over [`fill_color`][..].
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
border_color: ft.ColorValue = ft.Colors.CYAN
|
|
45
|
+
"""
|
|
46
|
+
The color of the dataset outline.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
border_width: ft.Number = 2.0
|
|
50
|
+
"""
|
|
51
|
+
The width of the dataset outline.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
entry_radius: ft.Number = 5.0
|
|
55
|
+
"""
|
|
56
|
+
The radius of each entry.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def init(self):
|
|
60
|
+
super().init()
|
|
61
|
+
entries_length = len(self.entries)
|
|
62
|
+
if entries_length != 0 and entries_length < 3:
|
|
63
|
+
raise ValueError(
|
|
64
|
+
f"entries can contain either 0 or at least 3 items, "
|
|
65
|
+
f"got {entries_length}"
|
|
66
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-charts
|
|
3
|
-
Version: 0.70.0.
|
|
3
|
+
Version: 0.70.0.dev6333
|
|
4
4
|
Summary: Interactive chart controls for Flet apps.
|
|
5
5
|
Author-email: Flet contributors <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -11,7 +11,7 @@ Project-URL: Issues, https://github.com/flet-dev/flet/issues
|
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: flet==0.70.0.
|
|
14
|
+
Requires-Dist: flet==0.70.0.dev6333
|
|
15
15
|
Dynamic: license-file
|
|
16
16
|
|
|
17
17
|
# flet-charts
|
|
@@ -57,10 +57,11 @@ For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/
|
|
|
57
57
|
|
|
58
58
|
### Available charts
|
|
59
59
|
|
|
60
|
-
- `BarChart`
|
|
61
|
-
- `CandlestickChart`
|
|
62
|
-
- `LineChart`
|
|
63
|
-
- `MatplotlibChart`
|
|
64
|
-
- `PieChart`
|
|
65
|
-
- `PlotlyChart`
|
|
66
|
-
- `
|
|
60
|
+
- [`BarChart`](https://docs.flet.dev/charts/bar_chart/)
|
|
61
|
+
- [`CandlestickChart`](https://docs.flet.dev/charts/candlestick_chart/)
|
|
62
|
+
- [`LineChart`](https://docs.flet.dev/charts/line_chart/)
|
|
63
|
+
- [`MatplotlibChart`](https://docs.flet.dev/charts/matplotlib_chart/)
|
|
64
|
+
- [`PieChart`](https://docs.flet.dev/charts/pie_chart/)
|
|
65
|
+
- [`PlotlyChart`](https://docs.flet.dev/charts/plotly_chart/)
|
|
66
|
+
- [`RadarChart`](https://docs.flet.dev/charts/radar_chart/)
|
|
67
|
+
- [`ScatterChart`](https://docs.flet.dev/charts/scatter_chart/)
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts.egg-info/SOURCES.txt
RENAMED
|
@@ -17,6 +17,8 @@ src/flet_charts/matplotlib_chart_with_toolbar.py
|
|
|
17
17
|
src/flet_charts/pie_chart.py
|
|
18
18
|
src/flet_charts/pie_chart_section.py
|
|
19
19
|
src/flet_charts/plotly_chart.py
|
|
20
|
+
src/flet_charts/radar_chart.py
|
|
21
|
+
src/flet_charts/radar_data_set.py
|
|
20
22
|
src/flet_charts/scatter_chart.py
|
|
21
23
|
src/flet_charts/scatter_chart_spot.py
|
|
22
24
|
src/flet_charts/types.py
|
|
@@ -36,10 +38,12 @@ src/flutter/flet_charts/lib/src/candlestick_chart.dart
|
|
|
36
38
|
src/flutter/flet_charts/lib/src/extension.dart
|
|
37
39
|
src/flutter/flet_charts/lib/src/line_chart.dart
|
|
38
40
|
src/flutter/flet_charts/lib/src/pie_chart.dart
|
|
41
|
+
src/flutter/flet_charts/lib/src/radar_chart.dart
|
|
39
42
|
src/flutter/flet_charts/lib/src/scatter_chart.dart
|
|
40
43
|
src/flutter/flet_charts/lib/src/utils/bar_chart.dart
|
|
41
44
|
src/flutter/flet_charts/lib/src/utils/candlestick_chart.dart
|
|
42
45
|
src/flutter/flet_charts/lib/src/utils/charts.dart
|
|
43
46
|
src/flutter/flet_charts/lib/src/utils/line_chart.dart
|
|
44
47
|
src/flutter/flet_charts/lib/src/utils/pie_chart.dart
|
|
48
|
+
src/flutter/flet_charts/lib/src/utils/radar_chart.dart
|
|
45
49
|
src/flutter/flet_charts/lib/src/utils/scatter_chart.dart
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flet==0.70.0.dev6333
|
|
@@ -37,9 +37,6 @@ class _CandlestickChartControlState extends State<CandlestickChartControl> {
|
|
|
37
37
|
final bottomTitles = parseAxisTitles(widget.control.child("bottom_axis"));
|
|
38
38
|
|
|
39
39
|
final interactive = widget.control.getBool("interactive", true)!;
|
|
40
|
-
final handleBuiltInTouches =
|
|
41
|
-
widget.control.getBool("handle_built_in_touches", true)!;
|
|
42
|
-
final touchSpotThreshold = widget.control.getDouble("touch_spot_threshold");
|
|
43
40
|
|
|
44
41
|
final spotControls = widget.control.children("spots");
|
|
45
42
|
final candlestickSpots = spotControls.map((spot) {
|
|
@@ -54,21 +51,12 @@ class _CandlestickChartControlState extends State<CandlestickChartControl> {
|
|
|
54
51
|
);
|
|
55
52
|
}).toList();
|
|
56
53
|
|
|
57
|
-
final selectedIndicators = spotControls
|
|
58
|
-
.asMap()
|
|
59
|
-
.entries
|
|
60
|
-
.where((entry) => entry.value.getBool("selected", false)!)
|
|
61
|
-
.map((entry) => entry.key)
|
|
62
|
-
.toList();
|
|
63
|
-
|
|
64
|
-
final showingIndicators =
|
|
65
|
-
(!interactive || !handleBuiltInTouches) ? selectedIndicators : <int>[];
|
|
66
|
-
|
|
67
54
|
final candlestickTouchData = CandlestickTouchData(
|
|
68
55
|
enabled: interactive && !widget.control.disabled,
|
|
69
|
-
handleBuiltInTouches:
|
|
56
|
+
handleBuiltInTouches: !widget.control
|
|
57
|
+
.getBool("show_tooltips_for_selected_spots_only", false)!,
|
|
70
58
|
longPressDuration: widget.control.getDuration("long_press_duration"),
|
|
71
|
-
touchSpotThreshold:
|
|
59
|
+
touchSpotThreshold: widget.control.getDouble("touch_spot_threshold", 4)!,
|
|
72
60
|
touchTooltipData: parseCandlestickTouchTooltipData(
|
|
73
61
|
context,
|
|
74
62
|
widget.control,
|
|
@@ -112,7 +100,12 @@ class _CandlestickChartControlState extends State<CandlestickChartControl> {
|
|
|
112
100
|
widget.control.get("vertical_grid_lines"),
|
|
113
101
|
theme),
|
|
114
102
|
candlestickTouchData: candlestickTouchData,
|
|
115
|
-
showingTooltipIndicators:
|
|
103
|
+
showingTooltipIndicators: spotControls
|
|
104
|
+
.asMap()
|
|
105
|
+
.entries
|
|
106
|
+
.where((e) => e.value.getBool("selected", false)!)
|
|
107
|
+
.map((e) => e.key)
|
|
108
|
+
.toList(),
|
|
116
109
|
rotationQuarterTurns:
|
|
117
110
|
widget.control.getInt("rotation_quarter_turns", 0)!,
|
|
118
111
|
),
|
|
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|
|
4
4
|
import 'bar_chart.dart';
|
|
5
5
|
import 'candlestick_chart.dart';
|
|
6
6
|
import 'line_chart.dart';
|
|
7
|
+
import 'radar_chart.dart';
|
|
7
8
|
import 'pie_chart.dart';
|
|
8
9
|
import 'scatter_chart.dart';
|
|
9
10
|
|
|
@@ -17,6 +18,8 @@ class Extension extends FletExtension {
|
|
|
17
18
|
return CandlestickChartControl(key: key, control: control);
|
|
18
19
|
case "LineChart":
|
|
19
20
|
return LineChartControl(key: key, control: control);
|
|
21
|
+
case "RadarChart":
|
|
22
|
+
return RadarChartControl(key: key, control: control);
|
|
20
23
|
case "PieChart":
|
|
21
24
|
return PieChartControl(key: key, control: control);
|
|
22
25
|
case "ScatterChart":
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import 'package:fl_chart/fl_chart.dart';
|
|
2
|
+
import 'package:flet/flet.dart';
|
|
3
|
+
import 'package:flutter/material.dart';
|
|
4
|
+
|
|
5
|
+
import 'utils/radar_chart.dart';
|
|
6
|
+
|
|
7
|
+
class RadarChartControl extends StatefulWidget {
|
|
8
|
+
final Control control;
|
|
9
|
+
|
|
10
|
+
RadarChartControl({Key? key, required this.control})
|
|
11
|
+
: super(key: ValueKey("control_${control.id}"));
|
|
12
|
+
|
|
13
|
+
@override
|
|
14
|
+
State<RadarChartControl> createState() => _RadarChartControlState();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class _RadarChartControlState extends State<RadarChartControl> {
|
|
18
|
+
RadarChartEventData? _eventData;
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
Widget build(BuildContext context) {
|
|
22
|
+
debugPrint("RadarChart build: ${widget.control.id}‚");
|
|
23
|
+
|
|
24
|
+
final theme = Theme.of(context);
|
|
25
|
+
final animation = widget.control.getAnimation(
|
|
26
|
+
"animation",
|
|
27
|
+
ImplicitAnimationDetails(
|
|
28
|
+
duration: const Duration(milliseconds: 150),
|
|
29
|
+
curve: Curves.linear))!;
|
|
30
|
+
final interactive = widget.control.getBool("interactive", true)! &&
|
|
31
|
+
!widget.control.disabled;
|
|
32
|
+
final border = widget.control.getBorder("border", theme);
|
|
33
|
+
final titleControls = widget.control.children("titles", visibleOnly: false);
|
|
34
|
+
|
|
35
|
+
final chart = RadarChart(
|
|
36
|
+
RadarChartData(
|
|
37
|
+
dataSets: widget.control
|
|
38
|
+
.children("data_sets")
|
|
39
|
+
.map((ds) => parseRadarDataSet(ds, theme, context))
|
|
40
|
+
.toList(),
|
|
41
|
+
|
|
42
|
+
// Radar and borders
|
|
43
|
+
radarBackgroundColor: widget.control
|
|
44
|
+
.getColor("radar_bgcolor", context, Colors.transparent)!,
|
|
45
|
+
radarBorderData: widget.control.getBorderSide(
|
|
46
|
+
"radar_border_side", theme,
|
|
47
|
+
defaultValue: const BorderSide(width: 2))!,
|
|
48
|
+
radarShape: parseRadarShape(
|
|
49
|
+
widget.control.get("radar_shape"), RadarShape.polygon)!,
|
|
50
|
+
borderData: FlBorderData(show: border != null, border: border),
|
|
51
|
+
gridBorderData: widget.control.getBorderSide("grid_border_side", theme,
|
|
52
|
+
defaultValue: const BorderSide(width: 2))!,
|
|
53
|
+
|
|
54
|
+
// Titles
|
|
55
|
+
titleTextStyle: widget.control.getTextStyle("title_text_style", theme),
|
|
56
|
+
titlePositionPercentageOffset:
|
|
57
|
+
widget.control.getDouble("title_position_percentage_offset", 0.2)!,
|
|
58
|
+
getTitle: titleControls.isNotEmpty
|
|
59
|
+
? (int index, double angle) {
|
|
60
|
+
if (index >= titleControls.length) {
|
|
61
|
+
return RadarChartTitle(text: '', angle: angle);
|
|
62
|
+
}
|
|
63
|
+
final ctrl = titleControls[index];
|
|
64
|
+
return parseRadarChartTitle(ctrl, theme, angle);
|
|
65
|
+
}
|
|
66
|
+
: null,
|
|
67
|
+
|
|
68
|
+
// Ticks
|
|
69
|
+
tickCount: widget.control.getInt("tick_count", 1)!,
|
|
70
|
+
ticksTextStyle: widget.control.getTextStyle("ticks_text_style", theme),
|
|
71
|
+
tickBorderData: widget.control.getBorderSide("tick_border_side", theme,
|
|
72
|
+
defaultValue: const BorderSide(width: 2))!,
|
|
73
|
+
isMinValueAtCenter: widget.control.getBool("center_min_value", false)!,
|
|
74
|
+
|
|
75
|
+
// Interaction
|
|
76
|
+
radarTouchData: RadarTouchData(
|
|
77
|
+
enabled: interactive,
|
|
78
|
+
longPressDuration: widget.control.getDuration("long_press_duration"),
|
|
79
|
+
touchSpotThreshold: widget.control.getDouble("touch_spot_threshold"),
|
|
80
|
+
touchCallback: (event, response) {
|
|
81
|
+
final eventData = RadarChartEventData.fromDetails(event, response);
|
|
82
|
+
if (eventData != _eventData) {
|
|
83
|
+
_eventData = eventData;
|
|
84
|
+
widget.control.triggerEvent("event", eventData.toMap());
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
),
|
|
88
|
+
),
|
|
89
|
+
duration: animation.duration,
|
|
90
|
+
curve: animation.curve,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return ConstrainedControl(
|
|
94
|
+
control: widget.control,
|
|
95
|
+
child: LayoutBuilder(
|
|
96
|
+
builder: (BuildContext context, BoxConstraints constraints) {
|
|
97
|
+
return (constraints.maxHeight == double.infinity)
|
|
98
|
+
? ConstrainedBox(
|
|
99
|
+
constraints: const BoxConstraints(maxHeight: 300),
|
|
100
|
+
child: chart)
|
|
101
|
+
: chart;
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -38,11 +38,11 @@ class BarChartEventData extends Equatable {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
Map<String, dynamic> toMap() => <String, dynamic>{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
'type': eventType,
|
|
42
|
+
'group_index': groupIndex,
|
|
43
|
+
'rod_index': rodIndex,
|
|
44
|
+
'stack_item_index': stackItemIndex,
|
|
45
|
+
};
|
|
46
46
|
|
|
47
47
|
@override
|
|
48
48
|
List<Object?> get props => [eventType, groupIndex, rodIndex, stackItemIndex];
|
|
@@ -96,9 +96,8 @@ BarTouchTooltipData? parseBarTouchTooltipData(
|
|
|
96
96
|
FLHorizontalAlignment.center,
|
|
97
97
|
)!,
|
|
98
98
|
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
|
99
|
-
var rod =
|
|
100
|
-
.children("groups")[groupIndex]
|
|
101
|
-
.children("rods")[rodIndex];
|
|
99
|
+
var rod =
|
|
100
|
+
control.children("groups")[groupIndex].children("rods")[rodIndex];
|
|
102
101
|
return parseBarTooltipItem(rod, context);
|
|
103
102
|
},
|
|
104
103
|
);
|
|
@@ -118,8 +117,7 @@ BarTooltipItem? parseBarTooltipItem(Control rod, BuildContext context) {
|
|
|
118
117
|
)!;
|
|
119
118
|
if (tooltipTextStyle.color == null) {
|
|
120
119
|
tooltipTextStyle = tooltipTextStyle.copyWith(
|
|
121
|
-
color:
|
|
122
|
-
rod.getGradient("gradient", theme)?.colors.first ??
|
|
120
|
+
color: rod.getGradient("gradient", theme)?.colors.first ??
|
|
123
121
|
rod.getColor("color", context, Colors.blueGrey)!,
|
|
124
122
|
);
|
|
125
123
|
}
|
|
@@ -194,8 +192,7 @@ BarChartRodData parseBarChartRodData(
|
|
|
194
192
|
defaultValue: BorderSide.none,
|
|
195
193
|
),
|
|
196
194
|
backDrawRodData: BackgroundBarChartRodData(
|
|
197
|
-
show:
|
|
198
|
-
(bgFromY != null ||
|
|
195
|
+
show: (bgFromY != null ||
|
|
199
196
|
bgToY != null ||
|
|
200
197
|
bgcolor != null ||
|
|
201
198
|
backgroundGradient != null),
|
|
@@ -235,13 +232,10 @@ BarChartRodStackItem parseBarChartRodStackItem(
|
|
|
235
232
|
);
|
|
236
233
|
}
|
|
237
234
|
|
|
238
|
-
BarChartAlignment? parseBarChartAlignment(
|
|
239
|
-
|
|
240
|
-
BarChartAlignment? defaultValue,
|
|
241
|
-
]) {
|
|
235
|
+
BarChartAlignment? parseBarChartAlignment(String? value,
|
|
236
|
+
[BarChartAlignment? defaultValue]) {
|
|
242
237
|
if (value == null) return defaultValue;
|
|
243
238
|
return BarChartAlignment.values.firstWhereOrNull(
|
|
244
|
-
|
|
245
|
-
) ??
|
|
239
|
+
(e) => e.name.toLowerCase() == value.toLowerCase()) ??
|
|
246
240
|
defaultValue;
|
|
247
241
|
}
|
|
@@ -39,24 +39,24 @@ CandlestickTouchTooltipData parseCandlestickTouchTooltipData(
|
|
|
39
39
|
final theme = Theme.of(context);
|
|
40
40
|
|
|
41
41
|
return CandlestickTouchTooltipData(
|
|
42
|
-
tooltipBorder:
|
|
43
|
-
|
|
42
|
+
tooltipBorder: parseBorderSide(tooltip["border_side"], theme,
|
|
43
|
+
defaultValue: BorderSide.none)!,
|
|
44
44
|
rotateAngle: parseDouble(tooltip["rotation"], 0.0)!,
|
|
45
|
-
tooltipBorderRadius:
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
tooltipBorderRadius:
|
|
46
|
+
parseBorderRadius(tooltip["border_radius"], BorderRadius.circular(4))!,
|
|
47
|
+
tooltipPadding: parsePadding(tooltip["padding"],
|
|
48
|
+
const EdgeInsets.symmetric(horizontal: 16, vertical: 8))!,
|
|
48
49
|
tooltipHorizontalAlignment: parseFLHorizontalAlignment(
|
|
49
50
|
tooltip["horizontal_alignment"], FLHorizontalAlignment.center)!,
|
|
50
51
|
tooltipHorizontalOffset: parseDouble(tooltip["horizontal_offset"], 0)!,
|
|
51
52
|
maxContentWidth: parseDouble(tooltip["max_width"], 120)!,
|
|
52
53
|
fitInsideHorizontally:
|
|
53
54
|
parseBool(tooltip["fit_inside_horizontally"], false)!,
|
|
54
|
-
fitInsideVertically:
|
|
55
|
-
parseBool(tooltip["fit_inside_vertically"], false)!,
|
|
55
|
+
fitInsideVertically: parseBool(tooltip["fit_inside_vertically"], false)!,
|
|
56
56
|
showOnTopOfTheChartBoxArea:
|
|
57
57
|
parseBool(tooltip["show_on_top_of_chart_box_area"], false)!,
|
|
58
|
-
getTooltipColor: (spot) =>
|
|
59
|
-
tooltip["bgcolor"], theme, const Color
|
|
58
|
+
getTooltipColor: (spot) =>
|
|
59
|
+
parseColor(tooltip["bgcolor"], theme, const Color(0xFFFFECEF))!,
|
|
60
60
|
getTooltipItems: (painter, touchedSpot, spotIndex) {
|
|
61
61
|
if (spotIndex < 0 || spotIndex >= spotControls.length) {
|
|
62
62
|
return null;
|
|
@@ -105,8 +105,9 @@ CandlestickTooltipItem? parseCandlestickTooltipItem(
|
|
|
105
105
|
textStyle: textStyle,
|
|
106
106
|
bottomMargin: parseDouble(tooltip["bottom_margin"], 8)!,
|
|
107
107
|
textAlign: parseTextAlign(tooltip["text_align"], TextAlign.center)!,
|
|
108
|
-
textDirection:
|
|
109
|
-
|
|
108
|
+
textDirection: parseBool(tooltip["rtl"], false)!
|
|
109
|
+
? TextDirection.rtl
|
|
110
|
+
: TextDirection.ltr,
|
|
110
111
|
children: tooltip["text_spans"] != null
|
|
111
112
|
? parseTextSpans(tooltip["text_spans"], theme, (s, eventName,
|
|
112
113
|
[eventData]) {
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import 'package:collection/collection.dart';
|
|
2
|
+
import 'package:equatable/equatable.dart';
|
|
3
|
+
import 'package:fl_chart/fl_chart.dart';
|
|
4
|
+
import 'package:flet/flet.dart';
|
|
5
|
+
import 'package:flutter/material.dart';
|
|
6
|
+
|
|
7
|
+
import 'charts.dart';
|
|
8
|
+
|
|
9
|
+
RadarShape? parseRadarShape(String? value, [RadarShape? defaultValue]) {
|
|
10
|
+
if (value == null) return defaultValue;
|
|
11
|
+
return RadarShape.values.firstWhereOrNull(
|
|
12
|
+
(e) => e.name.toLowerCase() == value.toLowerCase()) ??
|
|
13
|
+
defaultValue;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class RadarChartEventData extends Equatable {
|
|
17
|
+
final String eventType;
|
|
18
|
+
final int? dataSetIndex;
|
|
19
|
+
final int? entryIndex;
|
|
20
|
+
final double? entryValue;
|
|
21
|
+
|
|
22
|
+
const RadarChartEventData({
|
|
23
|
+
required this.eventType,
|
|
24
|
+
this.dataSetIndex,
|
|
25
|
+
this.entryIndex,
|
|
26
|
+
this.entryValue,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
factory RadarChartEventData.fromDetails(
|
|
30
|
+
FlTouchEvent event, RadarTouchResponse? response) {
|
|
31
|
+
final touchedSpot = response?.touchedSpot;
|
|
32
|
+
|
|
33
|
+
return RadarChartEventData(
|
|
34
|
+
eventType: eventMap[event.runtimeType.toString()] ?? "undefined",
|
|
35
|
+
dataSetIndex: touchedSpot?.touchedDataSetIndex,
|
|
36
|
+
entryIndex: touchedSpot?.touchedRadarEntryIndex,
|
|
37
|
+
entryValue: touchedSpot?.touchedRadarEntry.value,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Map<String, dynamic> toMap() => <String, dynamic>{
|
|
42
|
+
'type': eventType,
|
|
43
|
+
'data_set_index': dataSetIndex,
|
|
44
|
+
'entry_index': entryIndex,
|
|
45
|
+
'entry_value': entryValue,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
@override
|
|
49
|
+
List<Object?> get props => [eventType, dataSetIndex, entryIndex, entryValue];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
RadarDataSet parseRadarDataSet(
|
|
53
|
+
Control dataSet, ThemeData theme, BuildContext context) {
|
|
54
|
+
final fillColor = dataSet.getColor("fill_color", context, Colors.cyan)!;
|
|
55
|
+
final fillGradient = dataSet.getGradient("fill_gradient", theme);
|
|
56
|
+
final borderColor = dataSet.getColor("border_color", context, Colors.cyan)!;
|
|
57
|
+
final borderWidth = dataSet.getDouble("border_width", 2.0)!;
|
|
58
|
+
final entryRadius = dataSet.getDouble("entry_radius", 5.0)!;
|
|
59
|
+
|
|
60
|
+
final entries = dataSet
|
|
61
|
+
.children("entries")
|
|
62
|
+
.map((entry) => RadarEntry(value: entry.getDouble("value", 0)!))
|
|
63
|
+
.toList();
|
|
64
|
+
|
|
65
|
+
return RadarDataSet(
|
|
66
|
+
dataEntries: entries,
|
|
67
|
+
fillColor: fillColor,
|
|
68
|
+
fillGradient: fillGradient,
|
|
69
|
+
borderColor: borderColor,
|
|
70
|
+
borderWidth: borderWidth,
|
|
71
|
+
entryRadius: entryRadius,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
RadarChartTitle parseRadarChartTitle(
|
|
76
|
+
Control title, ThemeData theme, double defaultAngle) {
|
|
77
|
+
final spansValue = title.get("text_spans");
|
|
78
|
+
final spans = spansValue != null
|
|
79
|
+
? parseTextSpans(spansValue, theme, (control, eventName, [eventData]) {
|
|
80
|
+
control.triggerEvent(eventName, eventData);
|
|
81
|
+
})
|
|
82
|
+
: null;
|
|
83
|
+
|
|
84
|
+
return RadarChartTitle(
|
|
85
|
+
text: title.getString("text", "")!,
|
|
86
|
+
angle: title.getDouble("angle") ?? defaultAngle,
|
|
87
|
+
positionPercentageOffset: title.getDouble("position_percentage_offset"),
|
|
88
|
+
children: spans,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
flet==0.70.0.dev6316
|
|
File without changes
|
|
File without changes
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/bar_chart_group.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/candlestick_chart_spot.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/line_chart_data.py
RENAMED
|
File without changes
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/line_chart_data_point.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts/pie_chart_section.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flet_charts.egg-info/top_level.txt
RENAMED
|
File without changes
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/CHANGELOG.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-0.70.0.dev6316 → flet_charts-0.70.0.dev6333}/src/flutter/flet_charts/pubspec.yaml
RENAMED
|
File without changes
|