Skip to content

Commit 2c4edee

Browse files
feat(flet-charts): RadarChart (#5712)
* initial commit * refactor: Update tooltip configuration and interaction settings in charts * refactor: Rename RadarEntry to RadarDataSetEntry and update related references * add media * refactor: Update reference for radar chart in mkdocs configuration * refactor: Add example images path to radar chart documentation * cleanup * Add new Matplotlib chart examples and update docs Added 3D, animated, and event-handling chart examples to the Matplotlib chart examples directory. Renamed example files for clarity, updated associated media images, and removed unused images. Enhanced MatplotlibChart class with docstrings and refactored resize handler. Updated documentation to include new examples and images, and adjusted mkdocs.yml to improve API documentation filtering. * Improve optional dependency handling for Matplotlib and Plotly controls Refactored MatplotlibChart, MatplotlibChartWithToolbar, and PlotlyChart to gracefully handle missing optional dependencies by deferring import errors and providing clearer error messages. Added runtime checks to ensure required packages are installed before usage, improving robustness and user experience. * Move plotly requirement check to init method The _require_plotly() call was moved from before_update() to the init() method to ensure plotly is available during initialization rather than before updates. * Refactor MatplotlibChart initialization logic Moved the call to _require_matplotlib() from build() to a new init() method in MatplotlibChart. This separates initialization from build logic for better code organization. * refactor: Call super init method in MatplotlibChart initialization --------- Co-authored-by: Feodor Fitsner <[email protected]>
1 parent 15ac9b9 commit 2c4edee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+993
-135
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,7 @@ jobs:
619619
patch_toml_versions "$PYPROJECT" "$PYPI_VER"
620620
621621
rm -rf dist
622-
uv build --package "$PACKAGE" --wheel
623-
uv build --package "$PACKAGE" --sdist
622+
uv build --package "$PACKAGE"
624623
625624
- name: Upload artifacts
626625
uses: actions/upload-artifact@v4

sdk/python/Taskfile.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ tasks:
106106
- kill -9 $(lsof -ti :8550)
107107

108108
extensions-pre-commit-install:
109-
desc: "Installs pre-commit hooks of all extensions, assuming they are present in the currently active uv-workspace."
109+
desc: "Installs pre-commit hooks of all extensions."
110110
aliases:
111111
- pc-extensions
112112
- extensions-pre-commit
@@ -125,8 +125,3 @@ tasks:
125125
- uv run --package flet-rive pre-commit install
126126
- uv run --package flet-video pre-commit install
127127
- uv run --package flet-webview pre-commit install
128-
129-
# serve-extensions:
130-
# desc: "Serves all extensions, assuming they are present in the currently active uv-workspace."
131-
# cmds:
132-
# - uv run --active --package flet-audio --directory path/to/flet-audio mkdocs serve

sdk/python/examples/controls/charts/bar_chart/example_1.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import flet_charts as fch
2-
31
import flet as ft
2+
import flet_charts as fch
43

54

65
def main(page: ft.Page):

sdk/python/examples/controls/charts/candlestick_chart/example_1.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import flet_charts as ftc
2-
31
import flet as ft
2+
import flet_charts as ftc
43

54
CANDLE_DATA = [
65
("Mon", 24.8, 28.6, 23.9, 27.2),
@@ -100,7 +99,6 @@ def handle_event(e: ftc.CandlestickChartEvent):
10099
horizontal_alignment=ftc.HorizontalAlignment.CENTER,
101100
fit_inside_horizontally=True,
102101
),
103-
handle_built_in_touches=True,
104102
on_event=handle_event,
105103
)
106104

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import logging
2+
3+
import flet_charts
4+
import matplotlib.pyplot as plt
5+
import numpy as np
6+
7+
import flet as ft
8+
9+
logging.basicConfig(level=logging.INFO)
10+
11+
12+
def main(page: ft.Page):
13+
plt.style.use("_mpl-gallery")
14+
15+
# Make data for a double helix
16+
n = 50
17+
theta = np.linspace(0, 2 * np.pi, n)
18+
x1 = np.cos(theta)
19+
y1 = np.sin(theta)
20+
z1 = np.linspace(0, 1, n)
21+
x2 = np.cos(theta + np.pi)
22+
y2 = np.sin(theta + np.pi)
23+
z2 = z1
24+
25+
# Plot with defined figure size
26+
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(8, 6))
27+
ax.fill_between(x1, y1, z1, x2, y2, z2, alpha=0.5)
28+
ax.plot(x1, y1, z1, linewidth=2, color="C0")
29+
ax.plot(x2, y2, z2, linewidth=2, color="C0")
30+
31+
ax.set(xticklabels=[], yticklabels=[], zticklabels=[])
32+
33+
page.add(flet_charts.MatplotlibChartWithToolbar(figure=fig))
34+
35+
36+
ft.run(main)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import logging
2+
3+
import flet_charts
4+
import matplotlib.pyplot as plt
5+
import numpy as np
6+
7+
import flet as ft
8+
9+
logging.basicConfig(level=logging.INFO)
10+
11+
state = {}
12+
13+
14+
def main(page: ft.Page):
15+
import matplotlib.animation as animation
16+
17+
# Fixing random state for reproducibility
18+
np.random.seed(19680801)
19+
20+
def random_walk(num_steps, max_step=0.05):
21+
"""Return a 3D random walk as (num_steps, 3) array."""
22+
start_pos = np.random.random(3)
23+
steps = np.random.uniform(-max_step, max_step, size=(num_steps, 3))
24+
walk = start_pos + np.cumsum(steps, axis=0)
25+
return walk
26+
27+
def update_lines(num, walks, lines):
28+
for line, walk in zip(lines, walks):
29+
line.set_data_3d(walk[:num, :].T)
30+
return lines
31+
32+
# Data: 40 random walks as (num_steps, 3) arrays
33+
num_steps = 30
34+
walks = [random_walk(num_steps) for index in range(40)]
35+
36+
# Attaching 3D axis to the figure
37+
fig = plt.figure()
38+
ax = fig.add_subplot(projection="3d")
39+
40+
# Create lines initially without data
41+
lines = [ax.plot([], [], [])[0] for _ in walks]
42+
43+
# Setting the Axes properties
44+
ax.set(xlim3d=(0, 1), xlabel="X")
45+
ax.set(ylim3d=(0, 1), ylabel="Y")
46+
ax.set(zlim3d=(0, 1), zlabel="Z")
47+
48+
# Creating the Animation object
49+
state["anim"] = animation.FuncAnimation(
50+
fig, update_lines, num_steps, fargs=(walks, lines), interval=100
51+
)
52+
53+
page.add(flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True))
54+
55+
56+
ft.run(main)

sdk/python/examples/controls/charts/matplotlib_chart/example_1.py renamed to sdk/python/examples/controls/charts/matplotlib_chart/bar_chart.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
import flet as ft
66

7-
matplotlib.use("svg")
8-
97

108
def main(page: ft.Page):
119
fig, ax = plt.subplots()
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import flet_charts
2+
import matplotlib.pyplot as plt
3+
import numpy as np
4+
5+
import flet as ft
6+
7+
state = {}
8+
9+
10+
def main(page: ft.Page):
11+
# Fixing random state for reproducibility
12+
np.random.seed(19680801)
13+
14+
X = np.random.rand(100, 200)
15+
xs = np.mean(X, axis=1)
16+
ys = np.std(X, axis=1)
17+
18+
fig, (ax, ax2) = plt.subplots(2, 1)
19+
ax.set_title("click on point to plot time series")
20+
(line,) = ax.plot(xs, ys, "o", picker=True, pickradius=5)
21+
22+
class PointBrowser:
23+
"""
24+
Click on a point to select and highlight it -- the data that
25+
generated the point will be shown in the lower Axes. Use the 'n'
26+
and 'p' keys to browse through the next and previous points
27+
"""
28+
29+
def __init__(self):
30+
self.lastind = 0
31+
32+
self.text = ax.text(
33+
0.05, 0.95, "selected: none", transform=ax.transAxes, va="top"
34+
)
35+
(self.selected,) = ax.plot(
36+
[xs[0]], [ys[0]], "o", ms=12, alpha=0.4, color="yellow", visible=False
37+
)
38+
39+
def on_press(self, event):
40+
if self.lastind is None:
41+
return
42+
if event.key not in ("n", "p"):
43+
return
44+
inc = 1 if event.key == "n" else -1
45+
46+
self.lastind += inc
47+
self.lastind = np.clip(self.lastind, 0, len(xs) - 1)
48+
self.update()
49+
50+
def on_pick(self, event):
51+
if event.artist != line:
52+
return True
53+
54+
N = len(event.ind)
55+
if not N:
56+
return True
57+
58+
# the click locations
59+
x = event.mouseevent.xdata
60+
y = event.mouseevent.ydata
61+
62+
distances = np.hypot(x - xs[event.ind], y - ys[event.ind])
63+
indmin = distances.argmin()
64+
dataind = event.ind[indmin]
65+
66+
self.lastind = dataind
67+
self.update()
68+
69+
def update(self):
70+
if self.lastind is None:
71+
return
72+
73+
dataind = self.lastind
74+
75+
ax2.clear()
76+
ax2.plot(X[dataind])
77+
78+
ax2.text(
79+
0.05,
80+
0.9,
81+
f"mu={xs[dataind]:1.3f}\nsigma={ys[dataind]:1.3f}",
82+
transform=ax2.transAxes,
83+
va="top",
84+
)
85+
ax2.set_ylim(-0.5, 1.5)
86+
self.selected.set_visible(True)
87+
self.selected.set_data([xs[dataind]], [ys[dataind]])
88+
89+
self.text.set_text("selected: %d" % dataind)
90+
fig.canvas.draw()
91+
92+
browser = PointBrowser()
93+
state["browser"] = browser
94+
95+
fig.canvas.mpl_connect("pick_event", browser.on_pick)
96+
fig.canvas.mpl_connect("key_press_event", browser.on_press)
97+
98+
# plt.show()
99+
100+
page.add(flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True))
101+
102+
103+
ft.run(main)
329 KB
Loading
258 KB
Loading

0 commit comments

Comments
 (0)