IBB-Helper 0.4.8.dev24__tar.gz → 0.4.8.dev25__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.
- {ibb_helper-0.4.8.dev24/src/IBB_Helper.egg-info → ibb_helper-0.4.8.dev25}/PKG-INFO +1 -1
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/pyproject.toml +1 -1
- ibb_helper-0.4.8.dev25/src/IBB_Helper/animate.py +214 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25/src/IBB_Helper.egg-info}/PKG-INFO +1 -1
- ibb_helper-0.4.8.dev24/src/IBB_Helper/animate.py +0 -176
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/LICENSE +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/README.md +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/setup.cfg +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/setup.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/__init__.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/combine_plots.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/display.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/display_eigen.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/display_matrix.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/extend_plot.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/minimize.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/num_int.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/plot_2d.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/plot_3d.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/plot_param_grid.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper/symbolic_BSpline.py +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper.egg-info/SOURCES.txt +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper.egg-info/dependency_links.txt +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper.egg-info/requires.txt +0 -0
- {ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: IBB_Helper
|
|
3
|
-
Version: 0.4.8.
|
|
3
|
+
Version: 0.4.8.dev25
|
|
4
4
|
Summary: Helper functions for symbolic math, matrix visualization, and plotting
|
|
5
5
|
Author-email: "University of Stuttgart, Institute for Structural Mechanics (IBB)" <mvs@ibb.uni-stuttgart.de>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "IBB_Helper"
|
|
7
|
-
version = "0.4.8.
|
|
7
|
+
version = "0.4.8.dev25"
|
|
8
8
|
description = "Helper functions for symbolic math, matrix visualization, and plotting"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "BSD-3-Clause"
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import sympy as sp
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
import matplotlib.animation
|
|
5
|
+
from sympy import latex, Matrix
|
|
6
|
+
from IPython.display import display
|
|
7
|
+
|
|
8
|
+
def animate(exprs, var=None, **kwargs):
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Animates 2D curves from symbolic expressions or numeric datasets using Matplotlib.
|
|
12
|
+
|
|
13
|
+
Parameters:
|
|
14
|
+
exprs : Expression, tuple, or list of expressions to animate (symbolic, parametric, or numeric data)
|
|
15
|
+
var : Symbol or tuple defining the variable and range, or array mode ('array', x_values)
|
|
16
|
+
labels : Curve labels (strings or SymPy expressions, LaTeX supported) (default=None)
|
|
17
|
+
line_styles : Line styles for each curve (default=None → solid)
|
|
18
|
+
colors : Colors for each curve (default=None → Matplotlib cycle)
|
|
19
|
+
title : Plot title (string or SymPy expression, LaTeX supported) (default="Animation")
|
|
20
|
+
xlabel : X-axis label (string or SymPy expression, LaTeX supported) (default="x")
|
|
21
|
+
ylabel : Y-axis label (string or SymPy expression, LaTeX supported) (default="y")
|
|
22
|
+
xlim : X-axis limits as (min, max) (default=None → auto)
|
|
23
|
+
ylim : Y-axis limits as (min, max) (default=None → auto)
|
|
24
|
+
linewidth : Line width(s) as int or list (default=2)
|
|
25
|
+
animation_time : Total animation duration in milliseconds (default=5000)
|
|
26
|
+
frames : Number of animation frames (default=100)
|
|
27
|
+
resolution : Number of evaluation points for symbolic expressions (default=400)
|
|
28
|
+
show : Whether to display the animation (default=True)
|
|
29
|
+
width : Plot width in pixels (default=800)
|
|
30
|
+
height : Plot height in pixels (default=600)
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
matplotlib.animation.FuncAnimation
|
|
34
|
+
The animation object
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
# Unpack Options (The "Unfolding")
|
|
38
|
+
labels = kwargs.get('labels', None)
|
|
39
|
+
line_styles = kwargs.get('line_styles', None)
|
|
40
|
+
colors = kwargs.get('colors', None)
|
|
41
|
+
|
|
42
|
+
title = kwargs.get('title', "Animation")
|
|
43
|
+
xlabel = kwargs.get('xlabel', "x")
|
|
44
|
+
ylabel = kwargs.get('ylabel', "y")
|
|
45
|
+
|
|
46
|
+
xlim = kwargs.get('xlim', None)
|
|
47
|
+
ylim = kwargs.get('ylim', None)
|
|
48
|
+
|
|
49
|
+
thickness = kwargs.get('thickness', 2)
|
|
50
|
+
scaling = kwargs.get('scaling', None)
|
|
51
|
+
|
|
52
|
+
animation_time = kwargs.get('animation_time', 5000)
|
|
53
|
+
frames = kwargs.get('frames', 100)
|
|
54
|
+
resolution = kwargs.get('resolution', 400)
|
|
55
|
+
show = kwargs.get('show', True)
|
|
56
|
+
|
|
57
|
+
width = kwargs.get('width', 800)
|
|
58
|
+
height = kwargs.get('height', 600)
|
|
59
|
+
|
|
60
|
+
# Smart Labels
|
|
61
|
+
def _smart_label(lbl):
|
|
62
|
+
if isinstance(lbl, str):
|
|
63
|
+
if any(c in lbl for c in ['_', '^', '\\']): return f"${lbl}$"
|
|
64
|
+
return lbl
|
|
65
|
+
elif lbl is None: return None
|
|
66
|
+
return f"${latex(lbl)}$"
|
|
67
|
+
|
|
68
|
+
# Extract Data from Existing Plot
|
|
69
|
+
def _extract_from_axes(ax_input):
|
|
70
|
+
extracted_data, extracted_styles, extracted_colors = [], [], []
|
|
71
|
+
extracted_labels, extracted_widths = [], []
|
|
72
|
+
for line in ax_input.lines:
|
|
73
|
+
extracted_data.append((line.get_xdata(), line.get_ydata()))
|
|
74
|
+
extracted_colors.append(line.get_color())
|
|
75
|
+
extracted_styles.append(line.get_linestyle())
|
|
76
|
+
extracted_labels.append(line.get_label())
|
|
77
|
+
extracted_widths.append(line.get_linewidth())
|
|
78
|
+
return extracted_data, extracted_styles, extracted_colors, extracted_labels, extracted_widths
|
|
79
|
+
|
|
80
|
+
# Handle Parametric Logic
|
|
81
|
+
def _get_parametric_data(expr, x_sym, frames_count):
|
|
82
|
+
if len(expr) == 3: # Custom Range
|
|
83
|
+
x_e, y_e, range_info = expr
|
|
84
|
+
t_sym, t_min, t_max = range_info
|
|
85
|
+
t_vals = np.linspace(float(t_min), float(t_max), frames_count)
|
|
86
|
+
f_x = sp.lambdify(t_sym, x_e, modules='numpy')
|
|
87
|
+
f_y = sp.lambdify(t_sym, y_e, modules='numpy')
|
|
88
|
+
x_res, y_res = f_x(t_vals), f_y(t_vals)
|
|
89
|
+
if not hasattr(x_res, '__len__'): x_res = np.full_like(t_vals, x_res)
|
|
90
|
+
if not hasattr(y_res, '__len__'): y_res = np.full_like(t_vals, y_res)
|
|
91
|
+
return np.array(x_res).flatten(), np.array(y_res).flatten()
|
|
92
|
+
elif len(expr) == 2: # Global Range
|
|
93
|
+
x_data, y_data = expr
|
|
94
|
+
if isinstance(x_data, sp.Basic) or isinstance(y_data, sp.Basic):
|
|
95
|
+
f_x = sp.lambdify(x_sym, x_data, modules='numpy')
|
|
96
|
+
f_y = sp.lambdify(x_sym, y_data, modules='numpy')
|
|
97
|
+
x_data, y_data = f_x(x_vals_sample), f_y(x_vals_sample)
|
|
98
|
+
if hasattr(x_data, '__len__') and not hasattr(y_data, '__len__'):
|
|
99
|
+
y_data = np.full_like(x_data, y_data)
|
|
100
|
+
elif not hasattr(x_data, '__len__') and hasattr(y_data, '__len__'):
|
|
101
|
+
x_data = np.full_like(y_data, x_data)
|
|
102
|
+
return x_data, y_data
|
|
103
|
+
return None, None
|
|
104
|
+
|
|
105
|
+
# Handle Standard y=f(x) Logic
|
|
106
|
+
def _get_standard_data(expr, x_sym, x_vals_sample):
|
|
107
|
+
expr = sp.sympify(expr)
|
|
108
|
+
if not expr.has(x_sym):
|
|
109
|
+
y_vals = np.full_like(x_vals_sample, float(expr))
|
|
110
|
+
else:
|
|
111
|
+
f = sp.lambdify(x_sym, expr, modules='numpy')
|
|
112
|
+
y_vals = np.array(f(x_vals_sample)).flatten()
|
|
113
|
+
return x_vals_sample, y_vals
|
|
114
|
+
|
|
115
|
+
# Main Execution
|
|
116
|
+
dpi = 100
|
|
117
|
+
plt.rcParams["animation.html"] = "jshtml"
|
|
118
|
+
plt.rcParams['figure.dpi'] = dpi
|
|
119
|
+
plt.ioff()
|
|
120
|
+
|
|
121
|
+
plot_data = []
|
|
122
|
+
final_colors, final_styles, final_labels, final_widths = [], [], [], []
|
|
123
|
+
|
|
124
|
+
# Existing Plot
|
|
125
|
+
if isinstance(exprs, plt.Axes):
|
|
126
|
+
plot_data, final_styles, final_colors, final_labels, final_widths = _extract_from_axes(exprs)
|
|
127
|
+
if plot_data: frames = max(len(d[0]) for d in plot_data)
|
|
128
|
+
if title == "Animation": title = exprs.get_title()
|
|
129
|
+
if xlabel == "x": xlabel = exprs.get_xlabel()
|
|
130
|
+
if ylabel == "y": ylabel = exprs.get_ylabel()
|
|
131
|
+
|
|
132
|
+
# List of Expressions
|
|
133
|
+
else:
|
|
134
|
+
if not isinstance(exprs, list): exprs = [exprs]
|
|
135
|
+
|
|
136
|
+
# Parse Variable/Range
|
|
137
|
+
if isinstance(var, tuple):
|
|
138
|
+
if var[0] == 'array':
|
|
139
|
+
x_sym, x_vals_sample = None, var[1]
|
|
140
|
+
frames = len(x_vals_sample)
|
|
141
|
+
else:
|
|
142
|
+
x_sym, x_range = var[0], var[1]
|
|
143
|
+
x_vals_sample = np.linspace(float(x_range[0]), float(x_range[1]), frames)
|
|
144
|
+
else:
|
|
145
|
+
x_sym = var
|
|
146
|
+
x_range = (-1, 1)
|
|
147
|
+
x_vals_sample = np.linspace(float(x_range[0]), float(x_range[1]), frames)
|
|
148
|
+
|
|
149
|
+
# Process Expressions
|
|
150
|
+
for i, expr in enumerate(exprs):
|
|
151
|
+
if isinstance(expr, Matrix): expr = np.array(expr).astype(np.float64).flatten()
|
|
152
|
+
|
|
153
|
+
# Style defaults
|
|
154
|
+
usr_style = line_styles[i] if line_styles and i < len(line_styles) else None
|
|
155
|
+
usr_color = colors[i] if colors and i < len(colors) else None
|
|
156
|
+
usr_label = labels[i] if labels and i < len(labels) else None
|
|
157
|
+
usr_width = thickness[i] if isinstance(thickness, list) and i < len(thickness) else (thickness if isinstance(thickness, (int, float)) else 2)
|
|
158
|
+
|
|
159
|
+
final_styles.append(usr_style)
|
|
160
|
+
final_colors.append(usr_color)
|
|
161
|
+
final_labels.append(usr_label)
|
|
162
|
+
final_widths.append(usr_width)
|
|
163
|
+
|
|
164
|
+
if isinstance(expr, (tuple, list)):
|
|
165
|
+
px, py = _get_parametric_data(expr, x_sym, frames)
|
|
166
|
+
plot_data.append((px, py))
|
|
167
|
+
else:
|
|
168
|
+
sx, sy = _get_standard_data(expr, x_sym, x_vals_sample)
|
|
169
|
+
plot_data.append((sx, sy))
|
|
170
|
+
|
|
171
|
+
# Limits & Figure Setup
|
|
172
|
+
if xlim is None and plot_data:
|
|
173
|
+
all_x = np.concatenate([d[0] for d in plot_data])
|
|
174
|
+
min_x, max_x = np.min(all_x), np.max(all_x)
|
|
175
|
+
pad_x = (max_x - min_x) * 0.1 if max_x != min_x else 0.5
|
|
176
|
+
xlim = (min_x - pad_x, max_x + pad_x)
|
|
177
|
+
|
|
178
|
+
if ylim is None and plot_data:
|
|
179
|
+
all_y = np.concatenate([d[1] for d in plot_data])
|
|
180
|
+
min_y, max_y = np.min(all_y), np.max(all_y)
|
|
181
|
+
pad_y = (max_y - min_y) * 0.1 if max_y != min_y else 0.5
|
|
182
|
+
ylim = (min_y - pad_y, max_y + pad_y)
|
|
183
|
+
|
|
184
|
+
fig, ax = plt.subplots(figsize=(width / dpi, height / dpi))
|
|
185
|
+
if scaling == 'constrained': ax.set_aspect('equal', adjustable='box')
|
|
186
|
+
|
|
187
|
+
def animate_frame(frame):
|
|
188
|
+
ax.clear()
|
|
189
|
+
for i, (x_d, y_d) in enumerate(plot_data):
|
|
190
|
+
total_points = len(x_d)
|
|
191
|
+
idx = int((frame + 1) / frames * total_points)
|
|
192
|
+
lbl = _smart_label(final_labels[i])
|
|
193
|
+
stl = final_styles[i] if final_styles[i] else 'solid'
|
|
194
|
+
clr = final_colors[i]
|
|
195
|
+
wdth = final_widths[i]
|
|
196
|
+
ax.plot(x_d[:idx], y_d[:idx], label=lbl, linestyle=stl, color=clr, linewidth=wdth)
|
|
197
|
+
|
|
198
|
+
ax.set_xlim(xlim)
|
|
199
|
+
ax.set_ylim(ylim)
|
|
200
|
+
ax.set_title(_smart_label(title))
|
|
201
|
+
ax.set_xlabel(_smart_label(xlabel))
|
|
202
|
+
ax.set_ylabel(_smart_label(ylabel))
|
|
203
|
+
if any(final_labels): ax.legend(loc='upper right')
|
|
204
|
+
ax.grid(True, alpha=0.3)
|
|
205
|
+
|
|
206
|
+
anim = matplotlib.animation.FuncAnimation(
|
|
207
|
+
fig, animate_frame, frames=frames, interval=animation_time / frames, repeat=True
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
if show:
|
|
211
|
+
display(anim)
|
|
212
|
+
plt.close()
|
|
213
|
+
|
|
214
|
+
return anim
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: IBB_Helper
|
|
3
|
-
Version: 0.4.8.
|
|
3
|
+
Version: 0.4.8.dev25
|
|
4
4
|
Summary: Helper functions for symbolic math, matrix visualization, and plotting
|
|
5
5
|
Author-email: "University of Stuttgart, Institute for Structural Mechanics (IBB)" <mvs@ibb.uni-stuttgart.de>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import sympy as sp
|
|
3
|
-
import matplotlib.pyplot as plt
|
|
4
|
-
import matplotlib.animation
|
|
5
|
-
from sympy import latex, Matrix
|
|
6
|
-
|
|
7
|
-
def animate(exprs, var, labels=None, line_styles=None, colors=None,
|
|
8
|
-
title="Animation", xlabel="x", ylabel="y",
|
|
9
|
-
xlim=None, ylim=None, thickness=2,
|
|
10
|
-
animation_time=5000, frames=100, resolution=400, show=True):
|
|
11
|
-
"""
|
|
12
|
-
Animates 2D curves from symbolic expressions or numeric datasets using Matplotlib.
|
|
13
|
-
|
|
14
|
-
Parameters:
|
|
15
|
-
exprs : Expression, tuple, or list of expressions to animate (symbolic, parametric, or numeric data)
|
|
16
|
-
var : Symbol or tuple defining the variable and range, or array mode ('array', x_values)
|
|
17
|
-
labels : Curve labels (strings or SymPy expressions, LaTeX supported) (default=None)
|
|
18
|
-
line_styles : Line styles for each curve (default=None → solid)
|
|
19
|
-
colors : Colors for each curve (default=None → Matplotlib cycle)
|
|
20
|
-
title : Plot title (string or SymPy expression, LaTeX supported) (default="Animation")
|
|
21
|
-
xlabel : X-axis label (string or SymPy expression, LaTeX supported) (default="x")
|
|
22
|
-
ylabel : Y-axis label (string or SymPy expression, LaTeX supported) (default="y")
|
|
23
|
-
xlim : X-axis limits as (min, max) (default=None → auto)
|
|
24
|
-
ylim : Y-axis limits as (min, max) (default=None → auto)
|
|
25
|
-
thickness : Line width(s) as int or list (default=2)
|
|
26
|
-
animation_time : Total animation duration in milliseconds (default=5000)
|
|
27
|
-
frames : Number of animation frames (default=100)
|
|
28
|
-
resolution : Number of evaluation points for symbolic expressions (default=400)
|
|
29
|
-
show : Whether to display the animation (default=True)
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
matplotlib.animation.FuncAnimation
|
|
33
|
-
The animation object
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# Configure matplotlib for Jupyter notebook compatibility
|
|
38
|
-
plt.rcParams["animation.html"] = "jshtml"
|
|
39
|
-
plt.rcParams['figure.dpi'] = 150
|
|
40
|
-
plt.ioff()
|
|
41
|
-
|
|
42
|
-
# Helper function to convert labels to LaTeX
|
|
43
|
-
def smart_label(lbl):
|
|
44
|
-
if isinstance(lbl, str):
|
|
45
|
-
# Check for LaTeX characters
|
|
46
|
-
if any(c in lbl for c in ['_', '^', '\\']):
|
|
47
|
-
return f"${lbl}$"
|
|
48
|
-
else:
|
|
49
|
-
return lbl
|
|
50
|
-
else:
|
|
51
|
-
# Convert SymPy expression to LaTeX
|
|
52
|
-
return f"${latex(lbl)}$"
|
|
53
|
-
|
|
54
|
-
# Normalize inputs to lists
|
|
55
|
-
if not isinstance(exprs, list):
|
|
56
|
-
exprs = [exprs]
|
|
57
|
-
|
|
58
|
-
# Determine symbol and range
|
|
59
|
-
is_sympy = True
|
|
60
|
-
if isinstance(var, tuple):
|
|
61
|
-
if var[0] == 'array':
|
|
62
|
-
is_sympy = False
|
|
63
|
-
x_vals_sample = var[1]
|
|
64
|
-
frames = len(x_vals_sample)
|
|
65
|
-
else:
|
|
66
|
-
x_sym = var[0]
|
|
67
|
-
x_range = var[1]
|
|
68
|
-
x_vals_sample = np.linspace(float(x_range[0]), float(x_range[1]), frames)
|
|
69
|
-
else:
|
|
70
|
-
x_sym = var
|
|
71
|
-
x_range = (-1, 1)
|
|
72
|
-
x_vals_sample = np.linspace(float(x_range[0]), float(x_range[1]), frames)
|
|
73
|
-
|
|
74
|
-
# Setup thickness
|
|
75
|
-
if isinstance(thickness, (int, float)):
|
|
76
|
-
thickness = [thickness] * len(exprs)
|
|
77
|
-
|
|
78
|
-
# Prepare data for all expressions
|
|
79
|
-
plot_data = []
|
|
80
|
-
for i, expr in enumerate(exprs):
|
|
81
|
-
# Convert SymPy Matrix to NumPy array
|
|
82
|
-
if isinstance(expr, Matrix):
|
|
83
|
-
expr = np.array(expr).astype(np.float64).flatten()
|
|
84
|
-
|
|
85
|
-
# Tuple/list of two items (x, y) - parametric or data
|
|
86
|
-
if isinstance(expr, (tuple, list)) and len(expr) == 2:
|
|
87
|
-
x_data, y_data = expr
|
|
88
|
-
|
|
89
|
-
# If symbolic expressions, lambdify automatically
|
|
90
|
-
if isinstance(x_data, sp.Basic) or isinstance(y_data, sp.Basic):
|
|
91
|
-
if is_sympy:
|
|
92
|
-
f_x = sp.lambdify(x_sym, x_data, modules='numpy')
|
|
93
|
-
f_y = sp.lambdify(x_sym, y_data, modules='numpy')
|
|
94
|
-
x_data = f_x(x_vals_sample)
|
|
95
|
-
y_data = f_y(x_vals_sample)
|
|
96
|
-
|
|
97
|
-
# Handle constant parametric plots
|
|
98
|
-
is_x_array = hasattr(x_data, '__len__')
|
|
99
|
-
is_y_array = hasattr(y_data, '__len__')
|
|
100
|
-
|
|
101
|
-
if is_x_array and not is_y_array:
|
|
102
|
-
y_data = np.full_like(x_data, y_data)
|
|
103
|
-
elif not is_x_array and is_y_array:
|
|
104
|
-
x_data = np.full_like(y_data, x_data)
|
|
105
|
-
|
|
106
|
-
plot_data.append((np.array(x_data), np.array(y_data)))
|
|
107
|
-
|
|
108
|
-
else:
|
|
109
|
-
# Single symbolic or numeric expression
|
|
110
|
-
expr = sp.sympify(expr)
|
|
111
|
-
if not expr.has(x_sym) if is_sympy else False:
|
|
112
|
-
y_vals = np.full_like(x_vals_sample, float(expr))
|
|
113
|
-
else:
|
|
114
|
-
if is_sympy:
|
|
115
|
-
f = sp.lambdify(x_sym, expr, modules='numpy')
|
|
116
|
-
y_vals = np.array(f(x_vals_sample)).flatten()
|
|
117
|
-
else:
|
|
118
|
-
y_vals = np.array(expr).flatten()
|
|
119
|
-
|
|
120
|
-
plot_data.append((x_vals_sample, y_vals))
|
|
121
|
-
|
|
122
|
-
# Auto-calculate axis limits if not provided
|
|
123
|
-
if xlim is None:
|
|
124
|
-
all_x = np.concatenate([data[0] for data in plot_data])
|
|
125
|
-
x_min, x_max = np.min(all_x), np.max(all_x)
|
|
126
|
-
x_range = x_max - x_min
|
|
127
|
-
xlim = (x_min - 0.05 * x_range, x_max + 0.05 * x_range)
|
|
128
|
-
|
|
129
|
-
if ylim is None:
|
|
130
|
-
all_y = np.concatenate([data[1] for data in plot_data])
|
|
131
|
-
y_min, y_max = np.min(all_y), np.max(all_y)
|
|
132
|
-
y_range = y_max - y_min
|
|
133
|
-
ylim = (y_min - 0.1 * y_range, y_max + 0.1 * y_range)
|
|
134
|
-
|
|
135
|
-
# Create figure
|
|
136
|
-
fig, ax = plt.subplots(figsize=(10, 6))
|
|
137
|
-
|
|
138
|
-
def animate_frame(frame):
|
|
139
|
-
ax.clear()
|
|
140
|
-
|
|
141
|
-
# Show data up to current frame
|
|
142
|
-
idx = frame + 1
|
|
143
|
-
|
|
144
|
-
for i, (x_data, y_data) in enumerate(plot_data):
|
|
145
|
-
style = line_styles[i] if line_styles and i < len(line_styles) else 'solid'
|
|
146
|
-
color = colors[i] if colors and i < len(colors) else None
|
|
147
|
-
raw_label = labels[i] if labels and i < len(labels) else None
|
|
148
|
-
label = smart_label(raw_label) if raw_label is not None else None
|
|
149
|
-
|
|
150
|
-
ax.plot(x_data[:idx], y_data[:idx],
|
|
151
|
-
label=label,
|
|
152
|
-
linestyle=style,
|
|
153
|
-
color=color,
|
|
154
|
-
linewidth=thickness[i])
|
|
155
|
-
|
|
156
|
-
ax.set_xlim(xlim)
|
|
157
|
-
ax.set_ylim(ylim)
|
|
158
|
-
ax.set_title(smart_label(title))
|
|
159
|
-
ax.set_xlabel(smart_label(xlabel))
|
|
160
|
-
ax.set_ylabel(smart_label(ylabel))
|
|
161
|
-
|
|
162
|
-
if labels:
|
|
163
|
-
ax.legend()
|
|
164
|
-
ax.grid(True, alpha=0.3)
|
|
165
|
-
|
|
166
|
-
# Calculate interval from animation_time and frames
|
|
167
|
-
interval = animation_time / frames
|
|
168
|
-
|
|
169
|
-
anim = matplotlib.animation.FuncAnimation(
|
|
170
|
-
fig, animate_frame, frames=frames, interval=interval, repeat=True
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
if not show:
|
|
174
|
-
plt.close()
|
|
175
|
-
|
|
176
|
-
return anim
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ibb_helper-0.4.8.dev24 → ibb_helper-0.4.8.dev25}/src/IBB_Helper.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|