Python – openpyxlでエクセルグラフや図形が消える問題の解決法

プログラミング

症状「openpyxlでエクセルのシートコピーしたときにグラフや図形や画像が消える」

Pythonのopenpyxlでエクセル制御を行う際に、エクセルのシートをコピーすると、グラフ・画像・図形・テキストボックスが消えてしまう症状があります。

これはpythonの現仕様では避けられない症状のようです。

今回は、この問題の対処法として、
「pythonのwin32com.client と エクセルVBAを組み合わせる」ことで、エクセルのシートをコピーしてもグラフや図形が消えないようにpython制御するコードを作りました。

そのコードについて紹介させていただきます。

win32com.client と エクセルVBAでの対処法

今回解決のために行ったことは、
「エクセルシートコピーのプログラム命令を、pythonで実行するのではなく、エクセルVBAで実行すること」
です。

pythonによるエクセルVBAの実行は、「win32com.client」をimportすることで可能となります。

なぜこの対処法を行ったかについてですが、症状から考察しました。

今回の症状は、「pythonのopenpyxlでシートコピーする際に、シート内の文字や数字は問題なくコピーできるが、シート内のグラフや画像やテキストボックスなど、オブジェクトに関わるコピーはできない」というものでした。

つまり、openpyxlでは、オブジェクト入りのシートコピーはうまく対応できないということです。そこで、エクセルVBAでシートをまるごとコピーすれば、この問題を回避できるのではと考えたからです。

実際に、トライしてみたところ、グラフや画像は消えずに、エクセルシートコピーをすることができました。

そのときのPythonコードと、エクセルVBAコードの例を紹介させていただきます。

コード : Python


それでは、まずpythonのコード例をご紹介いたします。

import win32com.client
import os
filename  = r"C:\Users\mmiya\Desktop\format.xlsm"  
#元エクセル(フォーマット)
filename2 = r"C:\Users\mmiya\Desktop\test1.xlsm" 
#保存先エクセル


app = win32com.client.Dispatch("Excel.Application") 
#win32をappと定義

wb = app.Workbooks.Open(filename, ReadOnly=1) 
#元エクセル(フォーマット)を開く

app.Visible =  0  
#非表示 0、表示 1


sheet = wb.Worksheets("sheet1").Activate() 
#エクセルシート"sheet1"をアクティブ化

app.Application.Run('シート複製マクロ') 
#エクセルVBA「シート複製マクロ」を実行

app.DisplayAlerts = False 
#エクセルVBAでエラー発生しても、止まらずにそのまま進めるコード


wb.SaveAs(filename2)   #ファイル名指定保存
wb.Close                      
#wbを閉じる

app.Application.Quit()   
#アプリケーション終了

pythonでVBAを動かすため、openpyxlではなく、win32com.clientを用います。

エクセルシートをコピーする箇所は、app.Application.Run(‘シート複製マクロ’)です。ここでVBAを実行しています。

また、VBAは、エクセルファイルに事前に組み込んでおく必要があります。私の場合は、フォーマット用のエクセルファイルを準備しておき、そこにVBAを事前に作成しています。

つまり、下記のような手順です。

・フォーマット用のエクセルファイルを準備する
・フォーマット用のエクセルファイルに、VBA(“シート複製マクロ”)を作成しておく
・pythonで一連のプログラムになかで、エクセルシートコピーする際には、フォーマット用のエクセルファイルをwin32com.clientで開きにいく
・pythonのwin32com.clientで、エクセルVBA(“シート複製マクロ”)を実行し、シートコピーを行う
・pythonで、エクセルを別名で保存する


コード : エクセルVBA


次にエクセルVBAのコードについてです。

シートをコピーするだけのコードなので、非常に簡単なコードとなっています。


Sub シート複製マクロ()

Dim Sheetname As String 'シート名の定義
Sheetname = ActiveWorkbook.name 'アクティブエクセルシートを定義

Sheets(1).Activate 'シート1をアクティブ化
Sheets(1).Copy After:=Sheets(1) 'シート1の後ろに複製

End Sub


補足

エクセルのシートコピーもそうですが、例えば、エクセルのグラフ主軸の最大最小数値やグラフ自体のサイズを変更したいときも、私は、pythonではなく、VBAで念のために行っています。
理由はエクセルのシート内のオブジェクトに関わる制御については、pythonは苦手だと思うからです。

その場合は、下記のような順で動作するプログラムをつくっています。
・pythonのwin32com.clientで、最大値と最小値の必要数値などを、エクセルの任意セルに代入
・pythonのwin32com.clientで、エクセルVBA(“グラフ軸の変更マクロ”)を実行
・エクセルVBA(“グラフ軸の変更マクロ”)によって、エクセルの任意セルに代入された数値を読み取りにいき、グラフの軸数値を変更する
・pythonにてエクセルファイル保存

さいごに。本当に役立つ情報

Python初心者は、Udemyでの動画勉強をおすすめします。私もUdemyでかなり上達しました。

下記リンクから、Udemyのサンプル動画で講義の様子や内容を知ることができますので一度確認してみてください。本当におすすめです。

Udemy講師の方は現役でIT企業に勤めている方で、基礎的なところから応用まで丁寧に教えてくれます。特によかったのが、実際のIT企業でのコードの書き方やルールを解説してくれるところです。就職や転職も考えている方にも最初の学習に適していると思いました。


あと、プログラミングスクールが気になっている方は、かなり値段が高いので、せっかくなら就活支援が強いところ(就職率100%みたいなところ)にすることをおすすめします。

例えば、TECH CAMPです。私の友達も就活支援を活用しIT業界に転職した人もいます。

あまり知られていない情報ですが、もしTECH CAMPなどに入会する場合は有名なハピタスというポイ括サイトを経由して申し込みましょう。簡単に現金化できるポイントを3万~5万円分、公式のキャンペーンに加えてさらに貰うことができます。数十万円する費用を少しでも軽減しましょう。

その買うを、もっとハッピーに。|ハピタス



タイトルとURLをコピーしました