AeroViz 0.1.2__py3-none-any.whl → 0.1.3b0__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.

Potentially problematic release.


This version of AeroViz might be problematic. Click here for more details.

Files changed (112) hide show
  1. AeroViz/__init__.py +4 -4
  2. AeroViz/config/DEFAULT_DATA.csv +1417 -0
  3. AeroViz/config/DEFAULT_PNSD_DATA.csv +1417 -0
  4. AeroViz/dataProcess/Chemistry/__init__.py +38 -38
  5. AeroViz/dataProcess/Chemistry/_calculate.py +15 -15
  6. AeroViz/dataProcess/Chemistry/_isoropia.py +69 -68
  7. AeroViz/dataProcess/Chemistry/_mass_volume.py +158 -158
  8. AeroViz/dataProcess/Chemistry/_ocec.py +109 -109
  9. AeroViz/dataProcess/Chemistry/_partition.py +19 -18
  10. AeroViz/dataProcess/Chemistry/_teom.py +8 -11
  11. AeroViz/dataProcess/Optical/_IMPROVE.py +40 -39
  12. AeroViz/dataProcess/Optical/__init__.py +35 -35
  13. AeroViz/dataProcess/Optical/_absorption.py +35 -35
  14. AeroViz/dataProcess/Optical/_extinction.py +25 -24
  15. AeroViz/dataProcess/Optical/_mie.py +5 -6
  16. AeroViz/dataProcess/Optical/_mie_sd.py +89 -90
  17. AeroViz/dataProcess/Optical/_scattering.py +16 -16
  18. AeroViz/dataProcess/SizeDistr/__init__.py +37 -37
  19. AeroViz/dataProcess/SizeDistr/__merge.py +159 -158
  20. AeroViz/dataProcess/SizeDistr/_merge.py +155 -154
  21. AeroViz/dataProcess/SizeDistr/_merge_v1.py +162 -161
  22. AeroViz/dataProcess/SizeDistr/_merge_v2.py +153 -152
  23. AeroViz/dataProcess/SizeDistr/_merge_v3.py +326 -326
  24. AeroViz/dataProcess/SizeDistr/_merge_v4.py +272 -274
  25. AeroViz/dataProcess/SizeDistr/_size_distr.py +51 -51
  26. AeroViz/dataProcess/VOC/__init__.py +7 -7
  27. AeroViz/dataProcess/VOC/_potential_par.py +53 -55
  28. AeroViz/dataProcess/VOC/voc_par.json +464 -0
  29. AeroViz/dataProcess/__init__.py +4 -4
  30. AeroViz/dataProcess/core/__init__.py +59 -58
  31. AeroViz/plot/__init__.py +6 -1
  32. AeroViz/plot/bar.py +126 -0
  33. AeroViz/plot/box.py +68 -0
  34. AeroViz/plot/distribution/distribution.py +421 -427
  35. AeroViz/plot/meteorology/meteorology.py +240 -292
  36. AeroViz/plot/optical/__init__.py +0 -1
  37. AeroViz/plot/optical/optical.py +230 -230
  38. AeroViz/plot/pie.py +198 -0
  39. AeroViz/plot/regression.py +210 -0
  40. AeroViz/plot/scatter.py +99 -0
  41. AeroViz/plot/templates/__init__.py +0 -3
  42. AeroViz/plot/templates/contour.py +25 -25
  43. AeroViz/plot/templates/corr_matrix.py +86 -93
  44. AeroViz/plot/templates/diurnal_pattern.py +24 -24
  45. AeroViz/plot/templates/koschmieder.py +106 -106
  46. AeroViz/plot/templates/metal_heatmap.py +34 -34
  47. AeroViz/plot/timeseries/timeseries.py +53 -60
  48. AeroViz/plot/utils/__init__.py +2 -1
  49. AeroViz/plot/utils/_color.py +57 -57
  50. AeroViz/plot/utils/_unit.py +48 -48
  51. AeroViz/plot/utils/fRH.json +390 -0
  52. AeroViz/plot/utils/plt_utils.py +92 -0
  53. AeroViz/plot/utils/sklearn_utils.py +49 -0
  54. AeroViz/plot/utils/units.json +84 -0
  55. AeroViz/plot/violin.py +79 -0
  56. AeroViz/process/__init__.py +15 -15
  57. AeroViz/process/core/DataProc.py +9 -9
  58. AeroViz/process/core/SizeDist.py +81 -81
  59. AeroViz/process/method/PyMieScatt_update.py +488 -488
  60. AeroViz/process/method/mie_theory.py +231 -229
  61. AeroViz/process/method/prop.py +40 -40
  62. AeroViz/process/script/AbstractDistCalc.py +103 -103
  63. AeroViz/process/script/Chemical.py +166 -166
  64. AeroViz/process/script/IMPACT.py +40 -40
  65. AeroViz/process/script/IMPROVE.py +152 -152
  66. AeroViz/process/script/Others.py +45 -45
  67. AeroViz/process/script/PSD.py +26 -26
  68. AeroViz/process/script/PSD_dry.py +69 -70
  69. AeroViz/process/script/retrieve_RI.py +50 -51
  70. AeroViz/rawDataReader/__init__.py +57 -57
  71. AeroViz/rawDataReader/core/__init__.py +328 -326
  72. AeroViz/rawDataReader/script/AE33.py +18 -18
  73. AeroViz/rawDataReader/script/AE43.py +20 -20
  74. AeroViz/rawDataReader/script/APS_3321.py +30 -30
  75. AeroViz/rawDataReader/script/Aurora.py +23 -23
  76. AeroViz/rawDataReader/script/BC1054.py +40 -40
  77. AeroViz/rawDataReader/script/EPA_vertical.py +9 -9
  78. AeroViz/rawDataReader/script/GRIMM.py +21 -21
  79. AeroViz/rawDataReader/script/IGAC_TH.py +67 -67
  80. AeroViz/rawDataReader/script/IGAC_ZM.py +59 -59
  81. AeroViz/rawDataReader/script/MA350.py +39 -39
  82. AeroViz/rawDataReader/script/NEPH.py +74 -74
  83. AeroViz/rawDataReader/script/OCEC_LCRES.py +21 -21
  84. AeroViz/rawDataReader/script/OCEC_RES.py +16 -16
  85. AeroViz/rawDataReader/script/SMPS_TH.py +25 -25
  86. AeroViz/rawDataReader/script/SMPS_aim11.py +32 -32
  87. AeroViz/rawDataReader/script/SMPS_genr.py +31 -31
  88. AeroViz/rawDataReader/script/TEOM.py +28 -28
  89. AeroViz/rawDataReader/script/Table.py +12 -12
  90. AeroViz/rawDataReader/script/VOC_TH.py +16 -16
  91. AeroViz/rawDataReader/script/VOC_ZM.py +28 -28
  92. AeroViz/rawDataReader/script/__init__.py +20 -20
  93. AeroViz/rawDataReader/utils/config.py +161 -161
  94. AeroViz/tools/database.py +65 -65
  95. AeroViz/tools/dataclassifier.py +106 -106
  96. AeroViz/tools/dataprinter.py +51 -51
  97. AeroViz/tools/datareader.py +38 -38
  98. {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/METADATA +5 -4
  99. AeroViz-0.1.3b0.dist-info/RECORD +110 -0
  100. AeroViz/config/__init__.py +0 -0
  101. AeroViz/plot/improve/__init__.py +0 -1
  102. AeroViz/plot/improve/improve.py +0 -240
  103. AeroViz/plot/optical/aethalometer.py +0 -77
  104. AeroViz/plot/templates/event_evolution.py +0 -65
  105. AeroViz/plot/templates/regression.py +0 -256
  106. AeroViz/plot/templates/scatter.py +0 -130
  107. AeroViz/plot/templates/templates.py +0 -398
  108. AeroViz/plot/utils/_decorator.py +0 -74
  109. AeroViz-0.1.2.dist-info/RECORD +0 -106
  110. {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/LICENSE +0 -0
  111. {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/WHEEL +0 -0
  112. {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/top_level.txt +0 -0
@@ -69,13 +69,6 @@ def _plot(ax, df, _y, _color, plot_kws):
69
69
  ax.plot(df.index, df[_y], color=_color, **plot_kws)
70
70
 
71
71
 
72
- def combine_legends(axes_list: list[Axes]) -> tuple[list, list]:
73
- return (
74
- [legend for axes in axes_list for legend in axes.get_legend_handles_labels()[0]],
75
- [label for axes in axes_list for label in axes.get_legend_handles_labels()[1]]
76
- )
77
-
78
-
79
72
  @set_figure(fs=8, autolayout=False)
80
73
  def timeseries(df: DataFrame,
81
74
  y: list[str] | str,
@@ -93,59 +86,59 @@ def timeseries(df: DataFrame,
93
86
  **kwargs
94
87
  ) -> tuple[Figure, Axes]:
95
88
  """
96
- Plot the timeseries data with the option of scatterplot, barplot, and lineplot.
97
-
98
- Parameters
99
- -----------
100
- df : DataFrame
101
- The data to plot.
102
- y : list[str] | str
103
- The primary y-axis data columns.
104
- y2 : list[str] | str, optional
105
- The secondary y-axis data columns. Defaults to None.
106
- c : str, optional
107
- The column for color mapping or the color. Defaults to None.
108
- rolling : str | int | None, optional
109
- Rolling window size for smoothing. Defaults to None.
110
- times : tuple[datetime, datetime] | tuple[Timestamp, Timestamp], optional
111
- Time range for the data. Defaults to None.
112
- freq : str, optional
113
- Frequency for x-axis ticks. Defaults to '2MS'.
114
- style : Literal['scatter', 'bar', 'line'] | None, optional
115
- Style of the plot. Defaults to 'scatter'.
116
- ax : Axes | None, optional
117
- Matplotlib Axes object to plot on. Defaults to None.
118
- set_xaxis_visible : bool | None, optional
119
- Whether to set x-axis visibility. Defaults to None.
120
- legend_loc : Literal['best', 'upper right', 'upper left', 'lower left', 'lower right'], optional
121
- Location of the legend. Defaults to 'best'.
122
- legend_ncol : int, optional
123
- Number of columns in the legend. Defaults to 1.
124
- **kwargs : Additional keyword arguments for customization.
125
- fig_kws : dict, optional
126
- Additional keyword arguments for the figure. Defaults to {}.
127
- scatter_kws : dict, optional
128
- Additional keyword arguments for the scatter plot. Defaults to {}.
129
- bar_kws : dict, optional
130
- Additional keyword arguments for the bar plot. Defaults to {}.
131
- ax_plot_kws : dict, optional
132
- Additional keyword arguments for the primary y-axis plot. Defaults to {}.
133
- ax2_plot_kws : dict, optional
134
- Additional keyword arguments for the secondary y-axis plot. Defaults to {}.
135
- cbar_kws : dict, optional
136
- Additional keyword arguments for the colorbar. Defaults to {}.
137
- inset_kws : dict, optional
138
- Additional keyword arguments for the inset axes. Defaults to {}.
139
-
140
- Returns
141
- -------
142
- ax : AxesSubplot
143
- Matplotlib AxesSubplot.
144
-
145
- Example
146
- -------
147
- >>> timeseries(df, y='WS', c='WD', scatter_kws=dict(cmap='hsv'), cbar_kws=dict(ticks=[0, 90, 180, 270, 360]), ylim=[0, None])
148
- """
89
+ Plot the timeseries data with the option of scatterplot, barplot, and lineplot.
90
+
91
+ Parameters
92
+ -----------
93
+ df : DataFrame
94
+ The data to plot.
95
+ y : list[str] | str
96
+ The primary y-axis data columns.
97
+ y2 : list[str] | str, optional
98
+ The secondary y-axis data columns. Defaults to None.
99
+ c : str, optional
100
+ The column for color mapping or the color. Defaults to None.
101
+ rolling : str | int | None, optional
102
+ Rolling window size for smoothing. Defaults to None.
103
+ times : tuple[datetime, datetime] | tuple[Timestamp, Timestamp], optional
104
+ Time range for the data. Defaults to None.
105
+ freq : str, optional
106
+ Frequency for x-axis ticks. Defaults to '2MS'.
107
+ style : Literal['scatter', 'bar', 'line'] | None, optional
108
+ Style of the plot. Defaults to 'scatter'.
109
+ ax : Axes | None, optional
110
+ Matplotlib Axes object to plot on. Defaults to None.
111
+ set_xaxis_visible : bool | None, optional
112
+ Whether to set x-axis visibility. Defaults to None.
113
+ legend_loc : Literal['best', 'upper right', 'upper left', 'lower left', 'lower right'], optional
114
+ Location of the legend. Defaults to 'best'.
115
+ legend_ncol : int, optional
116
+ Number of columns in the legend. Defaults to 1.
117
+ **kwargs : Additional keyword arguments for customization.
118
+ fig_kws : dict, optional
119
+ Additional keyword arguments for the figure. Defaults to {}.
120
+ scatter_kws : dict, optional
121
+ Additional keyword arguments for the scatter plot. Defaults to {}.
122
+ bar_kws : dict, optional
123
+ Additional keyword arguments for the bar plot. Defaults to {}.
124
+ ax_plot_kws : dict, optional
125
+ Additional keyword arguments for the primary y-axis plot. Defaults to {}.
126
+ ax2_plot_kws : dict, optional
127
+ Additional keyword arguments for the secondary y-axis plot. Defaults to {}.
128
+ cbar_kws : dict, optional
129
+ Additional keyword arguments for the colorbar. Defaults to {}.
130
+ inset_kws : dict, optional
131
+ Additional keyword arguments for the inset axes. Defaults to {}.
132
+
133
+ Returns
134
+ -------
135
+ ax : AxesSubplot
136
+ Matplotlib AxesSubplot.
137
+
138
+ Example
139
+ -------
140
+ >>> timeseries(df, y='WS', c='WD', scatter_kws=dict(cmap='hsv'), cbar_kws=dict(ticks=[0, 90, 180, 270, 360]), ylim=[0, None])
141
+ """
149
142
  # Set the time
150
143
 
151
144
  if times is not None:
@@ -1,3 +1,4 @@
1
1
  from ._color import Color
2
- from ._decorator import set_figure
3
2
  from ._unit import Unit
3
+ from .plt_utils import *
4
+ from .sklearn_utils import *
@@ -9,63 +9,63 @@ __all__ = ['Color']
9
9
 
10
10
 
11
11
  class Color:
12
- color_cycle = cycler(color=['b', 'g', 'r', 'c', 'm', 'y', 'k'])
13
-
14
- linecolor = [{'line': '#1a56db', 'edge': '#0F50A6', 'face': '#5983D9'},
15
- {'line': '#046c4e', 'edge': '#1B591F', 'face': '#538C4A'},
16
- {'line': '#c81e1e', 'edge': '#f05252', 'face': '#f98080'}]
17
-
18
- # colors = ['#FF3333', '#33FF33', '#FFFF33', '#5555FF', '#B94FFF', '#AAAAAA', '#748690'] # the last one is "unknown"
19
-
20
- colors1 = ['#A65E58', '#A5BF6B', '#F2BF5E', '#3F83BF', '#B777C2', '#D1CFCB']
21
- colors2 = ['#A65E58', '#A5BF6B', '#F2BF5E', '#3F83BF', '#B777C2', '#D1CFCB', '#96c8e6']
22
- colors3 = ['#A65E58', '#A5BF6B', '#a6710d', '#F2BF5E', '#3F83BF', '#B777C2', '#D1CFCB', '#96c8e6'] # POC SOC
23
-
24
- colors_mutiWater = ['#A65E58', '#c18e8a', '#A5BF6B', '#c5d6a0', '#F2BF5E', '#3F83BF', '#c089ca', '#d3acda',
25
- '#D1CFCB']
26
- colors_mutiWater2 = ['#A65E58', '#96c8e6', '#A5BF6B', '#96c8e6', '#F2BF5E', '#3F83BF', '#c089ca', '#96c8e6',
27
- '#D1CFCB'] # water
28
-
29
- color_choose = {'Clean': ['#1d4a9f', '#84a7e9'],
30
- 'Transition': ['#4a9f1d', '#a7e984'],
31
- 'Event': ['#9f1d4a', '#e984a7']}
32
-
33
- paired = [plt.get_cmap('Paired')(i) for i in range(4)]
34
-
35
- @staticmethod
36
- def getColor(num: int = 6, cmap: str = 'jet_r'):
37
- category_colors = plt.colormaps[cmap](np.linspace(0.1, 0.9, num))
38
- return [plc.to_hex(category_colors[i]) for i in range(num)]
39
-
40
- @staticmethod
41
- def palplot(*args, **kwargs):
42
- sns.palplot(*args, **kwargs)
43
-
44
- @staticmethod
45
- def adjust_opacity(colors: str | list[str], alpha: float):
46
- if isinstance(colors, str):
47
- colors = [colors]
48
-
49
- adjusted_colors = []
50
- for color in colors:
51
- # 將顏色轉換為RGB表示
52
- r, g, b = int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16)
53
- # 調整透明度
54
- r_new = int(alpha * r + (1 - alpha) * 255)
55
- g_new = int(alpha * g + (1 - alpha) * 255)
56
- b_new = int(alpha * b + (1 - alpha) * 255)
57
- # 轉換為新的色碼
58
- new_color = '#{:02X}{:02X}{:02X}'.format(r_new, g_new, b_new)
59
- adjusted_colors.append(new_color)
60
- return adjusted_colors
61
-
62
- @staticmethod
63
- def color_maker(obj, cmap='Blues'):
64
- colors = np.nan_to_num(obj, nan=0)
65
- scalar_map = plt.cm.ScalarMappable(cmap=colormaps[cmap]) # create a scalar map for the colorbar
66
- scalar_map.set_array(colors)
67
- return scalar_map, colors
12
+ color_cycle = cycler(color=['b', 'g', 'r', 'c', 'm', 'y', 'k'])
13
+
14
+ linecolor = [{'line': '#1a56db', 'edge': '#0F50A6', 'face': '#5983D9'},
15
+ {'line': '#046c4e', 'edge': '#1B591F', 'face': '#538C4A'},
16
+ {'line': '#c81e1e', 'edge': '#f05252', 'face': '#f98080'}]
17
+
18
+ # colors = ['#FF3333', '#33FF33', '#FFFF33', '#5555FF', '#B94FFF', '#AAAAAA', '#748690'] # the last one is "unknown"
19
+
20
+ colors1 = ['#A65E58', '#A5BF6B', '#F2BF5E', '#3F83BF', '#B777C2', '#D1CFCB']
21
+ colors2 = ['#A65E58', '#A5BF6B', '#F2BF5E', '#3F83BF', '#B777C2', '#D1CFCB', '#96c8e6']
22
+ colors3 = ['#A65E58', '#A5BF6B', '#a6710d', '#F2BF5E', '#3F83BF', '#B777C2', '#D1CFCB', '#96c8e6'] # POC SOC
23
+
24
+ colors_mutiWater = ['#A65E58', '#c18e8a', '#A5BF6B', '#c5d6a0', '#F2BF5E', '#3F83BF', '#c089ca', '#d3acda',
25
+ '#D1CFCB']
26
+ colors_mutiWater2 = ['#A65E58', '#96c8e6', '#A5BF6B', '#96c8e6', '#F2BF5E', '#3F83BF', '#c089ca', '#96c8e6',
27
+ '#D1CFCB'] # water
28
+
29
+ color_choose = {'Clean': ['#1d4a9f', '#84a7e9'],
30
+ 'Transition': ['#4a9f1d', '#a7e984'],
31
+ 'Event': ['#9f1d4a', '#e984a7']}
32
+
33
+ paired = [plt.get_cmap('Paired')(i) for i in range(4)]
34
+
35
+ @staticmethod
36
+ def getColor(num: int = 6, cmap: str = 'jet_r'):
37
+ category_colors = plt.colormaps[cmap](np.linspace(0.1, 0.9, num))
38
+ return [plc.to_hex(category_colors[i]) for i in range(num)]
39
+
40
+ @staticmethod
41
+ def palplot(*args, **kwargs):
42
+ sns.palplot(*args, **kwargs)
43
+
44
+ @staticmethod
45
+ def adjust_opacity(colors: str | list[str], alpha: float):
46
+ if isinstance(colors, str):
47
+ colors = [colors]
48
+
49
+ adjusted_colors = []
50
+ for color in colors:
51
+ # 將顏色轉換為RGB表示
52
+ r, g, b = int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16)
53
+ # 調整透明度
54
+ r_new = int(alpha * r + (1 - alpha) * 255)
55
+ g_new = int(alpha * g + (1 - alpha) * 255)
56
+ b_new = int(alpha * b + (1 - alpha) * 255)
57
+ # 轉換為新的色碼
58
+ new_color = '#{:02X}{:02X}{:02X}'.format(r_new, g_new, b_new)
59
+ adjusted_colors.append(new_color)
60
+ return adjusted_colors
61
+
62
+ @staticmethod
63
+ def color_maker(obj, cmap='Blues'):
64
+ colors = np.nan_to_num(obj, nan=0)
65
+ scalar_map = plt.cm.ScalarMappable(cmap=colormaps[cmap]) # create a scalar map for the colorbar
66
+ scalar_map.set_array(colors)
67
+ return scalar_map, colors
68
68
 
69
69
 
70
70
  if __name__ == '__main__':
71
- Color.palplot(Color.colors2)
71
+ Color.palplot(Color.colors2)
@@ -5,51 +5,51 @@ __all__ = ['Unit']
5
5
 
6
6
 
7
7
  class Unit:
8
- file_path = Path(__file__).parent / 'units.json'
9
- data = None
10
-
11
- def __new__(cls, unit: str):
12
- cls.data = cls.load_jsonfile()
13
- try:
14
- value = cls.data[unit]
15
- return r'${}$'.format(value.replace(' ', r'\ '))
16
- except KeyError:
17
- print(f"Attribute '{unit}' not found. Using default value.")
18
- return r'${}$'.format(unit.replace(' ', r'\ ')) if unit is not None else 'None'
19
-
20
- @classmethod
21
- def load_jsonfile(cls):
22
- """ 讀取 JSON 檔中數據并將其變成屬性 """
23
- try:
24
- with open(cls.file_path, 'r', encoding='utf-8') as f:
25
- return json.load(f)
26
-
27
- except FileNotFoundError:
28
- print(f"JSON file '{cls.file_path}' not found.")
29
- except json.JSONDecodeError:
30
- print(f"Invalid JSON format in '{cls.file_path}'.")
31
-
32
- @classmethod
33
- def update_jsonfile(cls, key, value):
34
- """ 更新JSON檔 """
35
- with open(cls.file_path, 'r', encoding='utf-8') as f:
36
- old_data = json.load(f)
37
-
38
- old_data[key] = value
39
-
40
- with open(cls.file_path, 'w', encoding='utf-8') as f:
41
- json.dump(old_data, f, indent=4)
42
-
43
- @classmethod
44
- def del_jsonfile(cls, key):
45
- """ 更新JSON檔 """
46
- with open(cls.file_path, 'r', encoding='utf-8') as f:
47
- old_data = json.load(f)
48
-
49
- if key in old_data:
50
- del old_data[key]
51
-
52
- with open(cls.file_path, 'w', encoding='utf-8') as f:
53
- json.dump(old_data, f, indent=4)
54
- else:
55
- print(f"Key '{key}' not found.")
8
+ file_path = Path(__file__).parent / 'units.json'
9
+ data = None
10
+
11
+ def __new__(cls, unit: str):
12
+ cls.data = cls.load_jsonfile()
13
+ try:
14
+ value = cls.data[unit]
15
+ return r'${}$'.format(value.replace(' ', r'\ '))
16
+ except KeyError:
17
+ print(f"Attribute '{unit}' not found. Using default value.")
18
+ return r'${}$'.format(unit.replace(' ', r'\ ')) if unit is not None else 'None'
19
+
20
+ @classmethod
21
+ def load_jsonfile(cls):
22
+ """ 讀取 JSON 檔中數據并將其變成屬性 """
23
+ try:
24
+ with open(cls.file_path, 'r', encoding='utf-8') as f:
25
+ return json.load(f)
26
+
27
+ except FileNotFoundError:
28
+ print(f"JSON file '{cls.file_path}' not found.")
29
+ except json.JSONDecodeError:
30
+ print(f"Invalid JSON format in '{cls.file_path}'.")
31
+
32
+ @classmethod
33
+ def update_jsonfile(cls, key, value):
34
+ """ 更新JSON檔 """
35
+ with open(cls.file_path, 'r', encoding='utf-8') as f:
36
+ old_data = json.load(f)
37
+
38
+ old_data[key] = value
39
+
40
+ with open(cls.file_path, 'w', encoding='utf-8') as f:
41
+ json.dump(old_data, f, indent=4)
42
+
43
+ @classmethod
44
+ def del_jsonfile(cls, key):
45
+ """ 更新JSON檔 """
46
+ with open(cls.file_path, 'r', encoding='utf-8') as f:
47
+ old_data = json.load(f)
48
+
49
+ if key in old_data:
50
+ del old_data[key]
51
+
52
+ with open(cls.file_path, 'w', encoding='utf-8') as f:
53
+ json.dump(old_data, f, indent=4)
54
+ else:
55
+ print(f"Key '{key}' not found.")