tascpy 0.1.0__py3-none-any.whl

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.
Files changed (81) hide show
  1. tascpy/__init__.py +33 -0
  2. tascpy/domains/__init__.py +0 -0
  3. tascpy/domains/converters.py +458 -0
  4. tascpy/domains/coordinate.py +266 -0
  5. tascpy/domains/factory.py +76 -0
  6. tascpy/domains/load_displacement.py +270 -0
  7. tascpy/experiment.py +108 -0
  8. tascpy/operations/__init__.py +26 -0
  9. tascpy/operations/__pycache__/__init__.cpython-312.pyc +0 -0
  10. tascpy/operations/__pycache__/list_proxy.cpython-312.pyc +0 -0
  11. tascpy/operations/__pycache__/proxy.cpython-312.pyc +0 -0
  12. tascpy/operations/__pycache__/registry.cpython-312.pyc +0 -0
  13. tascpy/operations/__pycache__/stub_generator.cpython-312.pyc +0 -0
  14. tascpy/operations/coordinate/__init__.py +8 -0
  15. tascpy/operations/coordinate/__pycache__/__init__.cpython-312.pyc +0 -0
  16. tascpy/operations/coordinate/__pycache__/basic.cpython-312.pyc +0 -0
  17. tascpy/operations/coordinate/__pycache__/distance.cpython-312.pyc +0 -0
  18. tascpy/operations/coordinate/__pycache__/interpolation.cpython-312.pyc +0 -0
  19. tascpy/operations/coordinate/__pycache__/plot.cpython-312.pyc +0 -0
  20. tascpy/operations/coordinate/basic.py +140 -0
  21. tascpy/operations/coordinate/distance.py +289 -0
  22. tascpy/operations/coordinate/interpolation.py +479 -0
  23. tascpy/operations/coordinate/plot.py +1397 -0
  24. tascpy/operations/core/__init__.py +22 -0
  25. tascpy/operations/core/__pycache__/__init__.cpython-312.pyc +0 -0
  26. tascpy/operations/core/__pycache__/combine.cpython-312.pyc +0 -0
  27. tascpy/operations/core/__pycache__/filters.cpython-312.pyc +0 -0
  28. tascpy/operations/core/__pycache__/interpolate.cpython-312.pyc +0 -0
  29. tascpy/operations/core/__pycache__/math.cpython-312.pyc +0 -0
  30. tascpy/operations/core/__pycache__/plot.cpython-312.pyc +0 -0
  31. tascpy/operations/core/__pycache__/search.cpython-312.pyc +0 -0
  32. tascpy/operations/core/__pycache__/select.cpython-312.pyc +0 -0
  33. tascpy/operations/core/__pycache__/split.cpython-312.pyc +0 -0
  34. tascpy/operations/core/__pycache__/stats.cpython-312.pyc +0 -0
  35. tascpy/operations/core/__pycache__/transform.cpython-312.pyc +0 -0
  36. tascpy/operations/core/combine.py +525 -0
  37. tascpy/operations/core/filters.py +311 -0
  38. tascpy/operations/core/interpolate.py +299 -0
  39. tascpy/operations/core/math.py +829 -0
  40. tascpy/operations/core/plot.py +303 -0
  41. tascpy/operations/core/search.py +328 -0
  42. tascpy/operations/core/select.py +228 -0
  43. tascpy/operations/core/split.py +71 -0
  44. tascpy/operations/core/stats.py +212 -0
  45. tascpy/operations/core/transform.py +762 -0
  46. tascpy/operations/list_proxy.py +161 -0
  47. tascpy/operations/load_displacement/__init__.py +10 -0
  48. tascpy/operations/load_displacement/__pycache__/__init__.cpython-312.pyc +0 -0
  49. tascpy/operations/load_displacement/__pycache__/analysis.cpython-312.pyc +0 -0
  50. tascpy/operations/load_displacement/__pycache__/curves.cpython-312.pyc +0 -0
  51. tascpy/operations/load_displacement/__pycache__/cycles.cpython-312.pyc +0 -0
  52. tascpy/operations/load_displacement/__pycache__/plot.cpython-312.pyc +0 -0
  53. tascpy/operations/load_displacement/__pycache__/utils.cpython-312.pyc +0 -0
  54. tascpy/operations/load_displacement/analysis.py +642 -0
  55. tascpy/operations/load_displacement/curves.py +620 -0
  56. tascpy/operations/load_displacement/cycles.py +113 -0
  57. tascpy/operations/load_displacement/plot.py +554 -0
  58. tascpy/operations/load_displacement/utils.py +103 -0
  59. tascpy/operations/proxy.py +148 -0
  60. tascpy/operations/registry.py +359 -0
  61. tascpy/operations/stub_generator.py +646 -0
  62. tascpy/plugins/load_displacement.py +411 -0
  63. tascpy/py.typed +0 -0
  64. tascpy/typing/__init__.py +21 -0
  65. tascpy/typing/coordinate.py +1504 -0
  66. tascpy/typing/core.py +1257 -0
  67. tascpy/typing/list_proxy.py +93 -0
  68. tascpy/typing/load_displacement.py +1733 -0
  69. tascpy/typing/proxy_base.py +27 -0
  70. tascpy/typing/stubs.py +27 -0
  71. tascpy/utils/__init__.py +0 -0
  72. tascpy/utils/conversion.py +20 -0
  73. tascpy/utils/data.py +681 -0
  74. tascpy/utils/operation_decorator.py +21 -0
  75. tascpy/utils/plot.py +208 -0
  76. tascpy/utils/split.py +191 -0
  77. tascpy-0.1.0.dist-info/METADATA +224 -0
  78. tascpy-0.1.0.dist-info/RECORD +81 -0
  79. tascpy-0.1.0.dist-info/WHEEL +5 -0
  80. tascpy-0.1.0.dist-info/licenses/LICENSE +21 -0
  81. tascpy-0.1.0.dist-info/top_level.txt +1 -0
tascpy/__init__.py ADDED
@@ -0,0 +1,33 @@
1
+ """
2
+ tascpy - 実験データ処理のためのPythonライブラリ
3
+ """
4
+
5
+ import warnings
6
+
7
+ __version__ = "0.1.0"
8
+ __all__ = ["Experiment", "Reader"]
9
+
10
+ # 日本語フォントの自動設定を先に試行
11
+ japanize_available = False
12
+ try:
13
+ import japanize_matplotlib
14
+ import matplotlib as mpl
15
+
16
+ # 警告抑制機能をコメントアウトして、実際の警告が表示されるか確認
17
+ # warnings.filterwarnings("ignore", message="Glyph .* missing from font.*")
18
+ # warnings.filterwarnings(
19
+ # "ignore", category=UserWarning, message=".*FigureCanvasAgg is non-interactive.*"
20
+ # )
21
+
22
+ mpl.rcParams["axes.unicode_minus"] = False # マイナス記号を正しく表示
23
+ japanize_available = True
24
+ except ImportError as e:
25
+ # インポートエラーの詳細を警告として表示
26
+ warnings.warn(
27
+ f"japanize_matplotlib をインポートできませんでした: {e}。日本語が正しく表示されない可能性があります。"
28
+ "setuptools パッケージをインストールすることで解決できる場合があります: pip install setuptools"
29
+ )
30
+
31
+ # 公開APIのインポート
32
+ from .experiment import Experiment
33
+ from .io.file_handlers import load_from_file, save_to_file
File without changes
@@ -0,0 +1,458 @@
1
+ from typing import Optional, Any, Dict, List, Union, Tuple, Callable
2
+ from datetime import datetime, timedelta
3
+ import numpy as np
4
+ from ..core.collection import ColumnCollection
5
+ from ..core.step import Step
6
+
7
+
8
+ # ドメイン変換関数のレジストリ
9
+ _DOMAIN_CONVERTERS = {}
10
+
11
+
12
+ def register_domain_converter(source_domain: str = "core", target_domain: str = None):
13
+ """ドメイン変換関数を登録するデコレータ
14
+
15
+ Args:
16
+ source_domain: 変換元のドメイン名
17
+ target_domain: 変換先のドメイン名
18
+
19
+ Returns:
20
+ デコレータ関数
21
+ """
22
+
23
+ def decorator(func: Callable):
24
+ key = (source_domain, target_domain)
25
+ _DOMAIN_CONVERTERS[key] = func
26
+ return func
27
+
28
+ return decorator
29
+
30
+
31
+ def prepare_for_domain_conversion(
32
+ collection: ColumnCollection, target_domain: str, **kwargs: Any
33
+ ) -> Tuple[ColumnCollection, Dict[str, Any]]:
34
+ """ドメイン変換の前準備を行う
35
+
36
+ Args:
37
+ collection: 変換元のColumnCollection
38
+ target_domain: 変換先のドメイン名
39
+ **kwargs: 変換パラメータ
40
+
41
+ Returns:
42
+ 変換準備が完了したColumnCollection と 更新されたkwargs
43
+ """
44
+ # 元のコレクションをクローン
45
+ result = collection.clone()
46
+
47
+ # 変換元ドメインを決定(メタデータから取得、なければ "core")
48
+ source_domain = collection.metadata.get("domain", "core")
49
+
50
+ # coreドメインへの変換は汎用関数を使用
51
+ if target_domain == "core" and source_domain != "core":
52
+ return prepare_for_core(result, **kwargs)
53
+
54
+ # 登録されている変換関数を探す
55
+ converter_key = (source_domain, target_domain)
56
+ if converter_key in _DOMAIN_CONVERTERS:
57
+ # 登録されている変換関数を実行
58
+ result, mod_kwargs = _DOMAIN_CONVERTERS[converter_key](result, **kwargs)
59
+ return result, mod_kwargs
60
+
61
+ # 従来の変換関数で対応(後方互換性のため)
62
+ if target_domain == "timeseries":
63
+ mod_kwargs = _prepare_for_timeseries(result, **kwargs)
64
+ return result, mod_kwargs
65
+ elif target_domain == "signal":
66
+ mod_kwargs = _prepare_for_signal(result, **kwargs)
67
+ return result, mod_kwargs
68
+ elif target_domain == "load_displacement":
69
+ mod_kwargs = _prepare_for_load_displacement(result, **kwargs)
70
+ return result, mod_kwargs
71
+
72
+ # 対応する変換関数がない場合は、そのまま返す
73
+ return result, kwargs
74
+
75
+
76
+ def _prepare_for_timeseries(
77
+ collection: ColumnCollection, **kwargs: Any
78
+ ) -> Dict[str, Any]:
79
+ """時系列ドメインへの変換前処理
80
+
81
+ Args:
82
+ collection: 前処理するコレクション
83
+ **kwargs: 変換パラメータ
84
+
85
+ Returns:
86
+ 更新されたkwargs
87
+ """
88
+ # ステップが数値で、start_dateが指定されている場合は日付に変換
89
+ if (
90
+ len(collection.step.values) > 0
91
+ and not isinstance(collection.step.values[0], datetime)
92
+ and "start_date" in kwargs
93
+ ):
94
+
95
+ # 開始日を解析
96
+ if isinstance(kwargs["start_date"], str):
97
+ start_date = datetime.fromisoformat(kwargs["start_date"])
98
+ else:
99
+ start_date = kwargs["start_date"]
100
+
101
+ # 頻度を解析(デフォルトは1日)
102
+ freq = kwargs.get("frequency", "1D")
103
+ if freq == "1D":
104
+ delta = timedelta(days=1)
105
+ elif freq == "1H":
106
+ delta = timedelta(hours=1)
107
+ elif freq == "1min" or freq == "1m":
108
+ delta = timedelta(minutes=1)
109
+ elif freq == "1s":
110
+ delta = timedelta(seconds=1)
111
+ else:
112
+ # カスタム形式の解析(例: "2H", "30min")
113
+ import re
114
+
115
+ match = re.match(r"(\d+)([DHMSdhms])", freq)
116
+ if match:
117
+ value, unit = int(match.group(1)), match.group(2).upper()
118
+ if unit == "D":
119
+ delta = timedelta(days=value)
120
+ elif unit == "H":
121
+ delta = timedelta(hours=value)
122
+ elif unit == "M":
123
+ delta = timedelta(minutes=value)
124
+ elif unit == "S":
125
+ delta = timedelta(seconds=value)
126
+ else:
127
+ delta = timedelta(days=1) # デフォルト
128
+ else:
129
+ delta = timedelta(days=1) # 解析失敗時はデフォルト
130
+
131
+ # ステップを日付に変換
132
+ step_values = [
133
+ start_date + (delta * float(step)) for step in collection.step.values
134
+ ]
135
+
136
+ # 新しいStepオブジェクトを作成
137
+ collection.step = Step(values=step_values)
138
+
139
+ # 使用済みのキーをkwargsから削除
140
+ kwargs.pop("start_date", None)
141
+ return kwargs
142
+ return kwargs
143
+
144
+
145
+ def _prepare_for_signal(collection: ColumnCollection, **kwargs: Any) -> Dict[str, Any]:
146
+ """信号処理ドメインへの変換前処理
147
+
148
+ Args:
149
+ collection: 前処理するコレクション
150
+ **kwargs: 変換パラメータ
151
+
152
+ Returns:
153
+ 更新されたkwargs
154
+ """
155
+ # 日付ステップを時間軸に変換
156
+ if len(collection.step.values) > 0 and isinstance(
157
+ collection.step.values[0], datetime
158
+ ):
159
+
160
+ # サンプリングレートを取得
161
+ sample_rate = kwargs.get("sample_rate", 1.0)
162
+
163
+ # 開始時間を0とする時間軸に変換
164
+ start_time = collection.step.values[0]
165
+ time_values = [
166
+ (dt - start_time).total_seconds() for dt in collection.step.values
167
+ ]
168
+
169
+ # 新しいStepオブジェクトを作成
170
+ collection.step = Step(values=time_values)
171
+
172
+ # 元の時間情報をメタデータに保存
173
+ collection.metadata["original_timestamps"] = {
174
+ "start": start_time.isoformat(),
175
+ "sample_rate": sample_rate,
176
+ }
177
+
178
+ # 時間が等間隔でない場合、リサンプリングの警告をメタデータに追加
179
+ time_diffs = np.diff(time_values)
180
+ if len(time_diffs) > 0 and np.std(time_diffs) > 1e-6:
181
+ collection.metadata["signal_warning"] = (
182
+ "非等間隔データです。信号処理前にリサンプリングを検討してください。"
183
+ )
184
+ return kwargs
185
+ return kwargs
186
+
187
+
188
+ def _prepare_for_load_displacement(
189
+ collection: ColumnCollection, **kwargs: Any
190
+ ) -> Dict[str, Any]:
191
+ """一般コレクションから荷重-変位コレクションへの変換準備を行う
192
+
193
+ Args:
194
+ collection: 変換元のコレクション
195
+ **kwargs: 追加のパラメータ
196
+
197
+ Returns:
198
+ Dict[str, Any]: 更新されたkwargs
199
+ """
200
+ # 荷重カラムと変位カラムを決定
201
+ load_column = kwargs.get("load_column")
202
+ disp_column = kwargs.get("displacement_column")
203
+
204
+ # カラム名が指定されていない場合、既存カラムから推測
205
+ if not load_column:
206
+ # 荷重を含むカラム名を探す
207
+ possible_load_columns = ["load", "force", "荷重", "力"]
208
+ for colname in possible_load_columns:
209
+ matching = [
210
+ c for c in collection.columns.keys() if colname.lower() in c.lower()
211
+ ]
212
+ if matching:
213
+ load_column = matching[0]
214
+ break
215
+
216
+ if not disp_column:
217
+ # 変位を含むカラム名を探す
218
+ possible_disp_columns = ["disp", "displacement", "変位", "変形"]
219
+ for colname in possible_disp_columns:
220
+ matching = [
221
+ c for c in collection.columns.keys() if colname.lower() in c.lower()
222
+ ]
223
+ if matching:
224
+ disp_column = matching[0]
225
+ break
226
+
227
+ # カラム名が見つからない場合は最初の数値カラムを使用
228
+ if not load_column or not disp_column:
229
+ numeric_columns = [
230
+ name
231
+ for name, col in collection.columns.items()
232
+ if any(isinstance(v, (int, float)) for v in col.values)
233
+ ]
234
+
235
+ if len(numeric_columns) >= 2:
236
+ if not load_column:
237
+ load_column = numeric_columns[0]
238
+ if not disp_column:
239
+ disp_column = numeric_columns[1]
240
+
241
+ # 必要なカラムが見つからない場合はエラー
242
+ if not load_column and not disp_column:
243
+ raise ValueError("荷重と変位のカラムを指定または検出できませんでした")
244
+ elif not load_column:
245
+ raise ValueError("load_column が指定されていないか、検出できませんでした")
246
+ elif not disp_column:
247
+ raise ValueError(
248
+ "displacement_column が指定されていないか、検出できませんでした"
249
+ )
250
+
251
+ # 更新されたkwargsを返す
252
+ kwargs.update({"load_column": load_column, "displacement_column": disp_column})
253
+
254
+ return kwargs
255
+
256
+
257
+ @register_domain_converter(source_domain="core", target_domain="load_displacement")
258
+ def prepare_for_load_displacement(
259
+ collection: ColumnCollection, **kwargs: Any
260
+ ) -> Tuple[ColumnCollection, Dict[str, Any]]:
261
+ """一般コレクションから荷重-変位コレクションへの変換準備を行う
262
+
263
+ Args:
264
+ collection: 変換元のコレクション
265
+ **kwargs: 追加のパラメータ
266
+
267
+ Returns:
268
+ Tuple[ColumnCollection, Dict[str, Any]]:
269
+ (変換用に準備されたコレクション, 更新されたkwargs)
270
+ """
271
+ # 従来の関数を利用して処理
272
+ modified_kwargs = _prepare_for_load_displacement(collection, **kwargs)
273
+ return collection, modified_kwargs
274
+
275
+
276
+ @register_domain_converter(source_domain="core", target_domain="coordinate")
277
+ def prepare_for_coordinate(
278
+ collection: ColumnCollection, **kwargs: Any
279
+ ) -> Tuple[ColumnCollection, Dict[str, Any]]:
280
+ """一般コレクションから座標コレクションへの変換準備を行う
281
+
282
+ Args:
283
+ collection: 変換元のコレクション
284
+ **kwargs: 追加のパラメータ
285
+
286
+ Returns:
287
+ Tuple[ColumnCollection, Dict[str, Any]]:
288
+ (変換用に準備されたコレクション, 更新されたkwargs)
289
+ """
290
+ # 座標メタデータキーの設定
291
+ coordinate_metadata_key = kwargs.get("coordinate_metadata_key", "coordinates")
292
+
293
+ # 既存のカラムに座標情報が設定されているか確認
294
+ coordinate_columns = {}
295
+ for col_name, col in collection.columns.items():
296
+ if hasattr(col, "metadata") and col.metadata:
297
+ for meta_key, meta_value in col.metadata.items():
298
+ if isinstance(meta_value, dict) and all(
299
+ k in meta_value for k in ["x", "y"]
300
+ ):
301
+ # 座標情報っぽいメタデータが見つかった場合
302
+ coordinate_columns[col_name] = {
303
+ "x": meta_value.get("x"),
304
+ "y": meta_value.get("y"),
305
+ "z": meta_value.get("z", None),
306
+ }
307
+ break
308
+
309
+ # 座標情報が見つかった場合、それをメタデータキーに設定
310
+ if coordinate_columns:
311
+ for col_name, coords in coordinate_columns.items():
312
+ # メタデータが未設定の場合は初期化
313
+ if not collection.columns[col_name].metadata:
314
+ collection.columns[col_name].metadata = {}
315
+
316
+ # 座標情報をメタデータに設定
317
+ collection.columns[col_name].metadata[coordinate_metadata_key] = coords
318
+
319
+ # 更新されたkwargsを返す
320
+ kwargs.update({"coordinate_metadata_key": coordinate_metadata_key})
321
+ return collection, kwargs
322
+
323
+
324
+ @register_domain_converter(source_domain="load_displacement", target_domain="core")
325
+ def prepare_for_core_from_load_displacement(
326
+ collection: ColumnCollection, **kwargs: Any
327
+ ) -> Tuple[ColumnCollection, Dict[str, Any]]:
328
+ """荷重-変位コレクションから一般コレクションへの変換準備を行う
329
+
330
+ Args:
331
+ collection: 変換元の荷重-変位コレクション
332
+ **kwargs: 追加のパラメータ
333
+
334
+ Returns:
335
+ Tuple[ColumnCollection, Dict[str, Any]]:
336
+ (変換用に準備されたコレクション, 更新されたkwargs)
337
+ """
338
+ # 汎用変換関数を使用
339
+ return prepare_for_core(collection, **kwargs)
340
+
341
+
342
+ @register_domain_converter(source_domain="coordinate", target_domain="core")
343
+ def prepare_for_core_from_coordinate(
344
+ collection: ColumnCollection, **kwargs: Any
345
+ ) -> Tuple[ColumnCollection, Dict[str, Any]]:
346
+ """座標コレクションから一般コレクションへの変換準備を行う
347
+
348
+ Args:
349
+ collection: 変換元の座標コレクション
350
+ **kwargs: 追加のパラメータ
351
+
352
+ Returns:
353
+ Tuple[ColumnCollection, Dict[str, Any]]:
354
+ (変換用に準備されたコレクション, 更新されたkwargs)
355
+ """
356
+ # 汎用変換関数を使用
357
+ return prepare_for_core(collection, **kwargs)
358
+
359
+
360
+ def prepare_for_core(
361
+ collection: ColumnCollection, **kwargs: Any
362
+ ) -> Tuple[ColumnCollection, Dict[str, Any]]:
363
+ """任意のドメインからcoreドメインへの変換準備を行う汎用関数
364
+
365
+ Args:
366
+ collection: 変換元のコレクション
367
+ **kwargs: 追加のパラメータ
368
+
369
+ Returns:
370
+ Tuple[ColumnCollection, Dict[str, Any]]:
371
+ (変換用に準備されたコレクション, 更新されたkwargs)
372
+ """
373
+ # 元のドメインを取得
374
+ source_domain = collection.metadata.get("domain", "core")
375
+
376
+ # すでにcoreドメインの場合はそのまま返す
377
+ if source_domain == "core":
378
+ return collection, kwargs
379
+
380
+ # ドメイン固有の属性や設定を保存
381
+ if "domain_metadata" not in collection.metadata:
382
+ collection.metadata["domain_metadata"] = {}
383
+
384
+ domain_metadata = collection.metadata["domain_metadata"]
385
+ if source_domain not in domain_metadata:
386
+ domain_metadata[source_domain] = {}
387
+
388
+ # 各ドメイン固有の属性を保存
389
+ if source_domain == "load_displacement":
390
+ # 荷重-変位ドメインの属性を保存
391
+ # __dict__を使用して直接属性を取得
392
+ obj_dict = vars(collection)
393
+ if "_load_column" in obj_dict:
394
+ domain_metadata["load_displacement"]["load_column"] = obj_dict[
395
+ "_load_column"
396
+ ]
397
+ if "_displacement_column" in obj_dict:
398
+ domain_metadata["load_displacement"]["displacement_column"] = obj_dict[
399
+ "_displacement_column"
400
+ ]
401
+
402
+ elif source_domain == "coordinate":
403
+ # 座標ドメインの属性を保存
404
+ coordinate_metadata_key = kwargs.get("coordinate_metadata_key", "coordinates")
405
+ if "coordinate_metadata_key" in collection.metadata:
406
+ coordinate_metadata_key = collection.metadata["coordinate_metadata_key"]
407
+
408
+ # 座標情報を収集
409
+ coordinates = {}
410
+ for col_name, col in collection.columns.items():
411
+ if (
412
+ hasattr(col, "metadata")
413
+ and col.metadata
414
+ and coordinate_metadata_key in col.metadata
415
+ ):
416
+ coordinates[col_name] = col.metadata[coordinate_metadata_key]
417
+
418
+ # 明示的に属性をドメインメタデータに保存
419
+ domain_metadata["coordinate"]["coordinates"] = coordinates
420
+ domain_metadata["coordinate"][
421
+ "coordinate_metadata_key"
422
+ ] = coordinate_metadata_key
423
+
424
+ elif source_domain == "timeseries":
425
+ # 時系列ドメインの属性を保存
426
+ frequency = collection.metadata.get("frequency")
427
+ if frequency:
428
+ domain_metadata["timeseries"]["frequency"] = frequency
429
+
430
+ elif source_domain == "signal":
431
+ # 信号処理ドメインの属性を保存
432
+ if "original_timestamps" in collection.metadata:
433
+ domain_metadata["signal"]["original_timestamps"] = collection.metadata[
434
+ "original_timestamps"
435
+ ]
436
+
437
+ if "sample_rate" in collection.metadata:
438
+ domain_metadata["signal"]["sample_rate"] = collection.metadata[
439
+ "sample_rate"
440
+ ]
441
+
442
+ # その他の登録されているドメインの場合は、関連するメタデータを保存
443
+ # ここでは不明な属性も含めて、ドメイン固有のメタデータをすべて保存
444
+ for key, value in collection.metadata.items():
445
+ if key not in ["domain", "domain_metadata"]:
446
+ domain_metadata[source_domain][key] = value
447
+
448
+ # 継承した属性やプロパティの取得と保存
449
+ attributes_to_check = ["_domain_specific_attributes", "_custom_properties"]
450
+ for attr_name in attributes_to_check:
451
+ if hasattr(collection, attr_name) and getattr(collection, attr_name):
452
+ domain_metadata[source_domain][attr_name] = getattr(collection, attr_name)
453
+
454
+ # ドメイン名をcoreに変更
455
+ collection.metadata["domain"] = "core"
456
+
457
+ # 更新されたkwargsを返す
458
+ return collection, kwargs