ncepst-exceltools 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.
- exceltools/BatchModifyCharts.py +231 -0
- exceltools/ModifyChart.py +992 -0
- exceltools/README_PYPI.md +578 -0
- exceltools/ScatterChart.py +719 -0
- exceltools/__init__.py +4 -0
- exceltools/create_sheet_index.py +99 -0
- ncepst_exceltools-0.1.0.dist-info/METADATA +598 -0
- ncepst_exceltools-0.1.0.dist-info/RECORD +11 -0
- ncepst_exceltools-0.1.0.dist-info/WHEEL +5 -0
- ncepst_exceltools-0.1.0.dist-info/licenses/LICENSE +21 -0
- ncepst_exceltools-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""複数の埋め込みグラフに ModifyChart の設定を適用します。"""
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from inspect import signature
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Literal
|
|
6
|
+
|
|
7
|
+
from .ModifyChart import ModifyChart
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def BatchModifyCharts(
|
|
11
|
+
target: Literal["sheet", "book", "selected", "dir"] = "sheet",
|
|
12
|
+
*,
|
|
13
|
+
ws: Any = None,
|
|
14
|
+
wb: Any = None,
|
|
15
|
+
directory: str | Path | None = None,
|
|
16
|
+
recursive: bool = False,
|
|
17
|
+
preset: Literal["excel2021", "std", "no_grid", "grid", "no_change"] = "std", # プリセットスタイル名
|
|
18
|
+
width_cm = None, # グラフ幅(cm), Noneで変更なし
|
|
19
|
+
height_cm = None, # グラフ高さ(cm), Noneで変更なし
|
|
20
|
+
name = None, # グラフ名変更, Noneで変更なし
|
|
21
|
+
title: Literal[None, False, "タイトル"] = None, # タイトル文字列, Falseで無効化, Noneで変更なし
|
|
22
|
+
title_font_color = None, # タイトルフォント色(RGB)
|
|
23
|
+
title_font_size = None, # タイトルフォントサイズ
|
|
24
|
+
title_space = +0, # タイトルとグラフの間隔(pt)
|
|
25
|
+
NS: int | None = None, # データ系列数。Noneで各グラフから自動取得
|
|
26
|
+
series_list: list[dict]|None = None, # 各系列の設定
|
|
27
|
+
style: Literal[None, "line+marker", "line", "marker", "dash", "dash+marker", "chain"] = None, # 線+マーカーのスタイル
|
|
28
|
+
smooth: bool = None, # Trueで曲線、Falseで折れ線
|
|
29
|
+
marker: Literal["C", "S", "D", "T", "N"] = None, # マーカー種類: "C":●, "S":■, "D":◆, "T":▲, "N":なし
|
|
30
|
+
alpha = None, # 線の透明度(0~1)
|
|
31
|
+
x_title: Literal[None, False, "X軸タイトル"] = None, # X軸タイトル文字列。Falseで無効化、Noneで変更なし
|
|
32
|
+
x_title_space = +0, # プロットエリアを下側に広げる場合はマイナス
|
|
33
|
+
x_min: float|str|None = None, # X軸最小値, "auto"で自動調整, Noneで変更なし
|
|
34
|
+
x_max: float|str|None = None, # X軸最大値, "auto"で自動調整, Noneで変更なし
|
|
35
|
+
x_major: float|None = None, # X軸主目盛間隔, Noneで変更なし, グリッド線表示設定はPRESET
|
|
36
|
+
x_minor: float|None = None, # X軸副目盛間隔, Noneで変更なし, グリッド線表示設定はPRESET
|
|
37
|
+
x_cross = None, # Y軸との交差位置, Noneで変更なし
|
|
38
|
+
x_format: Literal[None, "0", "0.0", "0.00", "0.0E+00", "0%", "#,##0"] = None, # X軸表示形式 ("0.00", "0.0E+00", "0%" など), Noneで変更なし
|
|
39
|
+
x_log: Literal[None, True] = None, # Trueで対数表示, Noneで変更なし
|
|
40
|
+
y_title: Literal[None, False, "Y軸タイトル"] = None, # Y軸タイトル, Noneで変更なし
|
|
41
|
+
y_title_space = +0,
|
|
42
|
+
y_min: float|str|None = None,
|
|
43
|
+
y_max: float|str|None = None,
|
|
44
|
+
y_major: float|None = None,
|
|
45
|
+
y_minor: float|None = None,
|
|
46
|
+
y_cross = None, # X軸との交差位置, Noneで変更なし
|
|
47
|
+
y_format: Literal[None, "0", "0.0", "0.00", "0.0E+00", "0%", "#,##0"] = None,
|
|
48
|
+
y_log: Literal[None, True] = None,
|
|
49
|
+
y2_title: Literal[None, False, "副軸タイトル"] = None, # Y軸タイトル文字列, Falseで無効化, Noneで変更なし
|
|
50
|
+
y2_min: float|str|None = None,
|
|
51
|
+
y2_max: float|str|None = None,
|
|
52
|
+
y2_major: float|None = None,
|
|
53
|
+
y2_minor: float|None = None,
|
|
54
|
+
y2_format: Literal[None, "0", "0.0", "0.00", "0.0E+00", "0%", "#,##0"] = None,
|
|
55
|
+
y2_log: Literal[None, True] = None,
|
|
56
|
+
frame_color: Literal[None, False, 0] = None, # グラフ枠色 (False:枠なし, 0:黒枠, Noneでpreset)
|
|
57
|
+
legend: Literal[False, None, "right", "TR+bw+fb", "TC+bw+fb", "TL+bw+fb", "BL+bw+fb", "BC+bw+fb", "BR+bw+fb", "TR", "TL", ""] = None, # 凡例表示(False:非表示, Noneで変更なし, "right"で右側に表示)
|
|
58
|
+
legend_font_size = None, # 凡例のフォントサイズ, Noneで変更なし
|
|
59
|
+
legend_width_inc = 0, # 凡例ボックスの幅増減(pt)
|
|
60
|
+
legend_height_inc = 0, # 凡例ボックスの高さ増減(pt)
|
|
61
|
+
legend_right_space = 0, # 凡例の右端 = プロットエリアの右端を基準とした凡例位置制御
|
|
62
|
+
legent_top_space = 0, # 凡例の上端 = プロットエリアの上端を基準とした凡例位置制御
|
|
63
|
+
transparent_bg: bool|None = None, # 背景を透明化する場合はTrue
|
|
64
|
+
chart_type: Literal[None, "bar"] = None, # "bar"で棒グラフに変更
|
|
65
|
+
x_bold_line: float|None = None, # x_bold_line=0でx=0が太線
|
|
66
|
+
y_bold_line: float|None = None, # y_bold_line=0でy=0が太線
|
|
67
|
+
plot_area_space: Literal["relative", "absolute"] = "relative", # プロットエリア調整時の基準位置を"absolute"/"relative"で指定
|
|
68
|
+
width_inc = 0, # プロットエリアの幅増減(pt)
|
|
69
|
+
height_inc = 0, # プロットエリアの高さ増減(pt)
|
|
70
|
+
right_space = 0, # plot_area_space="abs"のときの右のスペース指定
|
|
71
|
+
) -> list[Any]:
|
|
72
|
+
"""シート・ブック内、または選択中のグラフを一括変更します。
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
target : {"sheet", "book", "selected", "dir"}
|
|
77
|
+
"sheet": ws のグラフ、"book": wb の全ワークシートのグラフ。
|
|
78
|
+
"selected": アクティブなExcelで選択中のグラフのみ。
|
|
79
|
+
Ctrlを押しながらグラフの外枠をクリックして複数選択してください。
|
|
80
|
+
このモードでは ws・wb を指定できません。
|
|
81
|
+
省略した対象は、アクティブなブック・シートから取得します。
|
|
82
|
+
ws : xlwings.Sheet, optional
|
|
83
|
+
対象シート。target="book" では指定できません。
|
|
84
|
+
wb : xlwings.Book, optional
|
|
85
|
+
対象ブック。ws と同時には指定できません。
|
|
86
|
+
directory : str or pathlib.Path, optional
|
|
87
|
+
target="dir" の対象フォルダ。xlsx/xlsm/xlsb/xls を処理し、上書き保存します。
|
|
88
|
+
Excelの一時ファイル(~$で始まる名前)は除外します。
|
|
89
|
+
対象一覧を表示し、yes入力時のみ実行します。それ以外は空リストを返します。
|
|
90
|
+
recursive : bool, default False
|
|
91
|
+
Trueでサブフォルダも対象にします。target="dir" 専用です。
|
|
92
|
+
書式設定引数
|
|
93
|
+
ModifyChart と共通の設定引数(preset、width_cm、title_font_size など)。
|
|
94
|
+
NS の省略時は各グラフの現在の系列数を使用します。
|
|
95
|
+
系列のデータ範囲指定に使う ws は、各グラフの所属シートになります。
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
list
|
|
100
|
+
通常は処理した xlwings.Chart のリスト。グラフがなければ空リスト。
|
|
101
|
+
target="dir" はグラフを処理・保存したファイルの絶対パス(Path)のリスト。
|
|
102
|
+
|
|
103
|
+
Notes
|
|
104
|
+
-----
|
|
105
|
+
ModifyChart と同じく、主に Windows Excel の散布図が対象です。
|
|
106
|
+
独立したグラフシートは対象外です。dirモードのみ上書き保存します。
|
|
107
|
+
dirモードは専用のExcelを起動し、マクロ・イベント・リンク更新を無効にします。
|
|
108
|
+
エラー時は現在のファイルを保存せず閉じ、停止します。先に保存したファイルは残ります。
|
|
109
|
+
例外が発生した時点で停止します。先に適用した変更は元に戻りません。
|
|
110
|
+
ModifyChart 内部で捕捉されるエラーの扱いは、元の関数と同じです。
|
|
111
|
+
"""
|
|
112
|
+
# 公開引数を既存の一括処理へ渡す設定辞書にまとめる。
|
|
113
|
+
kwargs = locals().copy()
|
|
114
|
+
for key in ("target", "ws", "wb", "directory", "recursive"):
|
|
115
|
+
kwargs.pop(key)
|
|
116
|
+
if NS is None:
|
|
117
|
+
kwargs.pop("NS")
|
|
118
|
+
|
|
119
|
+
if target not in ("sheet", "book", "selected", "dir"):
|
|
120
|
+
raise ValueError('target は "sheet", "book", "selected", "dir" のいずれかを指定してください。')
|
|
121
|
+
if target == "dir":
|
|
122
|
+
if ws is not None or wb is not None:
|
|
123
|
+
raise ValueError('target="dir" では ws・wb を指定できません。')
|
|
124
|
+
if directory is None:
|
|
125
|
+
raise ValueError('target="dir" では directory を指定してください。')
|
|
126
|
+
elif directory is not None or recursive:
|
|
127
|
+
raise ValueError('directory・recursive は target="dir" 専用です。')
|
|
128
|
+
if target == "selected" and (ws is not None or wb is not None):
|
|
129
|
+
raise ValueError('target="selected" では ws・wb を指定できません。')
|
|
130
|
+
if ws is not None and wb is not None:
|
|
131
|
+
raise ValueError("ws と wb は同時に指定できません。")
|
|
132
|
+
if target == "book" and ws is not None:
|
|
133
|
+
raise ValueError('target="book" では wb を指定してください。')
|
|
134
|
+
if "chart" in kwargs:
|
|
135
|
+
raise TypeError("chart は指定できません。対象は target で指定してください。")
|
|
136
|
+
# 引数名の誤りは、Excelを操作する前に検出する。
|
|
137
|
+
signature(ModifyChart).bind(chart=None, ws=None, **kwargs)
|
|
138
|
+
|
|
139
|
+
if target == "dir":
|
|
140
|
+
folder = Path(directory).expanduser().resolve()
|
|
141
|
+
if not folder.is_dir():
|
|
142
|
+
raise NotADirectoryError(f"フォルダが見つかりません: {folder}")
|
|
143
|
+
candidates = folder.rglob("*") if recursive else folder.iterdir()
|
|
144
|
+
files = sorted(
|
|
145
|
+
(p for p in candidates if p.is_file()
|
|
146
|
+
and p.suffix.lower() in {".xlsx", ".xlsm", ".xlsb", ".xls"}
|
|
147
|
+
and not p.name.startswith("~$")),
|
|
148
|
+
key=lambda p: str(p).lower(),
|
|
149
|
+
)
|
|
150
|
+
if not files:
|
|
151
|
+
print("対象のExcelファイルがありません。")
|
|
152
|
+
return []
|
|
153
|
+
print(f"対象ファイル({len(files)}件・上書き保存):")
|
|
154
|
+
for index, path in enumerate(files, start=1):
|
|
155
|
+
print(f" {index}. {path}")
|
|
156
|
+
ans = input("\n上記ファイルの全てにグラフの書式設定を適用しますか?[yes/N] : ")
|
|
157
|
+
if ans.strip().lower() != "yes":
|
|
158
|
+
print("処理を中止しました。")
|
|
159
|
+
return []
|
|
160
|
+
import xlwings as xw
|
|
161
|
+
saved = []
|
|
162
|
+
with xw.App(visible=False, add_book=False) as app:
|
|
163
|
+
app.display_alerts = False
|
|
164
|
+
app.enable_events = False
|
|
165
|
+
app.api.AutomationSecurity = 3 # msoAutomationSecurityForceDisable
|
|
166
|
+
for path in files:
|
|
167
|
+
book = None
|
|
168
|
+
try:
|
|
169
|
+
book = app.books.open(str(path), update_links=False, read_only=False,
|
|
170
|
+
ignore_read_only_recommended=True)
|
|
171
|
+
if book.api.ReadOnly:
|
|
172
|
+
raise PermissionError(f"読み取り専用で開かれました: {path}")
|
|
173
|
+
charts = BatchModifyCharts(target="book", wb=book, **kwargs)
|
|
174
|
+
if charts:
|
|
175
|
+
book.save()
|
|
176
|
+
saved.append(path)
|
|
177
|
+
except Exception as exc:
|
|
178
|
+
raise RuntimeError(f"Excelファイルの処理に失敗しました: {path}") from exc
|
|
179
|
+
finally:
|
|
180
|
+
if book is not None:
|
|
181
|
+
book.close()
|
|
182
|
+
return saved
|
|
183
|
+
|
|
184
|
+
if target == "selected":
|
|
185
|
+
import xlwings as xw
|
|
186
|
+
app = xw.apps.active
|
|
187
|
+
if app is None or app.books.active is None:
|
|
188
|
+
raise RuntimeError("アクティブなExcelブックがありません。")
|
|
189
|
+
sheet = app.books.active.sheets.active
|
|
190
|
+
try:
|
|
191
|
+
shapes = app.api.Selection.ShapeRange
|
|
192
|
+
except Exception as exc:
|
|
193
|
+
raise ValueError(
|
|
194
|
+
"グラフの外枠を選択してください。複数選択はCtrlを押しながらクリックします。"
|
|
195
|
+
) from exc
|
|
196
|
+
# ModifyChart による選択解除・名前変更の前に対象を固定する。
|
|
197
|
+
names = [
|
|
198
|
+
shapes.Item(i).Name
|
|
199
|
+
for i in range(1, shapes.Count + 1)
|
|
200
|
+
if shapes.Item(i).HasChart == -1
|
|
201
|
+
]
|
|
202
|
+
jobs = [(sheet, sheet.charts[name]) for name in names]
|
|
203
|
+
|
|
204
|
+
else: # "sheet", "book" の場合
|
|
205
|
+
if ws is not None:
|
|
206
|
+
sheets = [ws]
|
|
207
|
+
else:
|
|
208
|
+
if wb is None:
|
|
209
|
+
import xlwings as xw
|
|
210
|
+
wb = xw.books.active
|
|
211
|
+
if wb is None:
|
|
212
|
+
raise RuntimeError("アクティブなExcelブックがありません。")
|
|
213
|
+
if target == "sheet":
|
|
214
|
+
sheets = [wb.sheets.active]
|
|
215
|
+
elif target == "book":
|
|
216
|
+
sheets = list(wb.sheets)
|
|
217
|
+
else:
|
|
218
|
+
# 冒頭でも検証するが、未知の値をbook扱いにしない。
|
|
219
|
+
raise ValueError(f"不明なtargetです: {target!r}")
|
|
220
|
+
# 名前変更などでコレクションが変化しても、列挙対象を固定する。
|
|
221
|
+
jobs = [(sheet, chart) for sheet in sheets for chart in list(sheet.charts)]
|
|
222
|
+
modified = []
|
|
223
|
+
for sheet, chart in jobs:
|
|
224
|
+
options = deepcopy(kwargs)
|
|
225
|
+
if "NS" not in options:
|
|
226
|
+
options["NS"] = chart.api[1].SeriesCollection().Count
|
|
227
|
+
# ModifyChart が series_list を変更するため、グラフごとにコピーする。
|
|
228
|
+
ModifyChart(chart=chart, ws=sheet, **options)
|
|
229
|
+
modified.append(chart)
|
|
230
|
+
|
|
231
|
+
return modified
|