LambdaでMatplotlibを使って箱ひげ図のあるエクセルを作成する(openpyxl)
Lambdaで箱ひげ図を作成し、エクセルに挿入します。
2025.01.27
Matplotlibで箱ひげ図を作成し、エクセルに画像を挿入します。本記事では、この処理をAWS Lambdaで実行してみました。
おすすめの方
- LambdaでMatplotlibを使って箱ひげ図を作成したい方
- Lambdaでエクセルを操作したい方
S3バケットやLambdaを作成する
sam init
sam init \
--runtime python3.11 \
--name lambda-excel-sample \
--app-template hello-world \
--no-tracing \
--no-application-insights \
--structured-logging \
--package-type Zip
requirements.txt
にライブラリを記載する
日本語を表示するため、japanize-matplotlibをインストールして利用します。
requirements.txt
openpyxl
matplotlib
japanize-matplotlib
SAMテンプレート
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: lambda-excel-sample
Globals:
Function:
Timeout: 3
LoggingConfig:
LogFormat: JSON
Resources:
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: blog-lambda-excel-sample-bucket
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: blog-lambda-excel-sample-function
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.11
Policies:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Environment:
Variables:
BUCKET_NAME: !Ref Bucket
Architectures:
- x86_64
HelloWorldFunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}
Lambdaコード
適当にエクセルを作成し、箱ひげ図を作成したエクセルをS3バケットに保存します。
import os
import boto3
import openpyxl
import matplotlib.pyplot as plt
import japanize_matplotlib
BUCKET_NAME = os.getenv("BUCKET_NAME")
OUTPUT_FILE_NAME = "output.xlsx"
s3 = boto3.client("s3")
# 四分位は計算済み
DATA = {
"sapporo": [24.6, 19.0, 10.5, 0.8, -1.9],
"tokyo": [33.6, 27.7, 22.2, 14.8, 11.8],
"hakata": [30.5, 23.9, 19.0, 11.5, 8.3],
}
def lambda_handler(event, context):
# エクセルを作成する
wb = openpyxl.Workbook()
ws = wb.active
# データを追加する
ws.append(["都市", "最高気温", "第1四分位", "中央値", "第3四分位", "最低気温"])
ws.append(["札幌", *DATA["sapporo"]])
ws.append(["東京", *DATA["tokyo"]])
ws.append(["博多", *DATA["hakata"]])
# 箱ひげ図を作成する
fig, ax = plt.subplots()
ax.boxplot(
[
DATA["sapporo"],
DATA["tokyo"],
DATA["hakata"],
],
tick_labels=["札幌", "東京", "博多"],
showfliers=False, # 外れ値を表示しない
patch_artist=True, # 塗りつぶす
boxprops={
"facecolor": "bisque", # 塗りつぶしの色
"color": "black", # 枠の色
"linewidth": 1.5, # 枠の太さ
},
medianprops=dict(color="black", linewidth=1.5), # 中央値の線
)
ax.set_ylabel("気温 [℃]")
plt.title("都市ごとの気温分布(2024年1月〜12月)")
plt.grid(axis="y") # y軸方向のグリッドを表示
# 箱ひげ図を /tmp に保存する
boxplot_file_path = os.path.join("/tmp", f"{context.aws_request_id}.png")
plt.savefig(boxplot_file_path)
# エクセルに画像を挿入する
img = openpyxl.drawing.image.Image(boxplot_file_path)
ws.add_image(img, "H2")
# エクセルファイルを /tmp に保存する
output_file_path = os.path.join("/tmp", f"{context.aws_request_id}.xlsx")
wb.save(output_file_path)
# S3にアップロードする
s3.upload_file(output_file_path, BUCKET_NAME, OUTPUT_FILE_NAME)
デプロイ
sam build --use-container
sam deploy \
--guided \
--region ap-northeast-1 \
--stack-name lambda-excel-sample-stack
Lambdaを実行する
aws lambda invoke \
--function-name blog-lambda-excel-sample-function \
output.txt
S3バケットからエクセルファイルを取得する
aws s3 cp s3://blog-lambda-excel-sample-bucket/output.xlsx output.xlsx
エクセルファイルを確認する
期待通りにできました。