IBB-Helper 0.4.8.dev29__tar.gz → 0.4.8.dev30__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.dev29/src/IBB_Helper.egg-info → ibb_helper-0.4.8.dev30}/PKG-INFO +1 -1
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/pyproject.toml +1 -1
- ibb_helper-0.4.8.dev30/src/IBB_Helper/animate.py +249 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30/src/IBB_Helper.egg-info}/PKG-INFO +1 -1
- ibb_helper-0.4.8.dev29/src/IBB_Helper/animate.py +0 -206
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/LICENSE +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/README.md +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/setup.cfg +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/setup.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/__init__.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/combine_plots.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/display.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/display_eigen.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/display_matrix.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/extend_plot.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/minimize.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/num_int.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/plot_2d.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/plot_3d.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/plot_param_grid.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper/symbolic_BSpline.py +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper.egg-info/SOURCES.txt +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper.egg-info/dependency_links.txt +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper.egg-info/requires.txt +0 -0
- {ibb_helper-0.4.8.dev29 → ibb_helper-0.4.8.dev30}/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.dev30
|
|
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.dev30"
|
|
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,249 @@
|
|
|
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,
|
|
8
|
+
# --- Labels & Text ---
|
|
9
|
+
labels=None, title="Animation", xlabel="x", ylabel="y",
|
|
10
|
+
# --- Styling ---
|
|
11
|
+
line_styles=None, colors=None, linewidth=2,
|
|
12
|
+
# --- Limits ---
|
|
13
|
+
xlim=None, ylim=None,
|
|
14
|
+
# --- Animation Config ---
|
|
15
|
+
animation_time=5000, frames=100, resolution=400, show=True):
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
Animates 2D curves from symbolic expressions or numeric datasets using Matplotlib.
|
|
19
|
+
|
|
20
|
+
Parameters:
|
|
21
|
+
exprs : Expression, tuple, or list of expressions (symbolic, parametric, or numeric data)
|
|
22
|
+
var : Symbol or tuple defining variable/range, or array mode ('array', x_values)
|
|
23
|
+
|
|
24
|
+
# --- Labels ---
|
|
25
|
+
labels : Curve labels (strings or SymPy expressions, LaTeX supported) (default=None)
|
|
26
|
+
title : Plot title (default="Animation")
|
|
27
|
+
xlabel : X-axis label (default="x")
|
|
28
|
+
ylabel : Y-axis label (default="y")
|
|
29
|
+
|
|
30
|
+
# --- Styling ---
|
|
31
|
+
line_styles : Line styles for each curve (default=None -> solid)
|
|
32
|
+
colors : Colors for each curve (default=None -> Matplotlib cycle)
|
|
33
|
+
linewidth : Line width(s) as int or list (default=2)
|
|
34
|
+
|
|
35
|
+
# --- Limits ---
|
|
36
|
+
xlim : X-axis limits as (min, max) (default=None -> auto)
|
|
37
|
+
ylim : Y-axis limits as (min, max) (default=None -> auto)
|
|
38
|
+
|
|
39
|
+
# --- Animation Config ---
|
|
40
|
+
animation_time : Total animation duration in milliseconds (default=5000)
|
|
41
|
+
frames : Number of animation frames (default=100)
|
|
42
|
+
resolution : Number of evaluation points for symbolic expressions (default=400)
|
|
43
|
+
show : Whether to display the animation (default=True)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
matplotlib.animation.FuncAnimation
|
|
47
|
+
The animation object
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
# Configuration
|
|
51
|
+
plt.rcParams["animation.html"] = "jshtml"
|
|
52
|
+
plt.rcParams['figure.dpi'] = 150
|
|
53
|
+
plt.ioff()
|
|
54
|
+
|
|
55
|
+
# Label Formatting
|
|
56
|
+
def _smart_label(lbl):
|
|
57
|
+
"""Converts strings or SymPy objects to LaTeX formatted strings."""
|
|
58
|
+
if lbl is None:
|
|
59
|
+
return None
|
|
60
|
+
if isinstance(lbl, str):
|
|
61
|
+
# Check for LaTeX characters
|
|
62
|
+
if any(c in lbl for c in ['_', '^', '\\', '$']):
|
|
63
|
+
return f"${lbl}$" if '$' not in lbl else lbl
|
|
64
|
+
return lbl
|
|
65
|
+
# Convert SymPy expression to LaTeX
|
|
66
|
+
return f"${latex(lbl)}$"
|
|
67
|
+
|
|
68
|
+
# Data Preparation
|
|
69
|
+
def _prepare_data(raw_exprs, variable_def):
|
|
70
|
+
"""
|
|
71
|
+
Parses inputs (Symbolic/Numeric) and generates consistent (x, y) arrays.
|
|
72
|
+
"""
|
|
73
|
+
# Normalize inputs to lists
|
|
74
|
+
if not isinstance(raw_exprs, list):
|
|
75
|
+
expr_list = [raw_exprs]
|
|
76
|
+
else:
|
|
77
|
+
expr_list = raw_exprs
|
|
78
|
+
|
|
79
|
+
# Determine symbol and range
|
|
80
|
+
is_sympy_mode = True
|
|
81
|
+
|
|
82
|
+
if isinstance(variable_def, tuple):
|
|
83
|
+
if variable_def[0] == 'array':
|
|
84
|
+
is_sympy_mode = False
|
|
85
|
+
x_vals_sample = variable_def[1]
|
|
86
|
+
# If array mode, frames usually equals array length
|
|
87
|
+
nonlocal frames
|
|
88
|
+
frames = len(x_vals_sample)
|
|
89
|
+
x_sym = None
|
|
90
|
+
else:
|
|
91
|
+
x_sym = variable_def[0]
|
|
92
|
+
x_range = variable_def[1]
|
|
93
|
+
x_vals_sample = np.linspace(float(x_range[0]), float(x_range[1]), frames)
|
|
94
|
+
else:
|
|
95
|
+
x_sym = variable_def
|
|
96
|
+
x_range = (-1, 1)
|
|
97
|
+
x_vals_sample = np.linspace(float(x_range[0]), float(x_range[1]), frames)
|
|
98
|
+
|
|
99
|
+
prepared_data = []
|
|
100
|
+
|
|
101
|
+
for expr in expr_list:
|
|
102
|
+
# Handle SymPy Matrices
|
|
103
|
+
if isinstance(expr, Matrix):
|
|
104
|
+
expr = np.array(expr).astype(np.float64).flatten()
|
|
105
|
+
|
|
106
|
+
# Handle Parametric or Data Tuples (x, y)
|
|
107
|
+
if isinstance(expr, (tuple, list)) and len(expr) == 2:
|
|
108
|
+
x_comp, y_comp = expr
|
|
109
|
+
|
|
110
|
+
# Symbolic Parametric
|
|
111
|
+
if isinstance(x_comp, sp.Basic) or isinstance(y_comp, sp.Basic):
|
|
112
|
+
if is_sympy_mode:
|
|
113
|
+
f_x = sp.lambdify(x_sym, x_comp, modules='numpy')
|
|
114
|
+
f_y = sp.lambdify(x_sym, y_comp, modules='numpy')
|
|
115
|
+
x_data = f_x(x_vals_sample)
|
|
116
|
+
y_data = f_y(x_vals_sample)
|
|
117
|
+
else:
|
|
118
|
+
# Fallback if mixed types (shouldn't happen often)
|
|
119
|
+
x_data, y_data = x_comp, y_comp
|
|
120
|
+
else:
|
|
121
|
+
# Numeric Data or Constants
|
|
122
|
+
x_data, y_data = x_comp, y_comp
|
|
123
|
+
|
|
124
|
+
# specific check for constant arrays
|
|
125
|
+
is_x_array = hasattr(x_data, '__len__')
|
|
126
|
+
is_y_array = hasattr(y_data, '__len__')
|
|
127
|
+
|
|
128
|
+
if is_x_array and not is_y_array:
|
|
129
|
+
y_data = np.full_like(x_data, y_data)
|
|
130
|
+
elif not is_x_array and is_y_array:
|
|
131
|
+
x_data = np.full_like(y_data, x_data)
|
|
132
|
+
|
|
133
|
+
prepared_data.append((np.array(x_data), np.array(y_data)))
|
|
134
|
+
|
|
135
|
+
# Handle Single Expressions (y = f(x))
|
|
136
|
+
else:
|
|
137
|
+
expr = sp.sympify(expr)
|
|
138
|
+
|
|
139
|
+
# Constant function check
|
|
140
|
+
if is_sympy_mode and not expr.has(x_sym):
|
|
141
|
+
y_vals = np.full_like(x_vals_sample, float(expr))
|
|
142
|
+
else:
|
|
143
|
+
if is_sympy_mode:
|
|
144
|
+
f = sp.lambdify(x_sym, expr, modules='numpy')
|
|
145
|
+
try:
|
|
146
|
+
y_vals = f(x_vals_sample)
|
|
147
|
+
# Handle case where lambdify returns a scalar for vector input
|
|
148
|
+
if np.isscalar(y_vals):
|
|
149
|
+
y_vals = np.full_like(x_vals_sample, y_vals)
|
|
150
|
+
except Exception:
|
|
151
|
+
# Fallback for complex constant expressions
|
|
152
|
+
y_vals = np.full_like(x_vals_sample, float(expr))
|
|
153
|
+
else:
|
|
154
|
+
y_vals = np.array(expr).flatten()
|
|
155
|
+
|
|
156
|
+
y_vals = np.array(y_vals).flatten()
|
|
157
|
+
prepared_data.append((x_vals_sample, y_vals))
|
|
158
|
+
|
|
159
|
+
return prepared_data
|
|
160
|
+
|
|
161
|
+
# Animation Logic
|
|
162
|
+
def _create_animation_object(plot_data):
|
|
163
|
+
"""Sets up the figure, axes, and FuncAnimation object."""
|
|
164
|
+
|
|
165
|
+
# 1. Normalize Styling
|
|
166
|
+
n_plots = len(plot_data)
|
|
167
|
+
|
|
168
|
+
# Thickness
|
|
169
|
+
if isinstance(linewidth, (int, float)):
|
|
170
|
+
lw_list = [linewidth] * n_plots
|
|
171
|
+
else:
|
|
172
|
+
lw_list = linewidth
|
|
173
|
+
|
|
174
|
+
# Limits Calculation (if None)
|
|
175
|
+
nonlocal xlim, ylim
|
|
176
|
+
if xlim is None:
|
|
177
|
+
all_x = np.concatenate([d[0] for d in plot_data])
|
|
178
|
+
x_min, x_max = np.min(all_x), np.max(all_x)
|
|
179
|
+
dx = x_max - x_min if x_max != x_min else 1.0
|
|
180
|
+
xlim = (x_min - 0.05 * dx, x_max + 0.05 * dx)
|
|
181
|
+
|
|
182
|
+
if ylim is None:
|
|
183
|
+
all_y = np.concatenate([d[1] for d in plot_data])
|
|
184
|
+
y_min, y_max = np.min(all_y), np.max(all_y)
|
|
185
|
+
dy = y_max - y_min if y_max != y_min else 1.0
|
|
186
|
+
ylim = (y_min - 0.1 * dy, y_max + 0.1 * dy)
|
|
187
|
+
|
|
188
|
+
# 2. Setup Figure
|
|
189
|
+
fig, ax = plt.subplots(figsize=(10, 6))
|
|
190
|
+
|
|
191
|
+
# 3. Update Function
|
|
192
|
+
def _update_frame(frame):
|
|
193
|
+
ax.clear()
|
|
194
|
+
|
|
195
|
+
# Use 'frame + 1' to ensure we plot at least one point
|
|
196
|
+
idx = int(frame + 1)
|
|
197
|
+
|
|
198
|
+
for i, (x_data, y_data) in enumerate(plot_data):
|
|
199
|
+
# Safe Styling Retrieval
|
|
200
|
+
style = line_styles[i] if line_styles and i < len(line_styles) else 'solid'
|
|
201
|
+
color = colors[i] if colors and i < len(colors) else None
|
|
202
|
+
|
|
203
|
+
# Label Handling
|
|
204
|
+
raw_lbl = labels[i] if labels and i < len(labels) else None
|
|
205
|
+
lbl = _smart_label(raw_lbl)
|
|
206
|
+
|
|
207
|
+
# Slice data for animation effect
|
|
208
|
+
# Ensure we don't index out of bounds if frames > data length
|
|
209
|
+
curr_x = x_data[:min(idx, len(x_data))]
|
|
210
|
+
curr_y = y_data[:min(idx, len(y_data))]
|
|
211
|
+
|
|
212
|
+
ax.plot(curr_x, curr_y,
|
|
213
|
+
label=lbl,
|
|
214
|
+
linestyle=style,
|
|
215
|
+
color=color,
|
|
216
|
+
linewidth=lw_list[i] if i < len(lw_list) else 2)
|
|
217
|
+
|
|
218
|
+
# Apply Layout Settings
|
|
219
|
+
ax.set_xlim(xlim)
|
|
220
|
+
ax.set_ylim(ylim)
|
|
221
|
+
ax.set_title(_smart_label(title))
|
|
222
|
+
ax.set_xlabel(_smart_label(xlabel))
|
|
223
|
+
ax.set_ylabel(_smart_label(ylabel))
|
|
224
|
+
|
|
225
|
+
if labels:
|
|
226
|
+
ax.legend()
|
|
227
|
+
ax.grid(True, alpha=0.3)
|
|
228
|
+
|
|
229
|
+
# 4. Create Animation
|
|
230
|
+
interval = animation_time / frames
|
|
231
|
+
anim = matplotlib.animation.FuncAnimation(
|
|
232
|
+
fig, _update_frame, frames=frames, interval=interval, repeat=True
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
return anim
|
|
236
|
+
|
|
237
|
+
# Main Execution
|
|
238
|
+
|
|
239
|
+
# 1. Prepare Data
|
|
240
|
+
data = _prepare_data(exprs, var)
|
|
241
|
+
|
|
242
|
+
# 2. Create Animation
|
|
243
|
+
anim_obj = _create_animation_object(data)
|
|
244
|
+
|
|
245
|
+
# 3. Display
|
|
246
|
+
if not show:
|
|
247
|
+
plt.close()
|
|
248
|
+
|
|
249
|
+
return anim_obj
|
|
@@ -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.dev30
|
|
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,206 +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
|
-
from IPython.display import display, HTML
|
|
7
|
-
|
|
8
|
-
def animate(exprs, var,
|
|
9
|
-
# --- Plot Labels ---
|
|
10
|
-
title="Animation", xlabel="x", ylabel="y", labels=None,
|
|
11
|
-
# --- Styling ---
|
|
12
|
-
colors=None, line_styles=None, linewidth=2, scaling=None,
|
|
13
|
-
# --- Limits ---
|
|
14
|
-
xlim=None, ylim=None,
|
|
15
|
-
# --- Animation Settings ---
|
|
16
|
-
animation_time=5000, frames=100, resolution=200, show=True,
|
|
17
|
-
# --- Figure Size ---
|
|
18
|
-
width=800, height=600):
|
|
19
|
-
|
|
20
|
-
"""
|
|
21
|
-
Animates 2D curves from symbolic expressions or numeric datasets using Matplotlib.
|
|
22
|
-
|
|
23
|
-
Parameters:
|
|
24
|
-
exprs : Expression, tuple, or list of expressions to animate (symbolic, parametric, or numeric data)
|
|
25
|
-
var : Symbol or tuple defining the variable and range, or array mode ('array', x_values)
|
|
26
|
-
title : Plot title (string or SymPy expression, LaTeX supported) (default="Animation")
|
|
27
|
-
xlabel : X-axis label (string or SymPy expression, LaTeX supported) (default="x")
|
|
28
|
-
ylabel : Y-axis label (string or SymPy expression, LaTeX supported) (default="y")
|
|
29
|
-
labels : Curve labels (strings or SymPy expressions, LaTeX supported) (default=None)
|
|
30
|
-
colors : Colors for each curve (default=None → Matplotlib cycle)
|
|
31
|
-
line_styles : Line styles for each curve (default=None → solid)
|
|
32
|
-
linewidth : Line width(s) as int or list (default=2)
|
|
33
|
-
scaling : Plot scaling behavior (e.g., 'constrained' for equal aspect ratio)
|
|
34
|
-
xlim : X-axis limits as (min, max) (default=None → auto)
|
|
35
|
-
ylim : Y-axis limits as (min, max) (default=None → auto)
|
|
36
|
-
animation_time : Total animation duration in milliseconds (default=5000)
|
|
37
|
-
frames : Number of animation frames (default=100)
|
|
38
|
-
resolution : Number of evaluation points for symbolic spatial meshes (default=200)
|
|
39
|
-
show : Whether to display the animation (default=True)
|
|
40
|
-
width : Plot width in pixels (default=800)
|
|
41
|
-
height : Plot height in pixels (default=600)
|
|
42
|
-
|
|
43
|
-
Returns:
|
|
44
|
-
matplotlib.animation.FuncAnimation
|
|
45
|
-
The animation object
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
# Jupyter Configuration
|
|
49
|
-
plt.rcParams["animation.html"] = "jshtml"
|
|
50
|
-
plt.rcParams['figure.dpi'] = 100
|
|
51
|
-
plt.ioff()
|
|
52
|
-
|
|
53
|
-
# Default Handling for Mutable Arguments
|
|
54
|
-
if colors is None:
|
|
55
|
-
colors = ['black', 'blue', 'red', 'green']
|
|
56
|
-
if line_styles is None:
|
|
57
|
-
line_styles = ['solid'] * 10
|
|
58
|
-
if labels is None:
|
|
59
|
-
labels = []
|
|
60
|
-
|
|
61
|
-
# Helper: Range Unpacker
|
|
62
|
-
def _unpack_range(r_tuple):
|
|
63
|
-
if len(r_tuple) == 3: return r_tuple[0], float(r_tuple[1]), float(r_tuple[2])
|
|
64
|
-
elif len(r_tuple) == 2: return r_tuple[0], float(r_tuple[1][0]), float(r_tuple[1][1])
|
|
65
|
-
raise ValueError(f"Invalid range format: {r_tuple}")
|
|
66
|
-
|
|
67
|
-
# Parse Main Animation Variable
|
|
68
|
-
t_sym, t_start, t_end = _unpack_range(var)
|
|
69
|
-
t_vals = np.linspace(t_start, t_end, frames)
|
|
70
|
-
|
|
71
|
-
# Process Expressions & Generate Frame Data
|
|
72
|
-
all_curves_data = []
|
|
73
|
-
|
|
74
|
-
if not isinstance(exprs, list): exprs = [exprs]
|
|
75
|
-
|
|
76
|
-
for i, expr in enumerate(exprs):
|
|
77
|
-
|
|
78
|
-
# Check for Deformation Mode: (x, y, (z, 0, h))
|
|
79
|
-
if isinstance(expr, (tuple, list)) and len(expr) == 3 and isinstance(expr[2], (tuple, list)):
|
|
80
|
-
x_e, y_e, spatial_info = expr
|
|
81
|
-
z_sym, z_min, z_max = _unpack_range(spatial_info)
|
|
82
|
-
|
|
83
|
-
# Create Spatial Mesh using resolution parameter
|
|
84
|
-
z_vals = np.linspace(z_min, z_max, resolution)
|
|
85
|
-
|
|
86
|
-
# Lambdify f(z, t)
|
|
87
|
-
fx = sp.lambdify((z_sym, t_sym), x_e, modules='numpy')
|
|
88
|
-
fy = sp.lambdify((z_sym, t_sym), y_e, modules='numpy')
|
|
89
|
-
|
|
90
|
-
frame_x_list = []
|
|
91
|
-
frame_y_list = []
|
|
92
|
-
|
|
93
|
-
for t in t_vals:
|
|
94
|
-
x_res = fx(z_vals, t)
|
|
95
|
-
y_res = fy(z_vals, t)
|
|
96
|
-
|
|
97
|
-
if not hasattr(x_res, '__len__'): x_res = np.full_like(z_vals, x_res)
|
|
98
|
-
if not hasattr(y_res, '__len__'): y_res = np.full_like(z_vals, y_res)
|
|
99
|
-
|
|
100
|
-
frame_x_list.append(x_res)
|
|
101
|
-
frame_y_list.append(y_res)
|
|
102
|
-
|
|
103
|
-
all_curves_data.append({
|
|
104
|
-
'type': 'deformation',
|
|
105
|
-
'x': frame_x_list,
|
|
106
|
-
'y': frame_y_list
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
# Standard Trace Mode
|
|
110
|
-
else:
|
|
111
|
-
if isinstance(expr, (tuple, list)) and len(expr) == 2:
|
|
112
|
-
x_e, y_e = expr
|
|
113
|
-
else:
|
|
114
|
-
x_e, y_e = t_sym, expr
|
|
115
|
-
|
|
116
|
-
fx = sp.lambdify(t_sym, x_e, modules='numpy')
|
|
117
|
-
fy = sp.lambdify(t_sym, y_e, modules='numpy')
|
|
118
|
-
|
|
119
|
-
full_x = fx(t_vals)
|
|
120
|
-
full_y = fy(t_vals)
|
|
121
|
-
|
|
122
|
-
if not hasattr(full_x, '__len__'): full_x = np.full_like(t_vals, full_x)
|
|
123
|
-
if not hasattr(full_y, '__len__'): full_y = np.full_like(t_vals, full_y)
|
|
124
|
-
|
|
125
|
-
all_curves_data.append({
|
|
126
|
-
'type': 'trace',
|
|
127
|
-
'x': full_x,
|
|
128
|
-
'y': full_y
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
# Auto-Scaling
|
|
132
|
-
if xlim is None or ylim is None:
|
|
133
|
-
flat_x, flat_y = [], []
|
|
134
|
-
for c in all_curves_data:
|
|
135
|
-
if c['type'] == 'deformation':
|
|
136
|
-
flat_x.append(np.concatenate(c['x']))
|
|
137
|
-
flat_y.append(np.concatenate(c['y']))
|
|
138
|
-
else:
|
|
139
|
-
flat_x.append(c['x'])
|
|
140
|
-
flat_y.append(c['y'])
|
|
141
|
-
|
|
142
|
-
flat_x = np.concatenate(flat_x)
|
|
143
|
-
flat_y = np.concatenate(flat_y)
|
|
144
|
-
|
|
145
|
-
if xlim is None:
|
|
146
|
-
xmin, xmax = np.min(flat_x), np.max(flat_x)
|
|
147
|
-
pad = (xmax - xmin) * 0.1 if xmax != xmin else 1.0
|
|
148
|
-
xlim = (xmin - pad, xmax + pad)
|
|
149
|
-
|
|
150
|
-
if ylim is None:
|
|
151
|
-
ymin, ymax = np.min(flat_y), np.max(flat_y)
|
|
152
|
-
pad = (ymax - ymin) * 0.1 if ymax != ymin else 1.0
|
|
153
|
-
ylim = (ymin - pad, ymax + pad)
|
|
154
|
-
|
|
155
|
-
# Plotting Setup
|
|
156
|
-
fig, ax = plt.subplots(figsize=(width/100, height/100))
|
|
157
|
-
|
|
158
|
-
if scaling == 'constrained' or (isinstance(scaling, list) and 'constrained' in scaling):
|
|
159
|
-
ax.set_aspect('equal')
|
|
160
|
-
|
|
161
|
-
ax.set_xlim(xlim)
|
|
162
|
-
ax.set_ylim(ylim)
|
|
163
|
-
ax.grid(True, alpha=0.3)
|
|
164
|
-
|
|
165
|
-
def fmt_latex(l):
|
|
166
|
-
return f"${latex(l)}$" if hasattr(l, 'free_symbols') or (isinstance(l, str) and '\\' in l) else str(l)
|
|
167
|
-
|
|
168
|
-
ax.set_title(fmt_latex(title))
|
|
169
|
-
ax.set_xlabel(fmt_latex(xlabel))
|
|
170
|
-
ax.set_ylabel(fmt_latex(ylabel))
|
|
171
|
-
|
|
172
|
-
# Initialize Lines
|
|
173
|
-
lines = []
|
|
174
|
-
for i in range(len(all_curves_data)):
|
|
175
|
-
col = colors[i % len(colors)]
|
|
176
|
-
sty = line_styles[i % len(line_styles)]
|
|
177
|
-
lbl = labels[i] if i < len(labels) else None
|
|
178
|
-
|
|
179
|
-
if isinstance(linewidth, list): lw = linewidth[i % len(linewidth)]
|
|
180
|
-
else: lw = linewidth
|
|
181
|
-
|
|
182
|
-
ln, = ax.plot([], [], color=col, linestyle=sty, linewidth=lw, label=fmt_latex(lbl) if lbl else None)
|
|
183
|
-
lines.append(ln)
|
|
184
|
-
|
|
185
|
-
if any(labels): ax.legend()
|
|
186
|
-
|
|
187
|
-
# Animation Loop
|
|
188
|
-
def update_frame(frame_idx):
|
|
189
|
-
t_curr = t_vals[frame_idx]
|
|
190
|
-
ax.set_title(f"{fmt_latex(title)} ($t={t_curr:.2f}$)")
|
|
191
|
-
|
|
192
|
-
for i, data in enumerate(all_curves_data):
|
|
193
|
-
if data['type'] == 'deformation':
|
|
194
|
-
lines[i].set_data(data['x'][frame_idx], data['y'][frame_idx])
|
|
195
|
-
else:
|
|
196
|
-
lines[i].set_data(data['x'][:frame_idx+1], data['y'][:frame_idx+1])
|
|
197
|
-
|
|
198
|
-
ani = matplotlib.animation.FuncAnimation(
|
|
199
|
-
fig, update_frame, frames=frames, interval=animation_time/frames, blit=False
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
if show:
|
|
203
|
-
display(HTML(ani.to_jshtml()))
|
|
204
|
-
plt.close()
|
|
205
|
-
|
|
206
|
-
return ani
|
|
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.dev29 → ibb_helper-0.4.8.dev30}/src/IBB_Helper.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|