プロジェクト

全般

プロフィール

13章学習記録 » 履歴 » バージョン 2

Tatsuya ISHIGAKI, 2025/07/31 14:29

1 1 Tatsuya ISHIGAKI
# 第13章 特定のデータフォーマットを扱う
2
3
## CSV ファイルを扱う csv
4
CSV, TSV フォーマットのファイルの読み取り、書き込みを行う機能
5
6
- CSV ファイルの読み込みと書き込み
7
  
8
  |関数名|解説|戻り値|
9
  |---|---|---|
10
  |`reader(csvfile, dialect='excel', **fmtparams)`|CSV ファイルの各行を反復処理するような `reader` オブジェクトを返す|`reader` オブジェクト|
11
  |`writer(csvfile, dialect='excel', **fmtparams)`|CSV ファイルのデータを指定方法で書き込むための `writer` オブジェクトを返す|`writer` オブジェクト|
12
13
  - `csvfile` には、イテレータープロトコルをサポートするオブジェクトを指定
14
  - `dialect` には、以下の **書式化パラメーターセット** 、または `Dialect` サブクラスのインスタンスを指定できる
15
    - `excel` Excel で出力される CSV ファイル
16
    - `excel-tab` Excel で出力される TSV ファイル
17
    - `unix` 終端記号を `\n` とするファイル
18
19
      <br>書式化パラメーターセットによる、各書式化パラメーターのデフォルト値
20
      |パラメーター<br>セット|delimiter|quatechar|skipinitialspace|lineterminator|
21
      |---|---|---|---|---|
22
      |`excel`|`,`|`"`|False|`\r\n`|
23
      |`excel-tab`|`\t`|`"`|False|`\r\n`|
24
      |`unix`|`,`|`"`|False|`\n`|
25
26
      <br>`Dialect` クラスの主な属性
27
      |属性|デフォルト|解説|
28
      |---|---|---|
29
      |`delimiter`|`,`|区切り文字 (1文字からなる文字列)|
30
      |`quotechar`|`"`|引用符文字|
31
      |`skipinitialspace`|False|Trueの場合、`delimiter` の直後に続く空白は無視される|
32
      |`lineterminator`|`\r\n`|`writer` が使用する、各行の終わりを表す文字列|
33
34
  - `reader` オブジェクトで CSV 読み込み
35
36
      ```
37
      "id","都道府県","人口(人)","面積(km2)"
38
      "1","東京都","13900000","2194.05"
39
      "2","神奈川県","9200000","2416.10"
40
      "3","千葉県","6200000","5157.50"
41
      "4","埼玉県","7300000","3797.75"
42
      ```
43
44
      ```python
45
      >>> import csv
46
      >>> with open("01_sample.csv", mode="r", encoding="utf-8") as f:
47
      ...     reader = csv.reader(f)
48
      ...     for row in reader:
49
      ...         print(row)
50
      ...
51
      ['id', '都道府県', '人口(人)', '面積(km2)']
52
      ['1', '東京都', '13900000', '2194.05']
53
      ['2', '神奈川県', '9200000', '2416.10']
54
      ['3', '千葉県', '6200000', '5157.50']
55
      ['4', '埼玉県', '7300000', '3797.75']
56
      ```
57
58
      ```python
59
      >>> dialect = reader.dialect
60
      >>> dialect.quotechar
61
      '"'
62
      >>> dialect.lineterminator
63
      '\r\n'
64
      >>> dialect.doublequote
65
      True
66
      >>> dialect.skipinitialspace
67
      False
68
      >>> dialect.delimiter
69
      ','
70
      ```
71
72
  - `writer` オブジェクトで CSV 書き込み
73
74
    |メソッド名|解説|
75
    |---|---|
76
    |`writerow(row)`|データを書式化し、`writer` のファイルオブジェクトへ書き込む<br>`row` には文字列か数値のイテラブルを指定|
77
    |`writerows(rows)`|複数行を書き込む<br>`rows` には `writerow()` の `row` と同様のオブジェクトのイテラブルを指定|
78
79
    ```python
80
    >>> with open("writetest.tsv", mode="w", encoding="utf-8") as f:
81
    ...     writer = csv.writer(f, dialect="excel-tab")
82
    ...     for i in range(5):
83
    ...         writer.writerow([i, "x", i, "=", i**2])
84
    ...
85
    11
86
    11
87
    11
88
    11
89
    12
90
    ```
91
92
    ```
93
    0	x	0	=	0
94
    1	x	1	=	1
95
    2	x	2	=	4
96
    3	x	3	=	9
97
    4	x	4	=	16
98
    ```
99
100
  - 辞書データを用いた CSV ファイルの読み込みと書き込み
101
    - class `DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwargs)`
102
      - `f` イテレータープロトコルをサポートするオブジェクト
103
      - `fieldnames` 辞書のキーをシーケンスで指定 (未指定の場合は `f` の最初の行の値が使用される)
104
      - `restkey` `restval` 実際に読み込んだデータが、フィールド数 (`fieldnames` または `f` の1行目) と不一致である場合に使用される値
105
        - 実データのフィールド数が多い場合、残りの列の値はリストとしてまとめられて `restkey` キーの値となる
106
        - 実データのフィールド数が少ない場合、足りない値は `restval` によって埋められる
107
      - `dialect` (略)
108
      - **戻り値** `DictReader` オブジェクト
109
    - class `DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwargs)`
110
      - `f` (略)
111
      - `fieldnames` 書き込み時に渡される辞書の値をどの順でファイルへ書き出すかをシーケンスで指定
112
      - `restval` fieldnames に指定のキーが書き込みデータに存在しない場合に値として使用する文字列を指定
113
      - `extrasaction` fieldnames に存在しないキーが書き込みデータに存在する場合の動作
114
        - `raise` ValueError 送出
115
        - `ignore` 無視される
116
      - `dialect` (略)
117
      - **戻り値** `DictWriter` オブジェクト
118
119
      ```python
120
      >>> import csv
121
      >>> with open('01_sample.csv', mode='r', encoding='utf-8') as f:
122
      ...     for row in csv.DictReader(f):
123
      ...          print(row)
124
      ...
125
      {'id': '1', '都道府県': '東京都', '人口(人)': '13900000', '面積(km2)': '2194.05'}
126
      {'id': '2', '都道府県': '神奈川県', '人口(人)': '9200000', '面積(km2)': '2416.10'}
127
      {'id': '3', '都道府県': '千葉県', '人口(人)': '6200000', '面積(km2)': '5157.50'}
128
      {'id': '4', '都道府県': '埼玉県', '人口(人)': '7300000', '面積(km2)': '3797.75'}
129
      ```
130
131
    - `DictWriter` には、ヘッダーを書き込むメソッド `writeheader(row)` がある
132
      ```python
133
      import csv
134
      
135
      data = [
136
          {'都道府県': '東京都', '人口密度(人/km2)': 6335},
137
          {'都道府県': '神奈川県', '人口密度(人/km2)': 3807},
138
          {'都道府県': '千葉県', '人口密度(人/km2)': 1202},
139
      ]
140
      
141
      with open('result.csv', newline='', mode='w', encoding='utf-8') as write_file:
142
          fieldnames = ['都道府県', '人口密度(人/km2)']  # ヘッダーの要素順を指定する
143
          writer = csv.DictWriter(write_file, fieldnames=fieldnames)
144
          writer.writeheader()  # DictWriterのメソッドwriteheaderを使用してヘッダー行を書き込み
145
          writer.writerows(data)  # データの一括書き込み
146
      ```
147
148
- Dialect を推測して生成する Sniffer クラス
149
150
  |クラスメソッド名|解説|戻り値|
151
  |---|---|---|
152
  |`sniff(sample, delimiters=None)`|`sample` のデータを解析し、推測結果を返す|`Dialect` サブクラス|
153
  |`has_header(sample)`|ヘッダーの有無を判定する|bool|
154
155
## 13.2 JSON を扱う json
156
JSON フォーマットを扱うための機能
157
158
- JSON のエンコードとデコード
159
  - 関数 `dump(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)`
160
    - `obj` エンコード対象オブジェクト
161
    - `skipkeys` True の場合、辞書キーに `str` `int` `float` `bool` `None` 以外を指定しても TypeError を送出しない
162
    - `ensure_ascii` True の場合、非 ascii 文字列はエスケープされる (日本語などをそのまま出力したい場合は False にする)
163
    - `check_circular` True の場合、リストや辞書での循環参照がチェックされ無限再帰を防ぐ (False で循環参照が見つかると RecursionError)
164
    - `allow_nan` False の場合、許容範囲外 float (nan, inf, -inf) を検出すると ValueError
165
    - `cls` カスタマイズした `JSONEncoder` サブクラスを使用する場合に指定
166
    - `indent` インデントのスペース数を整数指定
167
    - `separators` セパレーター文字を `(item_separator, key_separator)` のタプルで指定
168
    - `default` シリアライズできないオブジェクトに対して呼び出す関数を指定
169
    - `sort_keys` True の場合、キーでソートされる
170
    - **戻り値** JSON 形式の str
171
172
    ```python
173
    >>> import json
174
    >>> dbinfo = [{"db1": {"id": "user1", "pw": "pass1", "failover": True, "host": [{"ip": "192.168.0.1", "port": 8021},{"i\p": "192.168.0.2", "port": 8021}]}}, {"db2": {"id": "user2", "pw": "pass2", "failover": False, "host": [{"ip": "192.168\.0.3", "port": 8021}]}}]
175
    >>> print(json.dumps(dbinfo, indent=4))
176
    [
177
        {
178
            "db1": {
179
                "id": "user1",
180
                "pw": "pass1",
181
                "failover": true,
182
                "host": [
183
                    {
184
                        "ip": "192.168.0.1",
185
                        "port": 8021
186
                    },
187
                    {
188
                        "ip": "192.168.0.2",
189
                        "port": 8021
190
                    }
191
                ]
192
            }
193
        },
194
        {
195
            "db2": {
196
                "id": "user2",
197
                "pw": "pass2",
198
                "failover": false,
199
                "host": [
200
                    {
201
                        "ip": "192.168.0.3",
202
                        "port": 8021
203
                    }
204
                ]
205
            }
206
        }
207
    ]
208
    ```
209
210
  - 関数 `loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)`
211
    - `s` デコード対象のオブジェクト (str, bytes, bytearray)
212
    - `cls` カスタマイズした `JSONDecoder` サブクラスを使用する場合に指定
213
    - `object_hook` オブジェクトリテラルがデコードされた結果に対して呼ばれる関数を指定 (デコード結果が関数戻り値に置換される)
214
    - `parse_float` JSON に含まれる浮動小数点数 (文字列) を扱う関数を指定 (None なら `float()` が使用される)
215
    - `parse_int` JSON に含まれる整数 (文字列) を扱う関数を指定 (None なら `int()` が使用される)
216
    - `parse_constant` JSON に含まれる `'-Infinity'` `'Infinity'` `'NaN'` を扱う関数を指定
217
    - `object_pairs_hook` ペアの順序付きリストのデコード結果に対して呼ばれる関数を指定 (`object_hook` より優先される)
218
    - **戻り値** Python オブジェクト
219
220
    ```python
221
    >>> jsonstr = '[{"name": "smith", "age": 41, "height": 167.5}, {"name": "sabakan", "age": 3}]'
222
    >>> pyobj = json.loads(jsonstr)
223
    >>> pyobj
224
    [{'name': 'smith', 'age': 41, 'height': 167.5}, {'name': 'sabakan', 'age': 3}]
225
    >>> type(pyobj)
226
    <class 'list'>
227
    >>> type(pyobj[0])
228
    <class 'dict'>
229
    >>> pyobj[0]
230
    {'name': 'smith', 'age': 41, 'height': 167.5}
231
    ```
232
233
  <br>エンコード変換表
234
  |Python|→|JSON|
235
  |---|---|---|
236
  |辞書||オブジェクト|
237
  |リスト、タプル||配列|
238
  |文字列||文字列|
239
  |整数、浮動小数点数、<br>intやfloatの派生列挙型||数値|
240
  |True||true|
241
  |False|||
242
  ||||
243
244
  <br>デコード変換表
245
  |JSON|→|Python|
246
  |---|---|---|
247
  |オブジェクト||辞書|
248
  |配列||リスト|
249
  |文字列||文字列|
250
  |数値||整数、浮動小数点数|
251
  |true||True|
252
  |false||False|
253
  |null||None|
254
255
- JSON のエンコードとデコード (ファイルオブジェクト)
256
  - 関数 `dump(obj, fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)`
257
    - `fp` 書き込み先ファイルオブジェクト
258
    - **戻り値** None
259
  - 関数 `load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)`
260
    - `fp` 読み込み元ファイルオブジェクト
261
    - **戻り値** Python オブジェクト
262
263
- JSON のコマンドラインインターフェースを提供している json.tool
264
  - JSON 文字列 (`curl で受け取ったレスポンスなど) を渡すだけで整形できる
265
  - `python -m json.tool -h` でヘルプ
266
267
## 13.3 INI ファイルを扱う configparser
268
Windows OS で設定ファイルとして多く使用される INI ファイル (他の場所でも多く使用されている) 、および INI ファイルに似た構造の設定ファイルを扱う
269
270
- サポートされる INI ファイルの構造 ([webドキュメントより](https://docs.python.org/ja/3.13/library/configparser.html#supported-ini-file-structure))
271
  - 各セクションは `[セクション名]` で始まる領域
272
    - デフォルトではセクション名は改行を含まない任意の文字列
273
    - セクション名は大文字小文字が区別される
274
  - セクション内には、指定文字列 (デフォルトでは、 `=` および `:`) を使った キー/値 要素が並ぶ
275
    - キー、値はすべて文字列として扱われるが、取得時に変換もするメソッドが用意されている
276
      - `getboolean()` `getint()` `getfloat()`
277
    - キーは大文字小文字が区別されず、すべて小文字として扱われる (書き込み時も小文字)
278
  - キー、値の前後の空白は基本的に除去される
279
  - 値は複数行に渡って記述でき、その場合は2行目以降を1行目よりインデントさせる
280
  - コメントは行頭に特定文字 (デフォルトでは、`#` および `;`) を付けた行全体 (インデントも可能)
281
  - 最初のセクション名は省略可能で、その場合は読み込み時にオプション `allow_unnamed_section=True` とすることで、無名セクションを扱える
282
    - 無名セクションへは、セクション名の代わりに `configparser.UNNAMED_SECTION` を使用してアクセスする
283
284
- INI ファイルを読み込む
285
286
  ConfigParser インスタンスのメソッド
287
  |メソッド|解説|戻り値|
288
  |---|---|---|
289
  |`read_string(string)`|指定文字列を INI フォーマットとして解析する|None|
290
  |`read(filenames, encoding=None)`|指定した INI ファイルを読み込む<br>`filenames` にはリストで複数渡せる|list (解析できたファイル名)|
291
  |`sections()`|読み込んだ INI 内のセクション名一覧を返す|list (セクション名)|
292
  |`options(section)`|指定セクションのキー一覧を返す|list (キー)|
293
294
  - DEFAULT セクション
295
    - 特定セクションの存在しないキーを参照した場合、DEFAULT セクションのキーを参照して値が返される
296
297
- INI ファイルの高度な利用 (値の補完)
298
  - INI ファイル内の他の場所に記載した内容を再利用 (値の補完 = interpolation) する
299
  - 値の補完方法クラスをコンストラクタに指定することで行う (クラスは configparser モジュール内)
300
    - `ConfigParser(interpolation=BasicInterpolation)` (指定しない場合と同じ)
301
    - `ConfigParser(interpolation=ExtendedInterpolation)`
302
303
    <br>**BasicInterpolation** (セクション内の値補完. `%(キー)s` で参照する)
304
      ```
305
      [USER_A]
306
      home_dir = /home/user_a
307
      mail_dir = %(home_dir)s/mail
308
      group = Developer
309
      ``` 
310
311
      ```python
312
      >>> config = ConfigParser()
313
      >>> config.read('config_interp.ini')
314
      ['config_interp.ini']
315
      >>> config['USER_A']['mail_dir']
316
      '/home/user_a/mail'
317
      ```
318
    
319
    <br>**ExtendedInterpolation** (セクション外も補完可能: `${キー}` `${セクション名:キー}` で参照する)
320
      ```
321
      [USER_A]
322
      home_dir = /home/user_a
323
      mail_dir = ${home_dir}/mail
324
      group = Developer
325
      
326
      [USER_B]
327
      group = ${USER_A:group}
328
      ```
329
330
      ```python
331
      >>> from configparser import ConfigParser, ExtendedInterpolation
332
      >>> config = ConfigParser(interpolation=ExtendedInterpolation())
333
      >>> config.read('config_exinterp.ini')
334
      ['config_exinterp.ini']
335
      >>> config['USER_B']['group']
336
      'Developer'
337
      ```
338
339
## 13.4 YAML を扱う PyYAML
340
341
- YAML ファイルの読み込み
342
  
343
  |関数名|解説|戻り値|
344
  |---|---|---|
345
  |`load(stream, Loader)`|YAML で記述されたファイルを読み込む|Python オブジェクト|
346
  |`load_all(stream, Loader)`|「---」で区切られた YAML で記述されたファイルを読み込む|Python オブジェクト (generator)|
347
  |`safe_load(stream)`|`load()` に `Loader=yaml.SafeLoader` を指定したもの|Python オブジェクト|
348
  |`safe_load_all()`|`load_all()` に `Loader=yaml.SafeLoader` を指定したもの|Python オブジェクト (generator)|
349
350
  - 関数の引数 `Loader` に指定できるもの
351
  
352
    |Loader|解説|
353
    |---|---|
354
    |`BaseLoader`|基本的な YAML のみをロードする<br>すべてのスカラーは文字列としてロードされる|
355
    |`SafeLoader`|YAML のサブセットを安全にロードする|
356
    |`FullLoader`|基本的に YAML の全機能を受け入れるが、任意コード実行は一部制限 (デフォルト Loader)|
357
    |`UnsafeLoader`|YAML の全機能を使用可能で、任意コード実行もできる|
358
  
359
  - YAML でキー `!!python/object:` を指定して記載すると、任意の Python オブジェクトが生成可能
360
    - 生成オブジェクトから処理を実行可能
361
    - この機能への対応が、Loader によって制御されている
362
363
  <br>**単独ドキュメント**
364
  ```
365
  ---
366
  database:
367
      host: localhost
368
      port: 3306
369
      db: test
370
      user: test
371
  smtp_host: localhost
372
  ```
373
374
  ```python
375
  >>> import yaml
376
  >>> with open("sample1.yml", "r") as f:
377
  ...     y1 = yaml.safe_load(f)
378
  ...     y1
379
  ...
380
  {'database': {'host': 'localhost', 'port': 3306, 'db': 'test', 'user': 'test'}, 'smtp_host': 'localhost'}
381
  ```
382
383
  <br>**複数ドキュメント**
384
  ```
385
  ---
386
  order: 1
387
  menu: ham
388
  ---
389
  order: 2
390
  menu: egg
391
  ```
392
393
  ```python
394
  >>> with open("sample2.yml", "r") as f:
395
  ...     y2 = yaml.safe_load(f)  # 複数ドキュメントに対して load() はエラー
396
  ...     y2
397
  ...
398
  Traceback (most recent call last):
399
    ...(略)...
400
  yaml.composer.ComposerError: expected a single document in the stream
401
    in "sample2.yml", line 2, column 1
402
  but found another document
403
    in "sample2.yml", line 4, column 1
404
  ```
405
406
  ```python
407
  >>> with open("sample2.yml", "r") as f:
408
  ...     y3 = yaml.safe_load_all(f)  # 複数ドキュメントに対しては load_all()
409
  ...     for y in y3:  # load_all() はジェネレーターを生成し、毎取得時にファイル参照するので、with 内で読み込みを完了させる
410
  ...         y
411
  ...
412
  {'order': 1, 'menu': 'ham'}
413
  {'order': 2, 'menu': 'egg'}
414
  ```
415
416
- YAML ファイルの書き込み
417
  
418
  |関数名|解説|戻り値|
419
  |---|---|---|
420
  |`dump(data, stream=None, Dumper=Dumper, **kwds)`|Python オブジェクトを YAML 文字列へ変換する|文字列または `stream` で指定した型|
421
  |`safe_dump(data, stream=None, **kwds)`|`dump()` と同じだが、標準の YAML タグ以外の変換はエラー|文字列または `stream` で指定した型|
422
423
  - `**kwds` 部分の代表的引数
424
425
    |引数|解説|
426
    |---|---|
427
    |`indent`|インデントのスペース数を数値指定|
428
    |`explicit_start`|True の場合、先頭に「---」が含まれる (デフォルトは False)|
429
    |`default_flow_style`|True の場合 (デフォルト)、YAML のフロースタイル<br>False の場合、ブロックスタイル<br>(※動作確認時は、デフォルトが False になっていた)|
430
431
432
    ```python
433
    >>> hosts = {'web_server': ['192.168.0.2', '192.168.0.3'], 'db_server': ['192.168.10.7']}
434
    >>> with open('dump.yml', 'w') as f:
435
    ...     f.write(yaml.dump(hosts, default_flow_style=False))
436
    ...
437
    66
438
    ```
439
440
    ```
441
    db_server:
442
    - 192.168.10.7
443
    web_server:
444
    - 192.168.0.2
445
    - 192.168.0.3
446
    ```
447
448
## 13.5 Excel を扱う openpyxl
449 2 Tatsuya ISHIGAKI
MS Excel の読み書きを Python で行うための機能を提供する
450
`pip install openpyxl`
451 1 Tatsuya ISHIGAKI
452 2 Tatsuya ISHIGAKI
- Excel の読み込み
453
  - 関数 `load_workbook(filename, read_only=False, use_iterators=False, keep_vba=False, guess_types=False, data_only=False)`
454
    - `filename` Excel ファイルパス
455
    - `read_only` True の場合、読み取り専用となり編集できない
456
    - `data_only` True の場合、セルの値が式の場合に評価結果を取得する
457
    - **戻り値** `Workbook` オブジェクト
458
  - 参照
459
    - `Workbook` の属性 `sheetnames` で、ワークシート名のリストが取得可能
460
    - `Workbook` からはワークシート名をキーとして辞書と同様に `Worksheet` が取得可能
461
    - `Worksheet` からはセル名をキーとして辞書と同様に `Cell` が取得可能
462
      - メソッド `cell(row=None, column=None, value=None)` でも取得可能
463
    - `Cell` の値は属性 `value` で取得可能
464
- Excel の書き込み
465
  - `Cell` に値を設定するには、辞書の値設定と同様に行う
466 1 Tatsuya ISHIGAKI
467 2 Tatsuya ISHIGAKI
    <br>Workbook のメソッド
468
    |メソッド名|解説|戻り値|
469
    |---|---|---|
470
    |`create_sheet(title=None, index=None)`|シートを `index` 位置に挿入する (0 なら先頭)|`Worksheet` オブジェクト|
471
    |`save(filename)`|ファイルパス `filename` へ Excel ファイルを保存する|None|
472
- スタイルの適用
473
  - フォント
474
    - `openpyxl.styles.Font` オブジェクトを作成し、セルの `font` 属性に設定する
475
  - セルの色、模様 (塗りつぶし)
476
    - `openpyxl.styles.PatternFill` オブジェクトを作成し、セルの `fill` 属性に設定する
477
  - 罫線
478
    - `openpyxl.styles.Border` オブジェクトを作成し、セルの `border` 属性に設定する
479
      - `Border` に設定する各辺の属性は `openpyxl.styles.Side` オブジェクトを設定する
480
  - 文字位置
481
    - `openpyxl.styles.Alignment` オブジェクトを作成し、セルの `alignment` 属性に設定する
482
- チャートの挿入
483
  - `openpyxl.chart` に様々なチャートあり (例 `LineChart` `BarChart`)
484
485
### 注意点
486
- 表示形式が「ユーザー定義」のセルは注意、日付がシリアル値取得されるなどあり (openpyxl.utils パッケージに変換ツールなどが存在する)
487
- Excel ファイルが他で開かれていると、保存時に PermissionError が発生する
488
- `data_only=True` で式の解決値を取得できるのは、Excel ソフトで一度以上開いた場合のみ
489
  - プログラムで書き込んで、Excel で開かないまま読み込むと解決値は取得できない
490
  - これは Excel で開いた際に式解決が行われて結果がキャッシュされる為
491
492 1 Tatsuya ISHIGAKI
## 13.6 画像を扱う Pillow
493 2 Tatsuya ISHIGAKI
画像データ (JPEG, PNG など) を扱う機能 (拡大縮小、回転、色調変更、文字挿入 等) を提供する
494
`pip install pillow`
495
`import PIL` ※インポート時の指定に注意
496
497
- 画像読み込み (PIL.Image モジュール)
498
  - 関数 `open(file_path, mode='r', formats=None)`
499
    - `file_path` 画像ファイルパス
500
    - `mode` モード指定だが、'r' 以外は使用できない
501
    - `formats` 開くファイルのフォーマットを制限したい場合は、フォーマットをタプルかリストで指定
502
    - **戻り値** `Image` オブジェクト
503
- 画像のサイズを変更する、回転する
504
  - メソッド `resize(size, resample=None, box=None, reducing_gap=None)`
505
    - `size` リサイズ後の画像サイズ (ピクセル) をタプル (width, hight) で指定
506
    - `resample` リサンプリングフィルターを指定
507
      - `PIL.Image.NEAREST` 最近傍
508
      - `PIL.Image.BILINEAR` バイリニア
509
      - `PIL.Image.BICUBIC` バイキュービック
510
      - `PIL.Image.LANCZOS` ランチョス
511
      - `PIL.Image.BOX`
512
      - `PIL.Image.HAMMING`
513
    - **戻り値** `Image` オブジェクト
514
  - メソッド `rotate(angle, resample=0, expand=0, center=None, translate=None, fillcolor=None)`
515
    - `angle` 回転角度 (反時計回り)
516
    - **戻り値** `Image` オブジェクト
517
- 画像を保存する
518
  - メソッド `save(file_path, format=None, **params)`
519
    - `file_path` 保存ファイルパス
520
    - `format` 保存する画像のフォーマットを指定 (省略時は `file_path` の拡張子から自動判別)
521
    - `**param` フォーマットごとに異なるオプション指定
522
    - **戻り値** None
523
- テキストの埋め込み
524
  - `ImageFont.truetype()` でフォントオブジェクト (FreeTypeFont) を取得し、`ImageDraw.Draw()` で `Image` に対する `ImageDraw` オブジェクトを作成し、`ImageDraw.text()` で画像に埋め込む
525
  - 関数 `ImageFont.truetype(font=None, size=10, index=0, encoding='', layout_engine=None)`
526
    - `font` TrueType のフォントファイルを設定
527
    - `size` フォントサイズを指定
528
    - `index` 指定したフォントファイルに複数んおフォントが含まれている場合、ttc 番号を指定
529
    - **戻り値** フォントオブジェクト (`FreeTypeFont`)
530
  - 関数 `ImageDraw.Draw(im, mode=None)`
531
    - `im` Image オブジェクト
532
    - **戻り値** `ImageDraw` オブジェクト
533
  - メソッド `ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align='left', direction=None, features=None, language=None, stroke_width=0, stroke_fill=None, embedded_color=False)`
534
    - `xy` テキストを埋め込む座標をタプル (x, y) で指定 (`anchor` 指定で実位置に変化あり)
535
    - `text` 埋め込むテキスト
536
    - `fill` テキストの色指定
537
    - `font` フォントオブジェクトを指定
538
    - **戻り値** None
539
540
  ```python
541
  >>> from PIL import Image, ImageDraw, ImageFont
542
  >>> ifont = ImageFont.truetype(r'C:\Windows\Fonts\Meiryo UI\meiryo.ttc', size=40)
543
  >>> image = Image.open("GrandCanyon.jpg")
544
  >>> idraw = ImageDraw.Draw(image)
545
  >>> idraw.text((306,10), "グランドキャニオン", font=ifont, fill='red')
546
  >>> image.save('GrandCanyon_withText.jpg')
547
  ```
548
549
  <br>元画像
550
  ![元画像](GrandCanyon.jpg "元画像")
551
552
  <br>テキスト埋め込み後画像
553
  ![テキスト埋め込み後](GrandCanyon_withText.jpg "テキスト埋め込み後")