同じ処理を複数のファイルに適用したいとき、バッチ処理が便利です。
QGISバッチ処理入門【複数ファイルの一括処理】
この記事では、QGISでバッチ処理を行う方法を解説します。
バッチ処理とは
概要
バッチ処理 = 複数のデータに同じ処理を一括で適用すること
【手動処理】 ファイル1 → 処理 → 出力1 ファイル2 → 処理 → 出力2 ファイル3 → 処理 → 出力3 → 時間がかかる、ミスが起きやすい 【バッチ処理】 [ファイル1, 2, 3] → 一括処理 → [出力1, 2, 3] → 効率的、確実
活用シーン
| シーン | 処理内容 |
|---|---|
| 座標系変換 | 複数ファイルをまとめて変換 |
| バッファ作成 | 複数レイヤにバッファを作成 |
| 形式変換 | シェープファイル→GeoPackage |
| 属性計算 | 全ファイルの面積を計算 |
処理ツールのバッチ実行
バッチ処理の起動
手順
- プロセシング → ツールボックス
- 使いたいツールを右クリック
- 「バッチ処理として実行」
バッチ処理画面
┌────────────────────────────────────────────┐ │ パラメータ1 パラメータ2 出力 │ ├────────────────────────────────────────────┤ │ 入力1 100 出力1.shp │ │ 入力2 100 出力2.shp │ │ 入力3 100 出力3.shp │ ├────────────────────────────────────────────┤ │ [行を追加] [自動入力] [実行] │ └────────────────────────────────────────────┘
入力ファイルの一括追加
手順
- 「入力」列のセルをダブルクリック
- ファイル選択ダイアログ
- 複数ファイルを選択(Ctrl+クリック)
- 各行に自動で展開される
出力ファイル名の自動生成
出力列で「自動入力」を使用: ・入力ファイル名をベースに自動生成 ・接頭辞/接尾辞を追加可能 例: 入力:data.shp 出力:data_buffered.shp
PyQGISでのバッチ処理
基本パターン
python
import os
import processing
input_folder = "C:/data/input"
output_folder = "C:/data/output"
# フォルダ内のシェープファイルを処理
for filename in os.listdir(input_folder):
if filename.endswith(".shp"):
input_path = os.path.join(input_folder, filename)
output_name = filename.replace(".shp", "_processed.shp")
output_path = os.path.join(output_folder, output_name)
# 処理を実行
processing.run("native:buffer", {
'INPUT': input_path,
'DISTANCE': 100,
'OUTPUT': output_path
})
print(f"処理完了: {filename}")
print("すべての処理が完了しました")
複数の処理を連続実行
python
def process_file(input_path, output_folder):
filename = os.path.basename(input_path)
name = os.path.splitext(filename)[0]
# 処理1: 座標系変換
reprojected = processing.run("native:reprojectlayer", {
'INPUT': input_path,
'TARGET_CRS': 'EPSG:6677',
'OUTPUT': 'memory:'
})['OUTPUT']
# 処理2: バッファ
buffered = processing.run("native:buffer", {
'INPUT': reprojected,
'DISTANCE': 50,
'OUTPUT': 'memory:'
})['OUTPUT']
# 処理3: 出力
output_path = os.path.join(output_folder, f"{name}_result.gpkg")
processing.run("native:savefeatures", {
'INPUT': buffered,
'OUTPUT': output_path
})
return output_path
# バッチ実行
for filepath in glob.glob("C:/data/*.shp"):
result = process_file(filepath, "C:/output")
print(f"完了: {result}")
実践的なバッチ処理例
例1: 座標系一括変換
python
import os
import processing
def batch_reproject(input_folder, output_folder, target_crs):
"""複数ファイルの座標系を一括変換"""
os.makedirs(output_folder, exist_ok=True)
for filename in os.listdir(input_folder):
if filename.endswith(('.shp', '.gpkg', '.geojson')):
input_path = os.path.join(input_folder, filename)
output_path = os.path.join(output_folder, filename)
try:
processing.run("native:reprojectlayer", {
'INPUT': input_path,
'TARGET_CRS': target_crs,
'OUTPUT': output_path
})
print(f"✓ {filename}")
except Exception as e:
print(f"✗ {filename}: {e}")
# 実行
batch_reproject(
"C:/data/input",
"C:/data/output_epsg6677",
"EPSG:6677"
)
例2: シェープファイル→GeoPackage変換
python
import os
import processing
def shp_to_gpkg(input_folder, output_gpkg):
"""複数シェープファイルを1つのGeoPackageに統合"""
for filename in os.listdir(input_folder):
if filename.endswith(".shp"):
input_path = os.path.join(input_folder, filename)
layer_name = os.path.splitext(filename)[0]
options = QgsVectorFileWriter.SaveVectorOptions()
options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
options.layerName = layer_name
layer = QgsVectorLayer(input_path, layer_name, "ogr")
QgsVectorFileWriter.writeAsVectorFormatV3(
layer,
output_gpkg,
QgsCoordinateTransformContext(),
options
)
print(f"追加: {layer_name}")
# 実行
shp_to_gpkg("C:/data/shapefiles", "C:/data/combined.gpkg")
例3: 面積・長さの一括計算
python
import os
def calculate_geometry_batch(input_folder, field_name, calc_type):
"""複数ファイルのジオメトリを計算して属性に追加"""
for filename in os.listdir(input_folder):
if filename.endswith(".gpkg"):
filepath = os.path.join(input_folder, filename)
layer = QgsVectorLayer(filepath, filename, "ogr")
if not layer.isValid():
continue
# フィールド追加
layer.startEditing()
if field_name not in [f.name() for f in layer.fields()]:
layer.addAttribute(QgsField(field_name, QVariant.Double))
layer.updateFields()
field_index = layer.fields().indexOf(field_name)
# 計算
for feature in layer.getFeatures():
if calc_type == "area":
value = feature.geometry().area()
elif calc_type == "length":
value = feature.geometry().length()
else:
value = 0
layer.changeAttributeValue(feature.id(), field_index, value)
layer.commitChanges()
print(f"計算完了: {filename}")
# 実行(面積計算)
calculate_geometry_batch("C:/data", "calc_area", "area")
エラーハンドリング
基本的なエラー処理
python
import traceback
def safe_batch_process(input_folder, output_folder):
"""エラーが発生しても処理を継続"""
success = []
failed = []
for filename in os.listdir(input_folder):
if filename.endswith(".shp"):
input_path = os.path.join(input_folder, filename)
output_path = os.path.join(output_folder, filename)
try:
processing.run("native:buffer", {
'INPUT': input_path,
'DISTANCE': 100,
'OUTPUT': output_path
})
success.append(filename)
except Exception as e:
failed.append({
'file': filename,
'error': str(e),
'traceback': traceback.format_exc()
})
# 結果サマリ
print(f"\n=== 処理結果 ===")
print(f"成功: {len(success)}件")
print(f"失敗: {len(failed)}件")
if failed:
print("\n失敗したファイル:")
for f in failed:
print(f" - {f['file']}: {f['error']}")
return success, failed
入力検証
python
def validate_input(filepath):
"""入力ファイルの検証"""
if not os.path.exists(filepath):
raise FileNotFoundError(f"ファイルが見つかりません: {filepath}")
layer = QgsVectorLayer(filepath, "test", "ogr")
if not layer.isValid():
raise ValueError(f"無効なレイヤ: {filepath}")
if layer.featureCount() == 0:
raise ValueError(f"フィーチャがありません: {filepath}")
return True
ログと進捗管理
ログファイルの出力
python
import logging
from datetime import datetime
def setup_logging(log_folder):
"""ログ設定"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file = os.path.join(log_folder, f"batch_{timestamp}.log")
logging.basicConfig(
filename=log_file,
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
return logging.getLogger()
# 使用例
logger = setup_logging("C:/logs")
logger.info("バッチ処理開始")
logger.info(f"処理完了: {filename}")
logger.error(f"エラー: {error}")
プログレス表示
python
def batch_with_progress(input_files, output_folder):
"""プログレス付きバッチ処理"""
total = len(input_files)
for i, filepath in enumerate(input_files):
progress = (i + 1) / total * 100
print(f"\r処理中: {progress:.1f}% ({i+1}/{total})", end="")
# 処理
process_file(filepath, output_folder)
print("\n完了!")
まとめ
バッチ処理のポイント
ポイント
- 処理ツールの「バッチ処理として実行」が簡単
- 複雑な処理はPyQGISで
- エラーハンドリングを忘れずに
- ログを残して追跡可能に
チェックリスト
実行前の確認
- 入力ファイルの形式・座標系を確認
- 出力先フォルダを準備
- テストデータで動作確認
- エラー処理を実装
- ログを記録
関連記事
