LoginSignup
3
2

More than 1 year has passed since last update.

Pythonだけでグラフを欠損させずにExcelシートをコピーしたい

Posted at

PythonでExcelのグラフを欠損させずシートをコピーする

最終的なコード

import pathlib

import pythoncom
import win32com.client


def copy_sheet(filepath: str, src_sheet: int | str, dst_sheet: int | str, new_sheet_name: str | None = None) -> None:
    """シートをコピーする。

    Args:
        filepath (str): Excelファイルのパス。(絶対パス)
        src_sheet (int | str): コピー元のシート。シート名 or シートのインデックス(1~)で指定する。
        dst_sheet (int | str): コピー先のシート位置。シート名 or シートのインデックス(1~)で指定する。
        new_sheet_name (str | None, optional): 新しいシートの名前。 デフォルトは None で、 None の場合は変更しない。
    """
    xl_app = win32com.client.Dispatch("Excel.Application")
    wb = xl_app.Workbooks.Open(filepath)

    try:
        wb.Worksheets(src_sheet).Copy(After=wb.Worksheets(dst_sheet))
        if new_sheet_name:
            xl_app.ActiveSheet.Name = new_sheet_name

        wb.Save()
    except pythoncom.com_error as e:
        print(e.excepinfo[2])
    finally:
        wb.Close(True)
        xl_app.Quit()


# 絶対パスでないと受け付けないので注意
src_path = str(pathlib.Path("./tests/test.xlsx").resolve())

copy_sheet(src_path, "1", "3", "new sheet (src.1 dst.3)")
# インデックス指定の場合(1からスタート)
copy_sheet(src_path, 1, 5, "new sheet (src.1 dst.5)")

実行結果

元の Excel
image.png

実行後
image.png

しっかりグラフもコピー出来ています。

背景

Python で Excel を操作しようと思った時、代表的なライブラリとして openpyxl があります。

このライブラリには普段からお世話になっているのですが、1つだけ不満点があります。
それはシートをコピーした時にグラフが消えてしまうという仕様です。

python - Chart can't be copied with Openpyxl - Stack Overflow

業務上、以下のような Excel を扱う機会が多くあるので、この仕様には困らされてきました。

  • 大量の計算式とその結果を参照するグラフを持つフォーマット Excel があり、それをコピーして使い回す
  • シートごとにグラフが存在する

VBA であれば上のような問題は起きませんが、 csv などからデータを抽出・加工して貼り付けたい時に面倒です。

そこで、どうにか Python だけグラフを保持したままシートをコピー出来ないか 試してみました。

解説

準備

pip かお好きなパッケージ管理ツールで pywin32 を導入します。

私は pipenv を使用しています。

pip install pywin32

Worksheet.Copy メソッド

Worksheet.Copy メソッド (Excel) | Microsoft Learn を使えばシートをコピー出来ます。

Worksheet.Copy(Before, After)

Before, After はどちらかしか指定出来ません。

シートの指定

シートの指定には インデックス (1~) or シート名 のどちらかが使えます。
毎回シートの最後にコピーしたい場合、 len(wb.Worksheets) などでシート数を取得すれば良いです。

コピー先シートの名前

コピー直後は Application.ActiveSheet がコピーしたシートに変わっているので、Application.ActiveSheet.Name を変更することでシート名の変更が可能です。

注意点

  • pywin32 は相対パスを受け付けてくれないので絶対パスに変換する必要があります。
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2