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

プログラミング
bitbank

症状「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を早く身に付けたい人は

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

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

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


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

私はものづくり技術職であり、他業種からプログラミングの勉強はじめました。

プログラミングの独学は挫折する確率が70%と言われており非常に高いです。

理由は私も体感しましたがかなり専門用語が多く、勉強の仕方も良く分からないところで苦戦しました。

モチベーションを保つには、はやくつまらない基礎学習は済ませて、気になるアプリを自分でつくってみることだと思います。

自分の思う通りに動作してくれると、結構楽しくて便利で、プログラミングにハマると思います。

もしも、悩んだ場合はプロに相談するのが良いですが、スクールなどは数万円~数十万円と値段がかかります。まずは、無料カウンセリングで、聞きたいことを聞きまくるのが良いです。

おすすめの無料カウンセリングを紹介しておきます。

大事なことですが、聞きたいことを事前にすべてまとめてから相談しましょう。

・悩んでいること
・具体的な勉強方法
・転職相談(希望あれば)
などを箇条書きに整理しておくイメージです。

無料ですので、時間の限り、どんどん質問しましょう。恥はかきすての精神です。自分の本気度次第で恥ずかしさは無くなるかと思います。
(何も考えずにいくと、スクール入会を勧められるだけで、実りある時間になりません,,,)

★プログラミング学習で悩んでいる人
プログラミングスクール大手のTechAchademyの無料学習カウンセリングです。プログラミング学習で悩んでいる人にプロの方がやさしく丁寧に答えてくれます。


★ITエンジニア転職まで考えている人

プログラミングスクール大手のTechAchademyの転職含めたカウンセリングです。IT業界に就職・転職したい人は、役立ち情報や進め方など、教えてくれます。スクールに入ると就職までしっかりと面倒を見てくれるコースもあるので参考に話を聞いてみるのはアリかなと思います。



bitbank
プログラミング
みやみつブログ