LambdaでMatplotlibを使って箱ひげ図のあるエクセルを作成する(openpyxl)

LambdaでMatplotlibを使って箱ひげ図のあるエクセルを作成する(openpyxl)

Lambdaで箱ひげ図を作成し、エクセルに挿入します。
Clock Icon2025.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

エクセルファイルを確認する

期待通りにできました。

01_excel

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.