#author("2024-07-12T16:20:37+09:00","","")
#author("2024-09-30T10:42:54+09:00","","")
[[matplotlib-円グラフの作成メモ]]

* 目次 [#ac924d71]
#contents

* 円グラフの作成 [#wb931522]
 https://github.com/jgm/pandoc/releases/download/3.1.11/pandoc-3.1.11-windows-x86_64.zip

 # プロキシ情報の設定
 $proxyUri = "http://PROXY_SERVER:PORT"
 $proxyCred = Get-Credential -UserName "USERNAME" -Message "Enter your proxy credentials"
 
 # ダウンロード
 Invoke-WebRequest -Uri "URL" -Proxy $proxyUri -ProxyCredential $proxyCred -OutFile "output_file.zip"


** 目的 [#e23b4c43]
 機械学習やビッグデータの解析では,大量にある多次元データを様々な側面から見る必要がある.ここでは,matplotlibを用いた円グラフの作成方法を学ぶ.

** 説明 [#c977589f]
*** 円グラフの描画 [#fd9df9c5]
まずは簡単な円グラフを描画してみよう.

 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count])
     plt.show()
 if __name__ == '__main__':
     main()

6行目から8行目で,280名の学生のある科目のテストの点数からなる配列を作っている.10行目で90点以上の点数をとった学生数を,11行目で80点以上90点未満の点数をとった学生数を求めている.以下同様に,12行目から15行目までで,各範囲の点数をとった学生数を求めている.19行目のように,axオブジェクトのpieメソッドを,円グラフとして表したい数からなるリストを引数として呼び出すと,円グラフを作成することができる.

*** 凡例・タイトルの表示 [#oce74bd0]
円グラフに凡例とタイトルを指定するには,以下のようにすればよい.
 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     labels = ['S', 'A', 'B', 'C', 'D', 'E']
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count])
     ax.legend(labels, loc='best')
     ax.set_title('Fig.1: Student grades.')
     plt.show()
 if __name__ == '__main__':
     main()

10行目で凡例として表示する文字列からなるリストを作成し,21行目のように,axオブジェクトのlegendメソッドを,作成したリストを引数として呼び出すと,円グラフに凡例をつけることができる.また,タイトルの指定の仕方はこれまでと同様である.

*** 開始位置と描画方向の指定 [#i9d54ccb]
上の実行結果からわかるように,この円グラフは3時の位置から開始し,半時計回りに描画されている.これを12時の位置から開始し,時計回りに描画するには,以下のようにすればよい.

 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     labels = ['S', 'A', 'B', 'C', 'D', 'E']
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count], startangle=90, counterclock=False)
     ax.legend(labels, loc='best')
     ax.set_title('Fig.1: Student grades.')
     plt.show()
 if __name__ == '__main__':
     main()

20行目のように,pieメソッドのキーワード引数startangleに90度と指定すると,デフォルトの開始位置から半時計回り(デフォルトの描画方向)に90度の位置から描画を開始できる.また,キーワード引数counterclockにFalseを指定すると,時計回りに描画することができる.

*** ラベルの指定 [#g22c97dd]
凡例としてではなく,円グラフの周囲にラベルを表示するには,pieメソッドのキーワード引数labelsを使用すればよい.

 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     labels = ['S', 'A', 'B', 'C', 'D', 'E']
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count], labels=labels, startangle=90, counterclock=False)
     ax.set_title('Fig.1: Student grades.')
     plt.show()
 if __name__ == '__main__':
     main()

*** 各データの割合をパーセント表示 [#n9514cee]
各データの割合をパーセント表示することができる.

 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     labels = ['S', 'A', 'B', 'C', 'D', 'E']
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count], autopct='%.1f%%', startangle=90, counterclock=False)
     ax.legend(labels, loc='best')
     ax.set_title('Fig.1: Student grades.')
     plt.show()
 if __name__ == '__main__':
     main()

20行目のように,pieメソッドのキーワード引数autopctに’%.1f%%’と指定すると,小数点以下1桁までの浮動小数点数として各データの割合をパーセント表示することができる.記述のルールはf文字列のフォーマット指定と同じである.

この例では,パーセント表示の一部が重複してしまっている.表示位置を変更するには,以下のようにすればよい.

 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     labels = ['S', 'A', 'B', 'C', 'D', 'E']
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count], autopct='%1.1f%%', pctdistance=1.1, startangle=90, counterclock=False)
     ax.legend(labels, loc='lower right')
     ax.set_title('Fig.1: Student grades.')
     plt.show()
 if __name__ == '__main__':
     main()

20行目のように,pieメソッドのキーワード引数pctdistanceに数値を指定することで,パーセント表示の位置を変更できる.0が円の中心を1が円周を表しており,20行目のように1.1と指定することで,円の少し外側に表示位置を変更している.

*** 各領域の色の指定 [#ua39c0aa]

円グラフの各領域の色を指定するには,以下のようにすればよい.

 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     labels = ['S', 'A', 'B', 'C', 'D', 'E']
     colors = ['red', 'green', 'blue', 'cyan', 'magenta', 'yellow']
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count], colors=colors, autopct='%1.1f%%', pctdistance=1.1, startangle=90, counterclock=False)
     ax.legend(labels, loc='lower right')
     ax.set_title('Fig.1: Student grades.')
     plt.show()
 if __name__ == '__main__':
     main()

11行目で各領域の色を表す文字列からなるリストを作成し,21行目のpieメソッドのキーワード引数colorsで色のリストを指定している.

*** 各領域の輝度の指定 [#p3f82918]
円グラフをグレースケールとして作成したい場合には,以下のようにすればよい.

 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     labels = ['S', 'A', 'B', 'C', 'D', 'E']
     brightness = ['0.15', '0.3', '0.45', '0.6', '0.75', '0.9']
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count], colors=brightness, autopct='%1.1f%%', pctdistance=1.1, startangle=90, counterclock=False)
     ax.legend(labels, loc='lower right')
     ax.set_title('Fig.1: Student grades.')
     plt.show()
 if __name__ == '__main__':
     main()

11行目で各領域の輝度を表す文字列からなるリストを作成している.0が最も暗く,1が最も明るい画素を表している.21行目のように,pieメソッドのキーワード引数colorsで輝度のリストを指定することで,グレースケールの円グラフを作成できる.

*** 各領域の境界線の指定 [#cc5b21b5]
円グラフの各領域の境界線を表示するには,以下のようにすればよい.

 from numpy.random import default_rng
 import matplotlib.pyplot as plt
 def main():
     rg = default_rng(seed=0)
     students_count = 280
     scores = rg.normal(65.9, 10.8, students_count)
     labels = ['S', 'A', 'B', 'C', 'D', 'E']
     brightness = ['0.15', '0.3', '0.45', '0.6', '0.75', '0.9']
     s_count = (90 <= scores).sum()
     a_count = ((80 <= scores) & (scores < 90)).sum()
     b_count = ((70 <= scores) & (scores < 80)).sum()
     c_count = ((60 <= scores) & (scores < 70)).sum()
     d_count = ((50 <= scores) & (scores < 60)).sum()
     e_count = (scores < 50).sum()
     fig = plt.figure(figsize=plt.figaspect(1.0))
     ax = fig.add_subplot()
     ax.pie([s_count, a_count, b_count, c_count, d_count, e_count], wedgeprops={'linewidth': 1, 'edgecolor': 'black'}, colors=brightness, autopct='%1.1f%%', pctdistance=1.1, startangle=90, counterclock=False)
     ax.legend(labels, loc='lower right')
     ax.set_title('Fig.1: Student grades.')
     plt.show()
 if __name__ == '__main__':
     main()

21行目のように,pieメソッドのキーワード引数wedgepropsに辞書として境界線の太さと色を指定することができる.辞書のキーlinewidthが線の太さを,キーedgecolorが線の色を表している.


** 参考サイト [#z020ca2b]
http://makotomurakami.com/blog/2020/04/03/4614/

** python-pptx画像書き込み [#j96ce18b]

 import plotly.graph_objs as go
 import plotly.io as pio
 from pptx import Presentation
 from pptx.util import Inches
 from io import BytesIO
 # サンプルのplotlyグラフを作成
 fig = go.Figure(data=[go.Scatter(x=[1, 2, 3], y=[4, 1, 2])])
 #fig.update_layout(title='グラフのタイトル', legend_font_family='メイリオ')
 fig.update_layout(title='グラフのタイトル', legend_font_family='MSゴシック')
 # plotlyグラフを画像に変換
 img_bytes = pio.to_image(fig, format='png')
 # BytesIOを使用して画像データをバッファに保持
 img_buffer = BytesIO(img_bytes)
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 # 新しいスライドを追加
 slide = prs.slides.add_slide(prs.slide_layouts[5])  # 5は白紙のスライドレイアウト
 # 画像をスライドに追加
 #left = Inches(1)
 #top = Inches(2)
 #width = Inches(5)
 #height = Inches(4)
 #pic = slide.shapes.add_picture(img_buffer, left, top, width, height)
 pic = slide.shapes.add_picture(img_buffer, Inches(1), Inches(2), Inches(7), Inches(5))
 # プレゼンテーションを保存
 prs.save("example_with_plotly.pptx")
 # バッファを閉じる
 img_buffer.close()

** その1 [#f18e555b]
 import matplotlib.pyplot as plt
 from pptx import Presentation
 from pptx.util import Inches
 from io import BytesIO
 # サンプルのMatplotlibグラフを作成
 plt.plot([1, 2, 3], [4, 1, 2])
 plt.xlabel("X軸")
 plt.ylabel("Y軸")
 plt.title("Matplotlibグラフ")
 # グラフを画像に変換
 img_buffer = BytesIO()
 plt.savefig(img_buffer, format='png')
 img_buffer.seek(0)
 plt.close()
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 # 新しいスライドを追加
 slide = prs.slides.add_slide(prs.slide_layouts[5])  # 5は白紙のスライドレイアウト
 # 画像をスライドに追加
 left = Inches(1)
 top = Inches(2)
 width = Inches(5)
 height = Inches(4)
 pic = slide.shapes.add_picture(img_buffer, left, top, width, height)
 # プレゼンテーションを保存
 prs.save("example_with_matplotlib.pptx")
 # バッファを閉じる
 img_buffer.close()

** その2 [#df58f18d]
 import plotly.graph_objs as go
 from pptx import Presentation
 from pptx.util import Inches
 from pptx.enum.text import PP_PARAGRAPH_ALIGNMENT
 # サンプルのplotly表データを作成
 data = [
     go.Table(
         header=dict(values=['列1', '列2']),
         cells=dict(values=[[1, 2, 3], [4, 5, 6]])
     )
 ]
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 # 新しいスライドを追加
 slide = prs.slides.add_slide(prs.slide_layouts[5])  # 5は白紙のスライドレイアウト
 # テーブルをスライドに追加
 left = Inches(1)
 top = Inches(2)
 width = Inches(5)
 height = Inches(2)
 table = slide.shapes.add_table(rows=3, cols=3, left=left, top=top, width=width, height=height)
 #table.fill.solid()
 #table.fill.fore_color.rgb = (255, 255, 255)
 # ヘッダーを追加
 for col, header_text in enumerate(data[0]['header']['values']):
     cell = table.table.cell(0, col)
     cell.text = header_text
     cell.text_frame.paragraphs[0].alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
 # データ行を追加
 for row, row_data in enumerate(data[0]['cells']['values']):
     for col, cell_value in enumerate(row_data):
         cell = table.table.cell(row + 1, col)
         cell.text = str(cell_value)
         cell.text_frame.paragraphs[0].alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
 # プレゼンテーションを保存
 prs.save("example_with_plotly_table.pptx")


** その3 [#n6fbb03b]
 from pptx import Presentation
 from pptx.util import Inches
 from pptx.enum.text import PP_PARAGRAPH_ALIGNMENT
 from pptx.dml.color import RGBColor
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 # スライドを追加
 slide = prs.slides.add_slide(prs.slide_layouts[5])  # 空白スライド
 # 表を作成
 rows = 3
 cols = 3
 left = Inches(1)
 top = Inches(2)
 width = Inches(6)
 height = Inches(2)
 table = slide.shapes.add_table(rows, cols, left, top, width, height).table
 # セル結合
 table.cell(0, 0).merge(table.cell(1, 0))
 # セルにテキストを挿入
 cell = table.cell(0, 0)
 cell.text = '値はありませんでした。'
 # セルのスタイルを設定
 cell.text_frame.paragraphs[0].alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
 cell.text_frame.font.size = Inches(0.2)
 cell.fill.solid()
 cell.fill.fore_color.rgb = RGBColor(217, 217, 217)  # グレーのセル色
 # プレゼンテーションを保存
 prs.save('table_example.pptx')

** その4 [#o4d7710e]
 from pptx import Presentation
 from pptx.util import Inches
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 # スライドを追加
 slide = prs.slides.add_slide(prs.slide_layouts[5])  # 空白スライド
 # 表データを準備
 data = [
     ['Value 1', 'Value 2', 'Value 3'],
     ['', '', ''],
     ['', '', ''],
     ['Value 4', 'Value 5', 'Value 6']
 ]
 # 表を作成
 rows = len(data)
 cols = len(data[0])
 left = Inches(1)
 top = Inches(2)
 width = Inches(6)
 height = Inches(2)
 table = slide.shapes.add_table(rows, cols, left, top, width, height).table
 # 表データをセルに挿入
 for row in range(rows):
     for col in range(cols):
         cell = table.cell(row, col)
         cell.text = data[row][col]
 # 空行を見つけてセル結合
 for row in range(1, rows):
     is_empty_row = all(cell.text == '' for cell in table.row_cells(row))
     if is_empty_row:
         for cell in table.row_cells(row):
             cell._tc.set_attribute('rowSpan', '2')
         table.cell(row + 1, 0).text = '値はありませんでした。'
         for col in range(1, cols):
             table.cell(row + 1, col).text = ''
             table.cell(row + 1, col)._tc.set_attribute('vMerge', '1')
 # プレゼンテーションを保存
 prs.save('merged_table.pptx')

** その5 [#w62f1da0]
 from pptx import Presentation
 from pptx.util import Inches
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 # スライドを追加
 slide = prs.slides.add_slide(prs.slide_layouts[5])  # 空のスライド
 # 表を作成
 rows = 3
 cols = 3
 table = slide.shapes.add_table(rows, cols, Inches(1), Inches(2), Inches(8), Inches(4)).table
 # 表のヘッダーを設定
 for i in range(cols):
     cell = table.cell(0, i)
     cell.text = f'Header {i+1}'
 # 新しい行を追加
 new_row = table.add_row().cells
 new_row[0].text = 'New'
 new_row[1].text = 'Row'
 new_row[2].text = 'Added'
 # プレゼンテーションを保存
 prs.save('table_example.pptx')

** その6 [#a3d119aa]
 from pptx import Presentation
 from pptx.util import Inches
 def add_row_to_table_if_not_exists(table, row_index):
     while len(table.rows) <= row_index:
         table.add_row()
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 # スライドを追加
 slide = prs.slides.add_slide(prs.slide_layouts[5])  # 空のスライド
 # 表を作成
 rows = 3
 cols = 3
 table = slide.shapes.add_table(rows, cols, Inches(1), Inches(2), Inches(8), Inches(4)).table
 # 表のヘッダーを設定
 for i in range(cols):
     cell = table.cell(0, i)
     cell.text = f'Header {i+1}'
 # 行が存在しない場合に新しい行を追加
 target_row_index = 4  # 追加したい行のインデックス
 add_row_to_table_if_not_exists(table, target_row_index)
 target_row = table.rows[target_row_index].cells
 target_row[0].text = 'New'
 target_row[1].text = 'Row'
 target_row[2].text = 'Added'
 # プレゼンテーションを保存
 prs.save('table_with_dynamic_row.pptx')

** その7 [#q59a0240]
もちろんです。PythonでJSONファイルを読み込み、その情報を使ってPython-pptxでスライドを制御するプログラムの例を以下に示します。
JSONファイル (data.json):
 json
 {
     "slides": [
         {
             "title": "Slide 1",
             "content": [
                 "Point 1",
                 "Point 2",
                 "Point 3"
             ]
         },
         {
             "title": "Slide 2",
             "content": [
                 "Item A",
                 "Item B",
                 "Item C"
             ]
         }
     ]
 }

Pythonプログラム:
 python
 import json
 from pptx import Presentation
 from pptx.util import Inches
 # JSONファイルを読み込む
 with open('data.json', 'r') as json_file:
     data = json.load(json_file)
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 # JSONデータからスライドを作成
 for slide_data in data['slides']:
     slide = prs.slides.add_slide(prs.slide_layouts[1])  # タイトルとコンテンツのスライド
     title = slide.shapes.title
     title.text = slide_data['title']
     left = Inches(1)
     top = Inches(2)
     width = Inches(8)
     height = Inches(4)
     content_box = slide.shapes.add_textbox(left, top, width, height)
     content_frame = content_box.text_frame
     for point in slide_data['content']:
         p = content_frame.add_paragraph()
         p.text = point
 # プレゼンテーションを保存
 prs.save('output_presentation.pptx')
このコードは、JSONファイルからスライドのタイトルとコンテンツ情報を取得し、Python-pptxを使用してプレゼンテーションを生成する例です。JSONファイルを編集して必要な情報を追加または変更し、スライドの構造や内容をカスタマイズできます。


** その8 [#j9c97800]
 from pptx import Presentation
 from reportlab.lib.pagesizes import letter
 from reportlab.pdfgen import canvas
 def convert_pptx_to_pdf(input_pptx, output_pdf):
     prs = Presentation(input_pptx)
     pdf_canvas = canvas.Canvas(output_pdf, pagesize=letter)
     for slide in prs.slides:
         pdf_canvas.showPage()
         pdf_canvas.drawString(100, 100, slide.name)  # スライド名を追加できます
         pdf_canvas.drawImage("slide.png", 0, 0, width=letter[0], height=letter[1])  # スライドを画像として追加します
     pdf_canvas.save()
 if __name__ == "__main__":
     input_pptx = "input.pptx"  # 変換したいPowerPointファイルのパス
     output_pdf = "output.pdf"  # 保存するPDFファイルのパス
     convert_pptx_to_pdf(input_pptx, output_pdf)

** その9 [#m52c42a2]
 from pptx import Presentation
 from reportlab.lib.pagesizes import letter
 from reportlab.pdfgen import canvas
 def convert_pptx_to_pdf(input_pptx, output_pdf):
     # PowerPointファイルを開く
     presentation = Presentation(input_pptx)
     # PDFファイルを作成
     pdf_canvas = canvas.Canvas(output_pdf, pagesize=letter)
     # 各スライドをPDFに描画
     for slide in presentation.slides:
         pdf_canvas.showPage()
         pdf_canvas.drawImage(slide.get_image(), 0, 0, width=letter[0], height=letter[1])
     # PDFファイルをクローズ
     pdf_canvas.save()
 if __name__ == "__main__":
     input_pptx_file = "input.pptx"  # PowerPointファイルのパス
     output_pdf_file = "output.pdf"  # 出力PDFファイルのパス
     convert_pptx_to_pdf(input_pptx_file, output_pdf_file)

** その10 [#fb3d302b]

 import plotly.graph_objects as go
 
 # サンプルデータ(データは適宜置き換えてください)
 categories = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"]
 values = [30, 25, 20, 15, 10, 5, 4, 3, 2, 1, 1]
 total_values = sum(values)
 
 # トップ10のデータとそれ以下のデータに分割
 top_10_categories = categories[:10]
 top_10_values = values[:10]
 remaining_categories = categories[10:]
 remaining_values = values[10:]
 
 # トップ10のデータに対する円グラフを作成
 fig = go.Figure()
 fig.add_trace(
     go.Pie(
         labels=top_10_categories,
         values=top_10_values,
         textinfo="label+percent",
         title="Top 10 Categories",
     )
 )
 
 # トップ10以外のデータの合計値を計算
 remaining_value = sum(remaining_values)
 
 # トップ10以外のデータの割合を表示しない
 if remaining_value > 0:
     fig.add_trace(
         go.Pie(
             labels=["Others"],
             values=[remaining_value],
             textinfo="none",
             title="",
         )
     )
 
 # グラフを表示
 fig.show()

** その11 [#d8040899]

 import plotly.express as px
 
 # サンプルデータ(データは適宜置き換えてください)
 data = [
     {"Category": "A", "Value": 30},
     {"Category": "B", "Value": 25},
     {"Category": "C", "Value": 20},
     {"Category": "D", "Value": 15},
     {"Category": "E", "Value": 10},
     {"Category": "F", "Value": 5},
     {"Category": "G", "Value": 4},
     {"Category": "H", "Value": 3},
     {"Category": "I", "Value": 2},
     {"Category": "J", "Value": 1},
     {"Category": "K", "Value": 1},
     # ここにさらにデータを追加
 ]
 
 # データを降順にソート
 data.sort(key=lambda x: x["Value"], reverse=True)
 
 # トップ10のデータとそれ以下のデータに分割
 top_10_data = data[:10]
 remaining_data = data[10:]
 
 # トップ10のデータに対する円グラフを作成
 fig = px.pie(top_10_data, values="Value", names="Category", title="Top 10 Categories")
  
 # トップ10以外のデータの合計値を計算
 remaining_value = sum(item["Value"] for item in remaining_data)
 
 # トップ10以外のデータの割合を表示しない
 if remaining_value > 0:
     fig.add_trace(
         px.pie(
             [{"Category": "Others", "Value": remaining_value}],
             values="Value",
             names="Category",
             title="",
         ).data[0]
     )
 
 # グラフを表示
 fig.show()


** その12 [#a13a1298]
 import plotly.graph_objects as go
 
 # サンプルデータ(データは適宜置き換えてください)
 categories = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"]
 values = [30, 25, 20, 15, 10, 5, 4, 3, 2, 1, 1]
 
 # データを降順にソート
 sorted_data = sorted(zip(categories, values), key=lambda x: x[1], reverse=True)
 
 # トップ10のラベルと値を取得
 top_10_labels, top_10_values = zip(*sorted_data[:10])
 
 # トップ10のデータに対する円グラフを作成
 fig = go.Figure(data=[go.Pie(labels=top_10_labels, values=top_10_values, textinfo="percent+label")])
 
 # グラフを表示
 fig.show()


** その13 [#h094c839]
 from pptx import Presentation
 from pptx.util import Inches
 # プレゼンテーションを作成
 prs = Presentation("template.pptx")  # テンプレートファイルを指定
 # プレースホルダー名とJSONデータをマッピング
 data = [
     {"PlaceholderName": "Title", "Text": "Title 1"},
     {"PlaceholderName": "Content", "Text": "Content 1"},
     # 他のデータ行も追加
 ]
 # ページに収まる行数を計算
 lines_per_page = 10  # 例: 1ページに10行
 # スライドを追加し、プレースホルダーにデータを挿入
 current_slide = None
 for item in data:
     if current_slide is None:
         current_slide = prs.slides.add_slide(prs.slide_layouts[5])  # 新しいスライドを作成
     current_slide.shapes[item["PlaceholderName"]].text = item["Text"]
     if len(current_slide.shapes[item["PlaceholderName"]].text_frame.paragraphs) >= lines_per_page:
         current_slide = None  # ページが変わる場合、新しいスライドを作成
 # PowerPointファイルを保存
 prs.save("output.pptx")

** その14 [#ua21fd13]
 from pptx import Presentation
 # プレゼンテーションを作成
 prs = Presentation()
 # テンプレートファイルを読み込む(.pptxファイル)
 template = Presentation("your_template.pptx")
 # スライドマスターの名前を指定
 slide_master_name = "Your Slide Master Name"
 # 指定した名前のスライドマスターを探す
 selected_slide_master = None
 for slide_master in template.slide_master:
     if slide_master.name == slide_master_name:
         selected_slide_master = slide_master
         break
 if selected_slide_master:
     # 新しいスライドを作成し、指定したスライドマスターを適用
     slide = prs.slides.add_slide(selected_slide_master)
 else:
     print(f"Slide Master '{slide_master_name}' not found in the template.")
 # プレゼンテーションを保存
 prs.save("output.pptx")


** その15 [#sbd50787]
 from pptx import Presentation
 from pptx.util import Pt
 import json
 
 # プレゼンテーションを作成
 prs = Presentation()
 
 # テンプレートファイルを読み込む(.pptxファイル)
 template = Presentation("your_template.pptx")
 
 # JSONデータを読み込む
 with open("your_data.json", "r") as json_file:
     data = json.load(json_file)
 
 # 1ページに表示できる最大行数
 max_lines_per_page = 10
 
 # スライドマスターを指定
 slide_master = template.slide_master[0]
 
 # ページ数を計算
 total_pages = len(data) // max_lines_per_page + 1
 
 for page_number in range(total_pages):
     # 新しいスライドを作成し、スライドマスターを適用
     slide = prs.slides.add_slide(slide_master)
 
     # プレースホルダー1とプレースホルダー2を取得
     placeholder1 = slide.placeholders[0]
     placeholder2 = slide.placeholders[1]
 
     # JSONデータから現在のページに挿入するデータを取得
     start_index = page_number * max_lines_per_page
     end_index = start_index + max_lines_per_page
     page_data = data[start_index:end_index]
 
     # プレースホルダー1にデータを挿入
     text_frame1 = placeholder1.text_frame
     for line in page_data:
         p = text_frame1.add_paragraph()
         p.text = line["placeholder1_data"]
         p.space_before = Pt(14)  # 適切なスペースを設定
 
     # プレースホルダー2にデータを挿入
     text_frame2 = placeholder2.text_frame
     for line in page_data:
         p = text_frame2.add_paragraph()
         p.text = line["placeholder2_data"]
         p.space_before = Pt(14)  # 適切なスペースを設定
 
 # プレゼンテーションを保存
 prs.save("output.pptx")

** その16 [#y11c2db7]
 import plotly.graph_objects as go
 
 # サンプルデータを作成
 labels = ["Category A", "Category B", "Category C", "Category D", "Category E"]
 values = [20, 30, 10, 15, 25]
 
 # 凡例名が長い場合、途中で切る
 max_legend_length = 10  # ここで凡例名の最大長を設定します
 shortened_labels = [label[:max_legend_length] + "..." if len(label) > max_legend_length else label for label in labels]
 
 fig = go.Figure(data=[go.Pie(labels=shortened_labels, values=values)])
 fig.update_traces(textinfo="percent+label")
 
 # グラフを表示
 fig.show()


 sudo mkdir -p /usr/share/fonts/mplus
 sudo wget https://osdn.net/frs/redir.php?m=jaist&f=%2Fmix-mplus-ipa%2F70053%2Fmplus-TESTFLIGHT-063a.tar.xz -O mplus-fonts.tar.xz
 sudo tar xvf mplus-fonts.tar.xz -C /usr/share/fonts/mplus

 from pptx import Presentation
 from pptx.util import Inches
 
 def create_presentation_with_meiryo():
     # Create a presentation
     prs = Presentation()
 
     # Add a slide
     slide = prs.slides.add_slide(prs.slide_layouts[5])  # 5 is a blank slide layout
 
     # Add a title and content slide layout
     title_slide_layout = prs.slide_layouts[0]
     slide = prs.slides.add_slide(title_slide_layout)
     title = slide.shapes.title
     title.text = "Sample Presentation"
 
     content_slide_layout = prs.slide_layouts[1]
     slide = prs.slides.add_slide(content_slide_layout)
     shapes = slide.shapes
     body_shape = shapes.placeholders[1]
     tf = body_shape.text_frame
 
     # Add text to the content slide
     p = tf.add_paragraph()
     p.text = "Hello, Meiryo!"
     p.space_after = Inches(0.1)
 
     # Save the presentation to a file
     prs.save('/tmp/meiryo_presentation.pptx')
 
 create_presentation_with_meiryo()

** その17 [#m7f52d5a]
 def estimate_text_box_size(
         txt,
         font,  # ImageFont
         max_width: Union[int, None] = None,
         line_spacing: int = 4
 ):
     """
     Example of use:
     right_margin = left_margin = Length(Cm(0.25)).pt * pt_per_pixel
     top_margin = bottom_margin = Length(Cm(0.13)).pt * pt_per_pixel
     width, height = estimate_text_box_size(
         txt,
         font,
         max_width=shape_width - (right_margin + left_margin),
     )
 
     print("Computed in pixels (w, h)")
     print((width + right_margin + left_margin, height + top_margin + bottom_margin))
 
 
     :param txt:
     :param font:
     :param max_width:
     :param line_spacing:
     :return:
     """
 
     from PIL import ImageDraw, Image
 
     image = Image.new(size=(400, 300), mode='RGB')
     draw = ImageDraw.Draw(image)
     emu_per_inch = 914400
     px_per_inch = 72.0
     pt_per_pixel = 0.75
 
     fontsize_pt = 12
     # font = ImageFont.truetype("arial.ttf", int(fontsize_pt / pt_per_pixel))
     import textwrap, math
     if max_width is not None:
         actual_txt = []
         for line in txt.split("\n"):
             _, _, width, h = font.getbbox(line)
             split_at = len(line) // math.ceil(width / max_width)
             actual_txt = actual_txt + textwrap.wrap(line, width=split_at)
 
         new_lines = len(actual_txt)
         actual_txt = "\n".join(
             actual_txt
         )
     else:
         actual_txt = txt
         new_lines = 0
 
     left, top, right, bottom = draw.multiline_textbbox(
         (0, 0), actual_txt, font=font, spacing=line_spacing
     )
     ascent, descent = font.getmetrics()
 
     return right - left, bottom  # + descent * new_lines

** その18 [#bce41366]
 from pptx import Presentation
 from pptx.util import Inches
 import polars as pl
 
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 
 # サンプルデータを生成
 data = {
     'Column 1': list(range(1, 13)),
     'Column 2': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L']
 }
 
 # Polarsデータフレームを作成
 df = pl.DataFrame(data)
 
 # 2列12行のテーブルを作成
 table = df.to_pptx()
 
 # スライドを追加
 slide_layout = prs.slide_layouts[5]  # ブランクスライド
 slide = prs.slides.add_slide(slide_layout)
 
 # テーブルをスライドに挿入
 left = Inches(1)
 top = Inches(1)
 width = Inches(6)
 height = Inches(3)
 table.plots[0].set_size(left, top, width, height)
 slide.shapes.add_picture(io.BytesIO(table.to_image()), left, top, width, height)
 
 # プレゼンテーションを保存
 prs.save('table_example.pptx')

** その19 [#u55bdf22]
 from pptx import Presentation
 from pptx.util import Inches
 import polars as pl
 
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 
 # サンプルデータを生成
 data = {
     '対象月': ['2023-01', '2023-02', '2023-03', '2023-04'],
     '件数': [100, 150, 120, 200]
 }
 
 # Polarsデータフレームを作成
 df = pl.DataFrame(data)
 
 # テーブルを作成
 table = df.to_pptx()
 
 # スライドを追加
 slide_layout = prs.slide_layouts[5]  # ブランクスライド
 slide = prs.slides.add_slide(slide_layout)
 
 # テーブルをスライドに挿入
 left = Inches(1)
 top = Inches(1)
 width = Inches(6)
 height = Inches(3)
 table.plots[0].set_size(left, top, width, height)
 slide.shapes.add_picture(io.BytesIO(table.to_image()), left, top, width, height)
 
 # プレゼンテーションを保存
 prs.save('table_example.pptx')

** その20 [#n556b94b]
 from pptx import Presentation
 from pptx.util import Inches
 
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 
 # スライドを追加
 slide_layout = prs.slide_layouts[5]  # ブランクスライド
 slide = prs.slides.add_slide(slide_layout)
 
 # テーブルの行数と列数を指定
 rows = 5
 cols = 2
 
 # テーブルの位置とサイズを指定
 left = Inches(1)
 top = Inches(1)
 width = Inches(6)
 height = Inches(3)
 
 # テーブルをスライドに挿入
 table = slide.shapes.add_table(rows, cols, left, top, width, height).table
 
 # 列の幅を設定
 table.columns[0].width = Inches(3)
 table.columns[1].width = Inches(3)
 
 # テーブルにヘッダーを追加
 table.cell(0, 0).text = '対象月'
 table.cell(0, 1).text = '件数'
 
 # データを追加
 data = [
     ['2023-01', '100'],
     ['2023-02', '150'],
     ['2023-03', '120'],
     ['2023-04', '200'],
 ]
 
 for row_index, row_data in enumerate(data):
     for col_index, cell_data in enumerate(row_data):
         table.cell(row_index + 1, col_index).text = cell_data
 
 # プレゼンテーションを保存
 prs.save('table_example.pptx')

** その21 [#a1b41d35]
 from pptx import Presentation
 from pptx.util import Inches
 
 # 新しいプレゼンテーションを作成
 prs = Presentation('your_presentation.pptx')  # 既存のPowerPointファイルを読み込む
 
 # スライドのインデックス
 slide_index = 0  # スライドのインデックス(0から始まる)
 
 # コンテンツプレースホルダーのインデックス
 content_placeholder_index = 0  # コンテンツプレースホルダーのインデックス(0から始まる)
 
 # 図のプレースホルダーのインデックス
 image_placeholder_index = 1  # 図のプレースホルダーのインデックス(0から始まる)
 
 # スライドを取得
 slide = prs.slides[slide_index]
 
 # コンテンツプレースホルダーを取得
 content_placeholder = slide.placeholders[content_placeholder_index]
 
 # コンテンツプレースホルダーの位置と大きさを取得
 left = content_placeholder.left
 top = content_placeholder.top
 width = content_placeholder.width
 height = content_placeholder.height
 
 # 図のプレースホルダーに変更
 content_placeholder.placeholder_format.idx = image_placeholder_index
 
 # 図のプレースホルダーに位置と大きさを設定
 image_placeholder = slide.placeholders[image_placeholder_index]
 image_placeholder.left = left
 image_placeholder.top = top
 image_placeholder.width = width
 image_placeholder.height = height
 
 # プレゼンテーションを保存
 prs.save('updated_presentation.pptx')


** その22 [#ta285ac6]
 from pptx import Presentation
 from pptx.util import Inches
 
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 
 # スライドにテーブルを追加する関数
 def add_table_to_slide(slide, rows):
     left = Inches(1)  # テーブルの位置を調整
     top = Inches(1)
     width = Inches(8)
     height = Inches(5)
 
     table = slide.shapes.add_table(rows, 2, left, top, width, height).table
 
     # テーブルのデザインやセルの内容を設定
     for row in range(rows):
         for col in range(2):
             cell = table.cell(row, col)
             cell.text = f'Row {row}, Col {col}'
 
 # 仮のデータを作成
 data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
 
 # データをスライドに追加
 for i in range(0, len(data), 10):
     slide = prs.slides.add_slide(prs.slide_layouts[5])  # 5はタイトルとコンテンツ
     add_table_to_slide(slide, min(10, len(data) - i))
 
 # プレゼンテーションを保存
 prs.save('output.pptx')

** その23 [#c819a594]
 from pptx import Presentation
 from pptx.util import Inches
 
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 
 # 新しいスライドを追加する関数
 def add_new_slide(prs):
     slide_layout = prs.slide_layouts[5]  # 5は新しいページのスライドレイアウトに対応します
     slide = prs.slides.add_slide(slide_layout)
     return slide
 
 # サンプルの長い文字列
 long_text = "Your long text goes here. This is just a sample to demonstrate a long string in the table cell."
 
 # 新しいスライドを追加し、テキストをセルに追加する関数
 def add_text_to_slide(slide, text):
     table = slide.shapes.add_table(rows=1, cols=1, left=Inches(0.5), top=Inches(1), width=Inches(8), height=Inches(1)).table
     cell = table.cell(0, 0)
     cell.text = text
 
 # 文字列をチャンクに分割し、指定の文字数でテーブルセルに追加
 chunk_size = 50  # テキストを分割するサイズ
 
 text_chunks = [long_text[i:i + chunk_size] for i in range(0, len(long_text), chunk_size)]
 
 current_slide = prs.slides.add_slide(prs.slide_layouts[5])  # 最初のスライドを追加
 
 for chunk in text_chunks:
     if len(current_slide.shapes) == 0:
         add_text_to_slide(current_slide, chunk)
     else:
         if len(current_slide.shapes[0].text_frame.text) + len(chunk) > chunk_size:
             current_slide = add_new_slide(prs)
             add_text_to_slide(current_slide, chunk)
         else:
             current_slide.shapes[0].text_frame.text += chunk
 
 # プレゼンテーションを保存
 prs.save('output_presentation.pptx')

** その24 [#i052114a]
 from pptx import Presentation
 from pptx.util import Inches
 
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 
 # 新しいスライドを作成
 slide = prs.slides.add_slide(prs.slide_layouts[5])  # 適切なレイアウトを選択
 
 # 10行のサンプルデータ(仮のデータ)
 sample_data = [
     ['A1', 'B1', 'C1'],
     ['A2', 'B2', 'C2'],
     ['A3', 'B3', 'C3'],
     # ... 他の行データを含める ...
 ]
 
 # テーブルを作成
 rows = 4
 cols = 3
 table = slide.shapes.add_table(rows, cols, Inches(1), Inches(1), Inches(6), Inches(3)).table
 
 # テーブルにデータを挿入
 row_index = 0
 for row in sample_data:
     if row_index >= rows:  # テーブルの行数を超えたら新しいスライドにテーブルを追加
         slide = prs.slides.add_slide(prs.slide_layouts[5])
         table = slide.shapes.add_table(rows, cols, Inches(1), Inches(1), Inches(6), Inches(3)).table
         row_index = 0
 
     for col_index, cell_value in enumerate(row):
         table.cell(row_index, col_index).text = cell_value
     row_index += 1
 
 # プレゼンテーションを保存
 prs.save('output_presentation.pptx')

** その25 [#zb5d7725]
 from pptx import Presentation
 from pptx.util import Inches
 
 # 新しいプレゼンテーションを作成
 prs = Presentation()
 
 # 新しいスライドを追加
 slide_layout = prs.slide_layouts[5]  # 5は新しいページのスライドレイアウトに対応します
 slide = prs.slides.add_slide(slide_layout)
 
 # 表を追加する関数
 def add_table_to_slide(slide):
     left = Inches(1)
     top = Inches(1.5)
     width = Inches(8)
     height = Inches(1.5)
 
     rows = 5  # 表の行数
     cols = 3  # 表の列数
 
     table = slide.shapes.add_table(rows, cols, left, top, width, height).table
 
     # 表の見た目を調整(任意)
     table.columns[0].width = Inches(2)
     table.columns[1].width = Inches(3)
     table.columns[2].width = Inches(3)
 
     return table
 
 # 表にレコードを追加する関数
 def add_record_to_table(table, data):
     row_count = len(table.rows)
     for row_index, record in enumerate(data):
         if row_count <= row_index:
             table.add_row().cells
         for col_index, value in enumerate(record):
             table.cell(row_index, col_index).text = value
 
 # サンプルのレコードデータ
 new_records = [
     ["Name 4", "Description 4", "Value 4"],
     ["Name 5", "Description 5", "Value 5"],
     ["Name 6", "Description 6", "Value 6"]
 ]
 
 # 最初のレコードを表に追加
 table = add_table_to_slide(slide)
 initial_records = [
     ["Name 1", "Description 1", "Value 1"],
     ["Name 2", "Description 2", "Value 2"],
     ["Name 3", "Description 3", "Value 3"]
 ]
 add_record_to_table(table, initial_records)
 
 # 後から新しいレコードを表に追加
 add_record_to_table(table, new_records)
 
 # プレゼンテーションを保存
 prs.save('table_presentation.pptx')

** その26 [#vd733bbf]
 from pptx import Presentation
 from pptx.util import Pt
 from pptx.enum.text import MSO_ANCHOR, MSO_UNDERLINE
 from pptx.dml.color import RGBColor
 
 def underline_specific_text(paragraph, target_text):
     for run in paragraph.runs:
         if target_text in run.text:
             # 特定の文字が含まれるRunに下線を引く
             run.font.underline = True
             run.font.underline = MSO_UNDERLINE.DASH_LINE
 
 def main():
     # 新しいプレゼンテーションを作成
     presentation = Presentation()
 
     # スライドを追加
     slide = presentation.slides.add_slide(presentation.slide_layouts[0])
 
     # テキストボックスを追加
     textbox = slide.shapes.add_textbox(left=Pt(100), top=Pt(100), width=Pt(500), height=Pt(200))
     text_frame = textbox.text_frame
 
     # テキストを追加
     p = text_frame.add_paragraph()
     p.text = "This is an example text. Only 'example' should be underlined."
 
     #テキストの一部の色を赤色に変える
     pg = text_frame.paragraphs[0]
     run = pg.add_run()
     run.text = "Anaconda"
     run.font.color.rgb = RGBColor(255, 0, 0)
 
     #テキストの一部を青色に変える
     run = pg.add_run()
     run.text = " and Miniconda"
     run.font.color.rgb = RGBColor(0, 0, 255)
     run.font.underline = True
     run.font.underline = MSO_UNDERLINE.DOTTED_LINE
 
     run = pg.add_run()
     run.text = "Anaconda2"
     run.font.color.rgb = RGBColor(255, 0, 0)
 
     # 特定の文字だけに下線を引く
 #    underline_specific_text(p, "example")
     """
     #白紙のスライドを追加
     slide_layout_6 = ppt.slide_layouts[6]
     slide_6  = ppt.slides.add_slide(slide_layout_6)
     shapes = slide_6.shapes
     shape = shapes.add_textbox(Cm(1), Cm(1), Cm(5), Cm(5))
     text_frame = shape.text_frame
 
     #テキストの一部の色を赤色に変える
     pg = text_frame.paragraphs[0]
     run = pg.add_run()
     run.text = "Anaconda"
     run.font.color.rgb = RGBColor(255, 0, 0)
 
     #テキストの一部を青色に変える
     run = pg.add_run()
     run.text = " and Miniconda"
     run.font.color.rgb = RGBColor(0, 0, 255)
     """
 
     # プレゼンテーションを保存
     presentation.save("underlined_text.pptx")
 
 if __name__ == "__main__":
     main()

** その27 [#k5db21e6]
 def convert_dates(date_list):
     converted_dates = []
 
     for idx, date_str in enumerate(date_list):
         # 日付文字列をyyyymmdd形式からdatetimeオブジェクトに変換
         date_object = datetime.strptime(date_str, "%Y%m%d")
 
         # 初日の場合はyyyymmdd形式で追加、それ以外はdd形式で追加
         if idx == 0:
             converted_dates.append(date_object.strftime("%Y%m%d"))
         else:
             converted_dates.append(date_object.strftime("%d"))
 
     return converted_dates

** その28 [#s3a18a68]
 from pptx import Presentation
 from pptx.util import Inches
 
 def prs_to_pixels(prs, emu_value):
     """
     Convert EMUs (English Metric Units) to pixels based on the presentation settings.
 
     Parameters:
     - prs: Presentation object.
     - emu_value: Value in EMUs.
 
     Returns:
     - pixel_value: Value in pixels.
     """
     emus_per_inch = 914400
     inches_per_pixel = 1 / prs.slide_width  # Assuming the width of the slide as the reference
 
     pixel_value = emu_value / emus_per_inch / inches_per_pixel
     return round(pixel_value)
 
 def get_placeholder_size(prs, slide_master, placeholder_idx):
     """
     Get the width and height of a placeholder on the slide master in pixels.
 
     Parameters:
     - prs: Presentation object.
     - slide_master: The slide master object.
     - placeholder_idx: The index of the placeholder on the slide master.
 
     Returns:
     - width_pixels: Width of the placeholder in pixels.
     - height_pixels: Height of the placeholder in pixels.
     """
     placeholder = slide_master.placeholders[placeholder_idx]
     width_emu, height_emu = placeholder.width, placeholder.height
     width_pixels = prs_to_pixels(prs, width_emu)
     height_pixels = prs_to_pixels(prs, height_emu)
     return width_pixels, height_pixels
 
 # PowerPointプレゼンテーションの読み込み
 presentation = Presentation('your_presentation.pptx')
 
 # スライドマスターの取得 (例: 最初のスライドマスター)
 slide_master = presentation.slide_master
 
 # プレースホルダーのインデックス (例: 0はタイトル、1はサブタイトル)
 placeholder_idx = 0
 
 # プレースホルダーのwidthとheightをピクセルで取得
 width_pixels, height_pixels = get_placeholder_size(presentation, slide_master, placeholder_idx)
 
 # 結果の表示
 print(f"Width: {width_pixels} pixels")
 print(f"Height: {height_pixels} pixels")

** その29 [#c229d5bd]
 import plotly.graph_objects as go
  
 # データの作成
 labels = ['Category A', 'Category B', 'Category C', 'Category D', 'Category E',
           'Category F', 'Category G', 'Category H', 'Category I', 'Category J']
 values = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
  
 # 円グラフの作成
 fig = go.Figure(data=[go.Pie(labels=labels, values=values)])
  
 # レイアウトの設定
 fig.update_layout(
     title='Pie Chart',
     legend=dict(
         orientation='h',    # 凡例の方向を水平に設定
         x=0.5,               # x軸の中央に配置
         y=1.15,              # y軸の位置を調整
         xanchor='center',    # x軸のアンカーポイントを中央に設定
         yanchor='top',       # y軸のアンカーポイントを上端に設定
         traceorder='normal', # 凡例の並び順を指定
         borderwidth=1,       # 凡例の境界線の太さを指定
         bordercolor='Black'  # 凡例の境界線の色を指定
     )
 )
  
 # グラフの表示
 fig.show()

** その30 [#pb00d386]
 from pptx import Presentation
 from pptx.util import Inches
 
 def create_table_on_slide(prs, slide, data):
     # スライドに新しい表を作成
     table = slide.shapes.add_table(rows=1, cols=len(data[0]), left=Inches(1), top=Inches(1), width=Inches(8)).table
 
     # 表にデータを挿入
     for row_num, row_data in enumerate(data):
         for col_num, cell_value in enumerate(row_data):
             table.cell(row_num, col_num).text = str(cell_value)
 
     # 表が入りきらない場合は新しいスライドを作成して続きの表を作成
     if table.rows[0].height > slide.shapes.height:
         new_slide = prs.slides.add_slide(prs.slide_layouts[5])  # 新しい空のスライドを作成(indexは適切なものを選択)
         create_table_on_slide(prs, new_slide, data)
 
 # プレゼンテーションの作成
 presentation = Presentation()
 
 # データ(2次元リスト)の例
 table_data = [
     ["Header 1", "Header 2", "Header 3"],
     ["Data 1-1", "Data 1-2", "Data 1-3"],
     ["Data 2-1", "Data 2-2", "Data 2-3"],
     # ...  続きのデータ
 ]
 
 # 最初のスライドに表を作成
 first_slide = presentation.slides.add_slide(presentation.slide_layouts[5])  # indexは適切なものを選択
 create_table_on_slide(presentation, first_slide, table_data)
 
 # プレゼンテーションを保存
 presentation.save("output.pptx")
 
**その31 [#xe80cdfe]
 from pptx import Presentation
 from pptx.util import Inches, Pt
 
 def create_table_on_slide(prs, slide, data):
     # スライドに新しい表を作成
     table = slide.shapes.add_table(rows=1, cols=len(data[0]), left=Inches(1), top=Inches(1), width=Inches(8)).table
 
     # 表にデータを挿入
     for row_num, row_data in enumerate(data):
         for col_num, cell_value in enumerate(row_data):
             table.cell(row_num, col_num).text = str(cell_value)
 
     return table
 
 def add_rows_to_table(table, num_rows):
     # 指定された数の行を表に追加
     for _ in range(num_rows):
         table.add_row()
 
 # プレゼンテーションの作成
 presentation = Presentation()
 
 # データ(2次元リスト)の例
 table_data = [
     ["Header 1", "Header 2", "Header 3"],
     ["Data 1-1", "Data 1-2", "Data 1-3"],
     ["Data 2-1", "Data 2-2", "Data 2-3"],
     # ...  続きのデータ
 ]
 
 # 最初のスライドに表を作成
 first_slide = presentation.slides.add_slide(presentation.slide_layouts[5])  # indexは適切なものを選択
 table = create_table_on_slide(presentation, first_slide, table_data)
 
 # 3行追加した後の座標を取得
 add_rows_to_table(table, 3)
 table_x = table.left
 table_y = table.top
 
 print(f"Table coordinates after adding 3 rows: ({table_x}, {table_y})")
 
 # 4行追加した後の座標を取得
 add_rows_to_table(table, 4)
 table_x = table.left
 table_y = table.top
 
 print(f"Table coordinates after adding 4 rows: ({table_x}, {table_y})")
 
 # プレゼンテーションを保存
 presentation.save("output.pptx")

** その32 [#xa061721]
 
 from pptx import Presentation
 
 # プレゼンテーションの作成
 presentation = Presentation()
 
 # 新しいスライドの追加
 slide = presentation.slides.add_slide(presentation.slide_layouts[5])  # 適切なスライドレイアウトを選択
 
 # 表の追加
 table = slide.shapes.add_table(rows=1, cols=3, left=100, top=100, width=Inches(4)).table
 
 # 追加した表のインデックス(idx)を取得
 tables_on_slide = slide.shapes._spTree
 table_idx = list(tables_on_slide).index(table._element)
 
 print(f"Index of the added table: {table_idx}")
 
 # プレゼンテーションを保存
 presentation.save("output.pptx")

** その33 [#v2b3fda0]
 from pptx import Presentation
 from pptx.util import Inches
 
 def add_table_to_slide(slide):
     # スライドに新しい表を作成
     table = slide.shapes.add_table(rows=1, cols=3, left=Inches(1), top=Inches(1), width=Inches(4)).table
 
     # 表のヘッダーを設定
     table.cell(0, 0).text = "Header 1"
     table.cell(0, 1).text = "Header 2"
     table.cell(0, 2).text = "Header 3"
 
     return table
 
 def add_record_to_table(table, data):
     # 新しいレコード(行)を表に追加
     table.add_row()
     
     # レコードにデータを挿入
     for col_num, cell_value in enumerate(data):
         table.cell(table.rows[-1].index, col_num).text = str(cell_value)
 
 # PowerPointファイルを読み込み
 presentation = Presentation()
 
 # 新しいスライドの追加
 slide = presentation.slides.add_slide(presentation.slide_layouts[5])  # 適切なスライドレイアウトを選択
 
 # 表をスライドに追加
 added_table = add_table_to_slide(slide)
 
 # レコードを表に追加
 record_data = ["Data 1", "Data 2", "Data 3"]
 add_record_to_table(added_table, record_data)
 
 # プレゼンテーションを保存
 presentation.save("output.pptx")


** その34 [#e8417f90]
 from pptx import Presentation
 from pptx.util import Inches, Pt
 import json
 
 def create_table(slide, data):
     rows, cols = len(data) + 1, len(data[0])
     table = slide.shapes.add_table(rows=rows, cols=cols, left=Inches(1), top=Inches(1), width=Inches(8), height=Inches(4)).table
     
     # Set column widths
     for col, width in enumerate([Inches(2)] * cols):
         table.columns[col].width = width
 
     # Populate header row
     for col, header in enumerate(data[0]):
         cell = table.cell(0, col)
         cell.text = header
         cell.text_frame.paragraphs[0].font.bold = True
 
     # Populate data rows
     for row, row_data in enumerate(data[1:], start=1):
         for col, value in enumerate(row_data):
             cell = table.cell(row, col)
             cell.text = value
             cell.text_frame.word_wrap = True
 
 def create_slides_from_json(template_path, json_path, output_path):
     with open(json_path, 'r') as json_file:
         json_data = json.load(json_file)
 
     prs = Presentation(template_path)
 
     for data in json_data:
         slide = prs.slides.add_slide(prs.slide_layouts[0])  # Assuming the first layout is suitable
         create_table(slide, data)
 
     prs.save(output_path)
 
 # 使用例
 template_file = 'your_template.pptx'
 json_data_file = 'your_data.json'
 output_file = 'output.pptx'
 
 create_slides_from_json(template_file, json_data_file, output_file)

** その35 [#pf2735df]
 from pptx import Presentation
 from pptx.util import Inches, Pt
 
 def get_textbox_height(textbox):
     paragraphs = textbox.text_frame.paragraphs
     total_height = 0
 
     for paragraph in paragraphs:
         for run in paragraph.runs:
             total_height += run.font.size.pt
 
     return total_height
 
 def main():
     # プレゼンテーションファイルのパスを指定
     presentation_path = 'your_presentation.pptx'
     
     # プレゼンテーションを読み込む
     presentation = Presentation(presentation_path)
     
     # 例として1つ目のスライドの1つ目のテキストボックスを取得
     first_slide = presentation.slides[0]
     first_textbox = first_slide.shapes[0]
 
     # テキストボックスの高さを取得
     textbox_height = get_textbox_height(first_textbox)
     
     print(f'Textbox Height: {textbox_height} pt')
 
 if __name__ == "__main__":
     main()
** その36 [#lfdf7146]
 from pptx import Presentation
 from pptx.util import Inches, Pt
 from pptx.enum.text import PP_ALIGN
 from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
 
 def create_table_with_condition(slide, data):
     rows, cols = 3, 4
     table = slide.shapes.add_table(rows, cols, Inches(1), Inches(1), Inches(6), Inches(3)).table
 
     # データのセットアップ
     for row in range(rows):
         for col in range(cols):
             cell = table.cell(row, col)
             cell.text = data[row][col]
             cell.text_frame.text = data[row][col]
             cell.text_frame.paragraphs[0].font.size = Pt(14)
             cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
 
     # 最終行が条件に合致する場合、セルを結合して指定のテキストを置き換える
     if data[-1] == ['合計', '-', '0', '-']:
         last_row_cell = table.cell(rows-1, 0)
         last_row_cell.merge(table.cell(rows-1, cols-1))
         last_row_cell.text_frame.clear()
         last_row_cell.text_frame.text = '対象データはありませんでした'
         last_row_cell.text_frame.paragraphs[0].font.size = Pt(14)
         last_row_cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
 
         # 最終行のセル以外の文字をクリア
 #        for col in range(cols-1):
 #            table.cell(rows-1, col).text_frame.clear()
 
 # プレゼンテーションの作成
 presentation = Presentation()
 slide = presentation.slides.add_slide(presentation.slide_layouts[5])  # Blank Slide
 
 # 3行4列の表データ
 data = [
     ['A1', 'B1', 'C1', 'D1'],
     ['A2', 'B2', 'C2', 'D2'],
     ['合計', '-', '0', '-']
 ]
 
 # 条件に合わせて表を作成
 create_table_with_condition(slide, data)
 
 # プレゼンテーションの保存
 presentation.save('output-023-03.pptx')

** その37 [#d0de4fd6]
 import polars as pl
 
 def detect_rows_with_only_specified_value(df, specified_value):
     # 指定した文字列以外が存在するかどうかを判定する条件式を構築
     condition = ~df.drop(["index"]).apply(lambda series: series.nunique() > 1, in_place=True)
     
     # 検知された条件に合致する行のインデックスを取得
     detected_indexes = df.filter(condition)["index"].to_list()
 
     return detected_indexes
 
 # データの作成
 data = {
     'A': ['apple', 'orange', 'apple'],
     'B': ['banana', 'banana', 'banana'],
     'C': ['cherry', 'cherry', 'cherry'],
     'D': ['date', 'date', 'date']
 }
 df = pl.DataFrame(data)
 
 # 検知する文字列を指定
 specified_value = 'date'
 
 # プログラムを実行して指定した文字列が行内にしか存在しない行を検知
 detected_indexes = detect_rows_with_only_specified_value(df, specified_value)
 
 # 検知された行のインデックスを表示
 print(f"Rows with only '{specified_value}': {detected_indexes}")

** その38 [#s65f52cc]
 import json
 from pptx import Presentation
 from pptx.util import Inches, Pt
 from pptx.enum.text import PP_ALIGN
 from pptx.dml.color import RGBColor
 
 def create_table(slide, title, data):
     title_shape = slide.shapes.title
     title_shape.text = title
     
     # 表の位置とサイズ
     left = Inches(1)
     top = title_shape.top + title_shape.height + Inches(0.5)
     width = Inches(8)
     height = Inches(4)
     
     # 表を作成
     table = slide.shapes.add_table(rows=len(data) + 1, cols=len(data[0]), left=left, top=top, width=width, height=height).table
 
     # 表のスタイル設定
     table.style = "Table Grid"
     
     # タイトル行のフォント設定
     title_row = table.rows[0]
     for cell in title_row.cells:
         cell.text_frame.text = cell.text_frame.text.title()
         cell.text_frame.paragraphs[0].font.size = Pt(14)
         cell.text_frame.paragraphs[0].font.bold = True
         cell.text_frame.paragraphs[0].font.color.rgb = RGBColor(0, 0, 0)
 
     # データ行のフォント設定と折り返し
     for i, row in enumerate(data):
         data_row = table.rows[i + 1]
         for j, value in enumerate(row):
             cell = data_row.cells[j]
             cell.text_frame.text = str(value)
             cell.text_frame.paragraphs[0].font.size = Pt(12)
             cell.text_frame.word_wrap = True
 
 def create_presentation(json_file):
     # PowerPointファイルを生成
     presentation = Presentation()
 
     # JSONファイルからデータを読み込む
     with open(json_file, 'r') as f:
         json_data = json.load(f)
 
     for i, data in enumerate(json_data):
         # 新しいスライドを追加
         slide = presentation.slides.add_slide(presentation.slide_layouts[5])
         
         # タイトルとデータから表を作成
         create_table(slide, f"Table {i + 1}", data)
 
     # PowerPointファイルを保存
     presentation.save("output.pptx")
 
 # JSONファイルから表を作成してPowerPointファイルに保存
 create_presentation("table_data.json")

** その39 [#kcd687dd]
 import json
 from pptx import Presentation
 from pptx.util import Inches, Pt
 from pptx.enum.text import PP_ALIGN
 from pptx.dml.color import RGBColor
 
 def create_table(slide, title, headers):
     title_shape = slide.shapes.title
     title_shape.text = title
     
     # 表の位置とサイズ
     left = Inches(1)
     top = title_shape.top + title_shape.height + Inches(0.5)
     width = Inches(8)
     height = Inches(4)
     
     # 表を作成
     table = slide.shapes.add_table(rows=2, cols=len(headers), left=left, top=top, width=width, height=height).table
 
     # 表のスタイル設定
     table.style = "Table Grid"
     
     # タイトル行のフォント設定
     title_row = table.rows[0]
     for j, header in enumerate(headers):
         cell = title_row.cells[j]
         cell.text_frame.text = header
         cell.text_frame.paragraphs[0].font.size = Pt(14)
         cell.text_frame.paragraphs[0].font.bold = True
         cell.text_frame.paragraphs[0].font.color.rgb = RGBColor(0, 0, 0)
 
 def add_row_to_table(table, data):
     # 表に新しい行を追加
     row_cells = table.add_row().cells
     
     # データ行のフォント設定と折り返し
     for j, value in enumerate(data):
         cell = row_cells[j]
         cell.text_frame.text = str(value)
         cell.text_frame.paragraphs[0].font.size = Pt(12)
         cell.text_frame.word_wrap = True
 
 def create_presentation(json_file):
     # PowerPointファイルを生成
     presentation = Presentation()
 
     # JSONファイルからデータを読み込む
     with open(json_file, 'r') as f:
         json_data = json.load(f)
 
     for i, data in enumerate(json_data):
         # 新しいスライドを追加
         slide = presentation.slides.add_slide(presentation.slide_layouts[5])
         
         # タイトル行とデータ行1行だけの表を作成
         create_table(slide, f"Table {i + 1}", data.keys())
         
         # JSONデータのレコードを読み込んで表に行を追加
         add_row_to_table(slide.shapes[0].table, data.values())
 
     # PowerPointファイルを保存
     presentation.save("output.pptx")
 
 # JSONファイルから表を作成してPowerPointファイルに保存
 create_presentation("table_data.json")

** その40 [#m1c0c6ea]
 [
   {"Name": "Alice", "Age": 25},
   {"Name": "Bob", "Age": 30},
   {"Name": "Charlie", "Age": 22},
   {"Name": "David", "Age": 35},
   {"Name": "Eva", "Age": 28},
   {"Name": "Frank", "Age": 31},
   {"Name": "Grace", "Age": 24},
   {"Name": "Hank", "Age": 29},
   {"Name": "Ivy", "Age": 33},
   {"Name": "Jack", "Age": 26},
   {"Name": "Kate", "Age": 32},
   {"Name": "Leo", "Age": 27},
   {"Name": "Mia", "Age": 30},
   {"Name": "Nate", "Age": 23},
   {"Name": "Olivia", "Age": 34},
   {"Name": "Paul", "Age": 31},
   {"Name": "Quinn", "Age": 25},
   {"Name": "Ryan", "Age": 28},
   {"Name": "Sara", "Age": 29},
   {"Name": "Tom", "Age": 36}
 ]

** その41 [#y4f61d3e]
 from copy import deepcopy
 from pptx import slide
 from pptx.table import Table, _Row, _Column, _Cell
 
 def add_row(slide: slide, top_point: int, left_point: int, table: Table) -> Table:
     new_row = deepcopy(table._tbl.tr_lst[-1]) 
     # duplicating last row of the table as a new row to be added
 
     cell_margin_top = 0
     cell_margin_bottom = 0
     for tc in new_row.tc_lst:
         cell = _Cell(tc, new_row.tc_lst)
         cell.text = '' # defaulting cell contents to empty text
         cell_margin_top = cell.text_frame.margin_top
         cell_margin_bottom = cell.text_frame.margin_bottom
 
     table._tbl.append(new_row) 
     # 
     for shape in slide.shapes:
         if shape.top == top_point and shape.left == left_point:
             print('追加したレコード分、表の高さを更新します')
             #shape.height = shape.height + cell_margin_top + cell_margin_bottom
 
 #    return table.rows[-1]
     return table
 
 def remove_row(table: Table,
                row_to_delete: _Row) -> None:
     table._tbl.remove(row_to_delete._tr)

** その42 [#zed425e9]
 import collections.abc
 from pptx import Presentation
 from pptx.util import Inches
 import table_add
 
 
 #        # レコード追加した後に追加したレコード分の高さ情報を更新する
 #        cell_height = cell.text_frame.margin_top + cell.text_frame.margin_bottom
 #        table
 
 
 def check_table_size(slide):
     left_point = 100
     top_point = 200
 
     for shape in slide.shapes:
         print(shape.name)
         if shape.top == top_point and shape.left == left_point:
             print('追加したオブジェクトの位置: ' + str(shape.shape_id))
             print('座標: ' + str(shape.top) + ':' + str(shape.left) + ':'  + str(shape.height) + ':'  + str(shape.width))
 
 def add_table_to_slide(slide):
     left_point = 100
     top_point = 200
 
     # スライドに新しい表を作成
     table = slide.shapes.add_table(rows=1, cols=3, left=left_point, top=top_point, width=Inches(4), height=Inches(1)).table
 
     # 表のヘッダーを設定
     table.cell(0, 0).text = "Header 1"
     table.cell(0, 1).text = "Header 2"
     table.cell(0, 2).text = "Header 3"
 
     return table
 
 def add_record_to_table(slide, top_point, left_point, table, data, cnt):
     # 新しいレコード(行)を表に追加
     table = table_add.add_row(slide, top_point, left_point, table)
     
     # レコードにデータを挿入
     for col_num, cell_value in enumerate(data):
         table.cell(cnt, col_num).text = str(cell_value)
 
 # PowerPointファイルを読み込み
 presentation = Presentation()
 
 # 新しいスライドの追加
 slide = presentation.slides.add_slide(presentation.slide_layouts[5])  # 適切なスライドレイアウトを選択
 
 # 表をスライドに追加
 added_table = add_table_to_slide(slide)
 
 left_point = 100 # レコードを追加したタイミングでオブジェクトの高さを更新する
 top_point = 200
 
 # レコードを表に追加
 record_data = ["Data 1", "Data 2", "Data 3"]
 add_record_to_table(slide, top_point, left_point, added_table, record_data, 1)
 check_table_size(slide)
 record_data = ["Data 4", "Data 5", "Data 6"]
 add_record_to_table(slide, top_point, left_point, added_table, record_data, 2)
 check_table_size(slide)
 record_data = ["Data 7", "Data 8", "Data 9"]
 add_record_to_table(slide, top_point, left_point, added_table, record_data, 3)
 check_table_size(slide)
 
 # プレゼンテーションを保存
 presentation.save("output.pptx")

** その43 [#n0f60db5]
 from pptx import Presentation
 from pptx.util import Inches
 
 def get_table_height(table):
     # Tableが属するshapeオブジェクトの高さを取得
     height = table._element.get_or_add_txBody().bodyPr.get('anchor').split(',')[3]
     return int(height)
 
 # PowerPointファイルを生成
 presentation = Presentation()
 
 # 新しいスライドを追加
 slide = presentation.slides.add_slide(presentation.slide_layouts[5])
 
 # 表を追加
 table = slide.shapes.add_table(rows=3, cols=3, left=Inches(1), top=Inches(1), width=Inches(4), height=Inches(2)).table
 
 # 表の高さを取得
 table_height = get_table_height(table)
 
 # 結果の表示
 print(f"Table Height: {table_height} pt")
 
 # PowerPointファイルを保存
 presentation.save("output.pptx")

** その44 [#w986b0db]
 import uno
 from com.sun.star.beans import PropertyValue
 
 def set_custom_formatting(sheet):
     # 2つ目のスライドを取得
     slide = sheet.getSlides().getByIndex(1)  # インデックスは0から始まるので、2つ目のスライドはインデックス1
 
     # 2番目のスライドのプレースホルダー番号2を取得
     placeholder = slide.getShapes().getByIndex(1)  # インデックスは0から始まるので、2つ目のプレースホルダーはインデックス1
 
     # タブ文字に1点鎖線を設定
     placeholder.getPropertyValue("LineDash")  # 1点鎖線の定義
     placeholder.setPropertyValue("LineDash", (100,))  # 1点鎖線に設定
 
     # 右側のルーラーに12を設定
     sheet.setPropertyValue("RightMargin", 12)
 
 def convert_pptx_to_pdf(input_path, output_path):
     local_context = uno.getComponentContext()
     resolver = local_context.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", local_context)
     context = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
     desktop = context.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", context)
 
     # ファイルを開く
     doc = desktop.loadComponentFromURL(f"file://{input_path}", "_blank", 0, ())
 
     # 特定のシートに対してカスタムフォーマットを適用
     set_custom_formatting(doc.getSheets().getByIndex(0))
 
     # PDFに変換
     pdf_export_props = (
         PropertyValue("FilterName", 0, "writer_pdf_Export", 0),
         PropertyValue("Overwrite", 0, True, 0)
     )
     output_url = f"file://{output_path}"
     doc.storeToURL(output_url, pdf_export_props)
 
     # ドキュメントを閉じる
     doc.close(True)
 
 if __name__ == "__main__":
     input_pptx_path = "/path/to/your_presentation.pptx"
     output_pdf_path = "/path/to/output.pdf"
     convert_pptx_to_pdf(input_pptx_path, output_pdf_path)

** その45 [#pccb485f]
 import os
 
 def convert_pptx_to_pdf(input_pptx, output_pdf):
     os.system(f'PowerShell -Command "& {{ Start-Process powerpnt -ArgumentList \\"{os.path.abspath(input_pptx)}\\", /pt \\"{os.path.abspath(output_pdf)}\\" -Wait }}"')
 
 # 使用例
 input_pptx = 'C:\\path\\to\\your\\presentation.pptx'  # 入力のPowerPointファイルのパス
 output_pdf = 'C:\\path\\to\\your\\output.pdf'          # 出力のPDFファイルのパス
 
 convert_pptx_to_pdf(input_pptx, output_pdf)

** その46 [#t634e87f]
 import os
 
 def convert_pptx_to_pdf(input_pptx, output_pdf):
     os.system(f'PowerShell -Command "& {{ Start-Process powerpnt -ArgumentList \\"{os.path.abspath(input_pptx)}\\", /pt \\"Microsoft Print to PDF\\", \\"{os.path.abspath(output_pdf)}\\" -Wait }}"')
 
 # 使用例
 input_pptx = 'C:\\path\\to\\your\\presentation.pptx'  # 入力のPowerPointファイルのパス
 output_pdf = 'C:\\path\\to\\your\\output.pdf'          # 出力のPDFファイルのパス
 
 convert_pptx_to_pdf(input_pptx, output_pdf)

** その47 [#uf222b5d]
 # PowerPointのCOMオブジェクトを作成
 $powerPoint = New-Object -ComObject PowerPoint.Application
 
 # 変換元のフォルダと変換先のフォルダを指定
 $inputFolder = "C:\Path\To\Input\Folder"
 $outputFolder = "C:\Path\To\Output\Folder"
 
 # 変換元フォルダ内の.pptxファイルを検索
 $pptxFiles = Get-ChildItem -Path $inputFolder -Filter *.pptx
 
 foreach ($pptxFile in $pptxFiles) {
     # PowerPointファイルを開く
     $presentation = $powerPoint.Presentations.Open($pptxFile.FullName)
 
     # PDFに変換して保存
     $pdfFileName = [System.IO.Path]::ChangeExtension($pptxFile.Name, "pdf")
     $pdfFilePath = Join-Path -Path $outputFolder -ChildPath $pdfFileName
     $presentation.ExportAsFixedFormat($pdfFilePath, 32)  # 32はPDF形式
 
     # PowerPointを閉じる
     $presentation.Close()
 }
 
 # PowerPointのCOMオブジェクトを解放
 $powerPoint.Quit()
 [System.Runtime.Interopservices.Marshal]::ReleaseComObject($powerPoint) | Out-Null

** その48 [#d1c17e9a]
 import logging
 import logging.config
 import yaml
 
 def setup_logging(config_file='logging_config.yaml'):
     with open(config_file, 'rt') as f:
         config = yaml.safe_load(f.read())
         logging.config.dictConfig(config)
 
 def main():
     # ログ設定を読み込む
     setup_logging()
 
     # ロガーを取得
     logger = logging.getLogger(__name__)
 
     # ログメッセージの出力
     logger.debug("This is a debug message")
     logger.info("This is an info message")
     logger.warning("This is a warning message")
     logger.error("This is an error message")
     logger.critical("This is a critical message")
 
 if __name__ == "__main__":
     main()

** その49 [#g83dc600]
logging_config.yaml
 version: 1
 formatters:
   simple:
     format: "%(asctime)s - %(levelname)s - %(message)s"
 handlers:
   console:
     class: logging.StreamHandler
     level: INFO
     formatter: simple
   file:
     class: logging.FileHandler
     filename: example.log
     level: DEBUG
     formatter: simple
 loggers:
   my_logger:
     level: DEBUG
     handlers: [console, file]
     propagate: no
 root:
   level: INFO
   handlers: [console]

** その50 [#qb4493f3]
 # ログ設定のバージョン
 version: 1
 
 # フォーマッターの定義
 formatters:
   simple:
     format: "%(asctime)s - %(levelname)s - %(message)s"
 
 # ハンドラーの定義
 handlers:
   # コンソールにログを出力するハンドラー
   console:
     class: logging.StreamHandler
     level: INFO
     formatter: simple
 
   # ファイルにログを出力するハンドラー
   file:
     class: logging.FileHandler
     filename: example.log
     level: DEBUG
     formatter: simple
 
 # ロガーの定義
 loggers:
   # 特定のロガー (ここでは my_logger) の設定
   my_logger:
     level: DEBUG
     handlers: [console, file]
     propagate: no
 
 # ルートロガー (すべてのロガーに適用される設定)
 root:
   level: INFO  # ルートロガーのログレベル
   handlers: [console]  # ルートロガーに適用されるハンドラー

** その51 [#h13cbc4e]

 AWS EC2でwindowsサーバー+Office環境を構築したい。非機能要件書いて。性能要件や費用も月年単位で分かるように。
 ChatGPT
 以下に、AWS EC2上でWindowsサーバーおよびOffice環境を構築する際の非機能要件、性能要件、および費用に関する要件を示します。これらは一般的な要件であり、具体的なプロジェクトやニーズに応じて調整する必要があります。
 
 非機能要件:
 セキュリティ:
 
 インスタンスへのアクセスはセキュアな方法で行い、最小限の必要なポートのみを公開する。
 WindowsサーバーおよびOffice製品のライセンスは正規のものを使用し、セキュリティパッチやアップデートは適切に適用する。
 可用性と信頼性:
 
 EC2インスタンスはマルチアベイラビリティーゾーン(Multi-AZ)に展開し、冗長性を確保する。
 バックアップおよびリカバリ戦略を確立し、データの保護と復旧を行う。
 パフォーマンス:
 
 インスタンスタイプは、適切なCPU、メモリ、およびストレージリソースを持つものを選定する。
 ディスクI/Oおよびネットワークスループットの要件に対応するため、適切なEBSボリュームおよびネットワークの帯域幅を確保する。
 拡張性:
 
 将来的な需要に備えて、必要に応じてリソースを拡張できるアーキテクチャを確立する。
 性能要件:
 CPUおよびメモリ:
 
 インスタンスは、Officeアプリケーションおよび関連サービスの要件に応じたCPUおよびメモリを搭載する。
 ディスクI/O:
 
 ディスクI/OはOffice製品の正常な動作に必要な速度を確保する。
 ネットワーク帯域幅:
 
 インターネット接続およびVPC内の通信において、必要なネットワーク帯域幅を確保する。
 費用要件:
 EC2インスタンスの料金:
 
 EC2インスタンスの選定において、性能要件および予算に合致するインスタンスタイプを選択する。
 ストレージ料金:
 
 使用するEBSボリュームのサイズおよび性能に応じたストレージ料金を考慮する。
 ネットワーク料金:
 
 インターネット接続およびデータ転送に伴うネットワーク料金を評価し、予算に合わせて適切な設定を行う。
 Windowsライセンス料金:
 
 Windows ServerおよびOffice製品の正規のライセンスを購入し、ライセンスに関連する料金を考慮する。
 これらの要件に基づいて、AWSのコスト計算ツールや料金ページを活用して、月や年単位での予算を立てることが重要です。また、適切な予備費用(リザーブドインスタンスなど)を検討することも良いプラクティスです。

** その52 [#v6fb7411]
 import concurrent.futures
 
 def your_function(arg):
     # ここに並列化したい処理を記述
     # この関数は複数のスレッドで同時に実行されます
     result = arg * 2
     return result
 
 def main():
     # 並列処理のためのスレッド数を指定
     num_threads = 4
 
     # ThreadPoolExecutorを作成
     with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor:
         # 並列処理したいデータをリストで準備
         data_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 
         # mapメソッドを使用して並列処理を実行
         results = list(executor.map(your_function, data_list))
 
     # 結果の表示
     print(results)
 
 if __name__ == "__main__":
     main()

** その54 [#d7b6c619]
 import boto3
 from concurrent.futures import ThreadPoolExecutor, as_completed
 
 def process_message(message):
     # ここにメッセージを処理する具体的なロジックを記述
     print(f"Processing message: {message['Body']}")
 
 def receive_messages(queue_url, max_messages=10, num_threads=2):
     # AWSの認証情報やリージョンを設定
     aws_access_key = 'YOUR_ACCESS_KEY'
     aws_secret_key = 'YOUR_SECRET_KEY'
     aws_region = 'YOUR_REGION'
 
     # SQSクライアントの作成
     sqs = boto3.client('sqs', region_name=aws_region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
 
     # メッセージをまとめて取得
     response = sqs.receive_message(
         QueueUrl=queue_url,
         MaxNumberOfMessages=max_messages,
         AttributeNames=[
             'All'
         ],
         MessageAttributeNames=[
             'All'
         ],
         VisibilityTimeout=0,
         WaitTimeSeconds=0
     )
 
     # メッセージが取得できたかどうかを確認
     messages = response.get('Messages', [])
     if messages:
         with ThreadPoolExecutor(max_workers=num_threads) as executor:
             # submitメソッドを使用して各メッセージを非同期に処理
             futures = [executor.submit(process_message, message) for message in messages]
 
             # すべてのFutureが完了するまで待機
             for future in as_completed(futures):
                 try:
                     future.result()
                 except Exception as e:
                     print(f"Error processing message: {e}")
             
             # 取得したメッセージを削除
             for message in messages:
                 sqs.delete_message(QueueUrl=queue_url, ReceiptHandle=message['ReceiptHandle'])
     else:
         print("No messages available in the queue.")
 
 # SQSのURLを指定してメッセージを取得(最大10件、スレッド数2)
 queue_url = 'YOUR_SQS_QUEUE_URL'
 receive_messages(queue_url, max_messages=10, num_threads=2)

** その55 [#qca2d650]
 import boto3
 from botocore.exceptions import NoCredentialsError
 
 # AWSの認証情報
 aws_access_key = 'YOUR_ACCESS_KEY'
 aws_secret_key = 'YOUR_SECRET_KEY'
 aws_region = 'YOUR_REGION'
 aws_sqs_queue_url = 'YOUR_SQS_QUEUE_URL'
 aws_s3_bucket = 'YOUR_S3_BUCKET'
 aws_s3_key = 'YOUR_S3_KEY'
 
 # MFAの情報
 mfa_device_arn = 'YOUR_MFA_DEVICE_ARN'
 mfa_code = 'YOUR_MFA_CODE'
 
 # プロキシの設定
 proxy_host = 'YOUR_PROXY_HOST'
 proxy_port = 'YOUR_PROXY_PORT'
 proxies = {
     'http': f'http://{proxy_host}:{proxy_port}',
     'https': f'http://{proxy_host}:{proxy_port}',
 }
 
 def get_temporary_credentials():
     # STSクライアントの作成
     sts = boto3.client('sts', region_name=aws_region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
 
     # MFAの情報を含めて一時的な認証情報を取得
     response = sts.get_session_token(
         DurationSeconds=3600,  # 任意の有効期間
         SerialNumber=mfa_device_arn,
         TokenCode=mfa_code
     )
 
     return response['Credentials']
 
 try:
     # MFAを含めた一時的な認証情報を取得
     temporary_credentials = get_temporary_credentials()
 
     # SQSクライアントの作成
     sqs = boto3.client('sqs', region_name=aws_region,
                       aws_access_key_id=temporary_credentials['AccessKeyId'],
                       aws_secret_access_key=temporary_credentials['SecretAccessKey'],
                       aws_session_token=temporary_credentials['SessionToken'],
                       proxies=proxies)
 
     # SQSからメッセージを取得
     response = sqs.receive_message(
         QueueUrl=aws_sqs_queue_url,
         MaxNumberOfMessages=10,
         AttributeNames=['All'],
         MessageAttributeNames=['All'],
         VisibilityTimeout=0,
         WaitTimeSeconds=0
     )
 
     messages = response.get('Messages', [])
 
     if messages:
         for message in messages:
             print(f"Received message from SQS: {message['Body']}")
             # SQSのメッセージを削除
             receipt_handle = message['ReceiptHandle']
             sqs.delete_message(QueueUrl=aws_sqs_queue_url, ReceiptHandle=receipt_handle)
 
         # S3クライアントの作成
         s3 = boto3.client('s3', region_name=aws_region,
                           aws_access_key_id=temporary_credentials['AccessKeyId'],
                           aws_secret_access_key=temporary_credentials['SecretAccessKey'],
                           aws_session_token=temporary_credentials['SessionToken'],
                           proxies=proxies)
 
         # S3からファイルをダウンロード
         s3.download_file(aws_s3_bucket, aws_s3_key, 'downloaded_file.txt')
         print("File downloaded from S3.")
     else:
         print("No messages available in the SQS queue.")
 
 except NoCredentialsError:
     print("Credentials not available")
 except Exception as e:
     print(f"An error occurred: {e}")

** その56 [#i1921020]
 import boto3
 from botocore.exceptions import NoCredentialsError
 
 # AWSの認証情報
 aws_access_key_id = 'YOUR_ACCESS_KEY_ID'
 aws_secret_access_key = 'YOUR_SECRET_ACCESS_KEY'
 aws_session_token = 'YOUR_SESSION_TOKEN'  # MFA認証が必要な場合
 
 # プロキシ設定 (必要に応じて)
 proxies = {
     'http': 'http://proxy.example.com:8888',
     'https': 'http://proxy.example.com:8888',
 }
 
 # MFAデバイス情報
 mfa_serial = 'arn:aws:iam::ACCOUNT_ID:mfa/USERNAME'
 mfa_token_code = '123456'  # 実際のMFAデバイスから取得したコード
 
 # S3とSQSクライアントの作成
 s3_client = boto3.client('s3', aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key, aws_session_token=aws_session_token, proxies=proxies)
 sqs_client = boto3.client('sqs', aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key, aws_session_token=aws_session_token, proxies=proxies)
 
 # MFAデバイスのトークンを取得
 mfa_token = boto3.client('sts', aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key).get_session_token(
     SerialNumber=mfa_serial,
     TokenCode=mfa_token_code
 )['Credentials']['SessionToken']
 
 # SQSからメッセージを取得
 queue_url = 'YOUR_SQS_QUEUE_URL'
 try:
     response = sqs_client.receive_message(
         QueueUrl=queue_url,
         AttributeNames=['All'],
         MaxNumberOfMessages=1,
         MessageAttributeNames=['All'],
         VisibilityTimeout=0,
         WaitTimeSeconds=0
     )
 
     # メッセージがある場合、処理を行う
     if 'Messages' in response:
         message = response['Messages'][0]
         print(f"Received message: {message['Body']}")
         # ここでメッセージの処理を行う
 
         # メッセージを削除する
         receipt_handle = message['ReceiptHandle']
         sqs_client.delete_message(
             QueueUrl=queue_url,
             ReceiptHandle=receipt_handle
         )
     else:
         print("No messages in the queue")
 
 except NoCredentialsError:
     print('Credentials not available')
 except Exception as e:
     print(f"Error: {str(e)}")

** その57 [#c66441f1]
 import boto3
 from botocore.exceptions import NoCredentialsError
 
 def get_mfa_session_token(profile_name, mfa_device_arn, mfa_code):
     sts_client = boto3.client('sts')
     response = sts_client.get_session_token(
         DurationSeconds=3600,
         SerialNumber=mfa_device_arn,
         TokenCode=mfa_code
     )
 
     session_credentials = response['Credentials']
     session = boto3.Session(
         aws_access_key_id=session_credentials['AccessKeyId'],
         aws_secret_access_key=session_credentials['SecretAccessKey'],
         aws_session_token=session_credentials['SessionToken']
     )
 
     return session
 
 def receive_messages_with_mfa(queue_url, mfa_session):
     sqs_client = mfa_session.client('sqs')
 
     try:
         response = sqs_client.receive_message(
             QueueUrl=queue_url,
             AttributeNames=['All'],
             MessageAttributeNames=['All'],
             MaxNumberOfMessages=10,
             VisibilityTimeout=0,
             WaitTimeSeconds=0
         )
 
         messages = response.get('Messages', [])
         for message in messages:
             print(f"Received message: {message['Body']}")
 
     except NoCredentialsError:
         print("Credentials not available")
 
 if __name__ == "__main__":
     # AWSのプロファイル名
     aws_profile = 'your_profile'
     
     # MFAデバイスARN
     mfa_device_arn = 'arn:aws:iam::account-id-without-hyphens:mfa/your-mfa-device'
 
     # MFAコード
     mfa_code = input("Enter MFA code: ")
 
     # SQSキューのURL
     sqs_queue_url = 'https://sqs.your-region.amazonaws.com/your-account-id/your-queue-name'
 
     # MFAセッションを取得
     mfa_session = get_mfa_session_token(aws_profile, mfa_device_arn, mfa_code)
 
     # SQSからメッセージを受信
     receive_messages_with_mfa(sqs_queue_url, mfa_session)

** その58 [#ufea8ede]
 import boto3
 from botocore.exceptions import NoCredentialsError
 
 def get_mfa_session_token(profile_name, mfa_device_arn, mfa_code):
     sts_client = boto3.client('sts')
     response = sts_client.get_session_token(
         DurationSeconds=3600,
         SerialNumber=mfa_device_arn,
         TokenCode=mfa_code
     )
 
     session_credentials = response['Credentials']
     session = boto3.Session(
         aws_access_key_id=session_credentials['AccessKeyId'],
         aws_secret_access_key=session_credentials['SecretAccessKey'],
         aws_session_token=session_credentials['SessionToken']
     )
 
     return session
 
 def receive_messages_with_mfa(queue_url, mfa_session):
     sqs_client = mfa_session.client('sqs')
     s3_client = mfa_session.client('s3')
 
     try:
         # SQSからメッセージを受信
         response = sqs_client.receive_message(
             QueueUrl=queue_url,
             AttributeNames=['All'],
             MessageAttributeNames=['All'],
             MaxNumberOfMessages=10,
             VisibilityTimeout=0,
             WaitTimeSeconds=0
         )
 
         messages = response.get('Messages', [])
         
         # メッセージがある場合、S3にファイルを格納
         for message in messages:
             s3_client.put_object(
                 Bucket='your-s3-bucket',
                 Key=f'my-folder/{message["MessageId"]}.txt',
                 Body=message['Body']
             )
             print(f"Stored message in S3: {message['MessageId']}")
 
     except NoCredentialsError:
         print("Credentials not available")
     except Exception as e:
         print(f"Error: {e}")
 
 if __name__ == "__main__":
     # AWSのプロファイル名
     aws_profile = 'your_profile'
     
     # MFAデバイスARN
     mfa_device_arn = 'arn:aws:iam::account-id-without-hyphens:mfa/your-mfa-device'
 
     # MFAコード
     mfa_code = input("Enter MFA code: ")
 
     # SQSキューのURL
     sqs_queue_url = 'https://sqs.your-region.amazonaws.com/your-account-id/your-queue-name'
 
     # MFAセッションを取得
     mfa_session = get_mfa_session_token(aws_profile, mfa_device_arn, mfa_code)
 
     # SQSからメッセージを受信してS3に格納
     receive_messages_with_mfa(sqs_queue_url, mfa_session)

** その59 [#d95c4336]
 import subprocess
 import platform
 
 def run_command(command):
     process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
     output, error = process.communicate()
     return output.decode('utf-8'), error.decode('utf-8'), process.returncode
 
 def get_mfa_code():
     return input("Enter MFA code: ")
 
 def run_script():
     mfa_enabled = True  # ローカル開発時はTrue、本番環境ではFalseと仮定
 
     if mfa_enabled:
         mfa_code = get_mfa_code()
         command = f"aws sts get-session-token --serial-number arn:aws:iam::account-id-without-hyphens:mfa/your-mfa-device --token-code {mfa_code}"
         output, error, return_code = run_command(command)
 
         if return_code == 0:
             # MFA認証が成功した場合、セッショントークン情報を抽出
             session_token_info = output.splitlines()
             aws_access_key_id = session_token_info[2].split(":")[1].strip()
             aws_secret_access_key = session_token_info[3].split(":")[1].strip()
             aws_session_token = session_token_info[4].split(":")[1].strip()
 
             # 本番環境で使う設定
             # ここで本番環境用のAWSクレデンシャル情報を設定する
 
         else:
             print(f"MFA authentication failed: {error}")
             return
 
     else:
         # 本番環境で使う設定
         # ここで本番環境用のAWSクレデンシャル情報を設定する
 
     # 本番環境またはMFA認証成功後に行う処理
     # ここにAWS SDK for Python (Boto3) を使用して実際の処理を記述する
 
 if __name__ == "__main__":
     run_script()

** その60 [#m300645e]
 def update_mfa_section(credentials_file, new_access_key_id, new_secret_access_key):
     with open(credentials_file, 'r') as file:
         lines = file.readlines()
 
     in_mfa_section = False
     for i, line in enumerate(lines):
         if line.strip() == '[mfa]':
             in_mfa_section = True
             continue  # [mfa] セクションは更新せずに次の行に移動
 
         if in_mfa_section and line.startswith('['):
             break  # [mfa] セクションの終わりに到達したらループを終了
 
         if in_mfa_section:
             if line.startswith("aws_access_key_id"):
                 lines[i] = f"aws_access_key_id = {new_access_key_id}\n"
             elif line.startswith("aws_secret_access_key"):
                 lines[i] = f"aws_secret_access_key = {new_secret_access_key}\n"
 
     with open(credentials_file, 'w') as file:
         file.writelines(lines)
 
 if __name__ == "__main__":
     credentials_file = "path/to/your/aws/credentials/file"  # AWS credentialsファイルのパス
     new_access_key_id = "your-new-access-key-id"  # 新しいアクセスキーID
     new_secret_access_key = "your-new-secret-access-key"  # 新しいシークレットアクセスキー
 
     update_mfa_section(credentials_file, new_access_key_id, new_secret_access_key)

** その61 [#l88d683e]
 def get_changed_values(credentials_file):
     changed_values = {}
 
     with open(credentials_file, 'r') as file:
         lines = file.readlines()
 
     for line in lines:
         # 更新された行かどうかを確認
         if line.startswith("aws_access_key_id"):
             parts = line.split("=")
             key = parts[0].strip()
             value = parts[1].strip()
             changed_values[key] = value
         elif line.startswith("aws_secret_access_key"):
             parts = line.split("=")
             key = parts[0].strip()
             value = parts[1].strip()
             changed_values[key] = value
 
     return changed_values
 
 if __name__ == "__main__":
     credentials_file = "path/to/your/aws/credentials/file"  # 更新されたAWS credentialsファイルのパス
 
     updated_values = get_changed_values(credentials_file)
     print("Updated values:")
     print(updated_values)

** その62 [#p8cc680a]
 import logging
 from logging.handlers import TimedRotatingFileHandler
 import os
 import datetime
 
 # ログフォーマットを設定
 log_format = '%(asctime)s - %(levelname)s - %(message)s'
 
 # ロガーを設定
 logger = logging.getLogger()
 logger.setLevel(logging.DEBUG)
 
 # ファイルの日付フォーマットを設定
 date_format = '%Y-%m-%d'
 today_date = datetime.datetime.now().strftime(date_format)
 
 # ファイルハンドラを作成
 log_file = 'example.log'
 backup_file = f'example_{today_date}.log'
 file_handler = TimedRotatingFileHandler(log_file, when='M', interval=1, backupCount=0, encoding='utf-8', atTime=datetime.time(0, 0, 0))
 file_handler.suffix = f'_{today_date}'
 file_handler.setLevel(logging.DEBUG)
 
 # ログフォーマットを設定
 formatter = logging.Formatter(log_format)
 file_handler.setFormatter(formatter)
 
 # ロガーにハンドラを追加
 logger.addHandler(file_handler)
 
 # ログメッセージの出力
 logger.debug('This is a debug message')
 logger.info('This is an info message')
 logger.warning('This is a warning message')
 logger.error('This is an error message')
 logger.critical('This is a critical message')
 
 # 古いバックアップファイルを削除
 try:
     os.remove(backup_file)
 except FileNotFoundError:
     pass

** その63 [#v4e056d8]
 import logging
 from logging.handlers import TimedRotatingFileHandler
 import datetime
 
 def setup_logger(log_path):
     # ロギングの設定
     logger = logging.getLogger()
     logger.setLevel(logging.INFO)
 
     # ローテーション設定
     handler = TimedRotatingFileHandler(log_path, when="midnight", interval=1, backupCount=12)
     handler.suffix = "%Y-%m-%d.log"  # ファイル名の接尾辞を設定する
     formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
     handler.setFormatter(formatter)
 
     logger.addHandler(handler)
 
 def main():
     log_path = "path/to/your/log/directory/logfile.log"  # ログファイルのパスを指定してください
     setup_logger(log_path)
     
     # ログ出力例
     logging.info("This is an info message")
     logging.warning("This is a warning message")
     logging.error("This is an error message")
 
 if __name__ == "__main__":
     main()

** その64 [#cd14ddc0]
 def some_function():
     logger = get_logger()
     logger.info("This is an info message from some_function")
 
 def another_function():
     logger = get_logger()
     logger.error("This is an error message from another_function")
 
 if __name__ == "__main__":
     some_function()
     another_function()


 import logging
 import threading
 
 class SingletonLogger:
     _instance = None
     _lock = threading.Lock()
 
     def __new__(cls):
         if not cls._instance:
             with cls._lock:
                 if not cls._instance:
                     cls._instance = super(SingletonLogger, cls).__new__(cls)
                     cls._instance._initialize()
         return cls._instance
 
     def _initialize(self):
         self.logger = logging.getLogger("SingletonLogger")
         self.logger.setLevel(logging.DEBUG)
         
         # Create console handler with a higher log level
         ch = logging.StreamHandler()
         ch.setLevel(logging.DEBUG)
         
         # Create formatter and add it to the handlers
         formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
         ch.setFormatter(formatter)
         
         # Add the handlers to the logger
         self.logger.addHandler(ch)
 
     def get_logger(self):
         return self.logger
 
 # グローバル関数からシングルトンロガーを取得する関数
 def get_logger():
     return SingletonLogger().get_logger()

** その65 [#gff1ebff]
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyLogGroup:
    Type: 'AWS::Logs::LogGroup'
    Properties:
      LogGroupName: !Sub '/aws/workspace/${AWS::StackName}-application-log'
      RetentionInDays: 7
 
  CloudWatchAgent:
    Type: 'AWS::SSM::Document'
    Properties:
      DocumentType: 'Command'
      Content:
        schemaVersion: '2.2'
        description: 'Install and configure the CloudWatch Agent'
        mainSteps:
          - action: 'aws:runPowerShellScript'
            name: 'configureCloudWatchAgent'
            inputs:
              runCommand:
                - |
                  $config = @"
                  {
                      "logs": {
                          "logs_collected": {
                              "files": {
                                  "collect_list": [
                                      {
                                          "file_path": "C:\\path\\to\\application.log",
                                          "log_group_name": "/aws/workspace/${AWS::StackName}-application-log",
                                          "log_stream_name": "{instance_id}"
                                      }
                                  ]
                              }
                          }
                      }
                  }
                  "@
                  $config | Out-File -FilePath "C:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\amazon-cloudwatch-agent.json" -Force
                  Start-Service AmazonCloudWatchAgent
                  Write-Host "CloudWatch Agent configured"
 
  WorkspaceInstance:
    Type: 'AWS::WorkSpaces::Workspace'
    Properties:
      BundleId: 'wsb-xxxxxx'  # 置き換え必要
      DirectoryId: 'd-xxxxxx'  # 置き換え必要
      UserName: 'your-username'  # 置き換え必要
      RootVolumeEncryptionEnabled: false
      UserVolumeEncryptionEnabled: false
      VolumeEncryptionKey: ''
      WorkspaceProperties:
        ComputeTypeName: 'STANDARD'
        RootVolumeSizeGib: 80
        UserVolumeSizeGib: 10
        RunningMode: 'AUTO_STOP'
        RunningModeAutoStopTimeoutInMinutes: 60
    DependsOn: CloudWatchAgent
 
  CloudWatchErrorMetricFilter:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      LogGroupName: !Ref MyLogGroup
      FilterPattern: 'ERROR'
      MetricTransformations:
        - MetricValue: '1'
          MetricNamespace: 'MyApp'
          MetricName: 'ErrorCount'
 
  CloudWatchErrorAlarm:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: 'Alarm if there are any ERROR messages in the application log'
      Namespace: 'MyApp'
      MetricName: 'ErrorCount'
      Statistic: 'Sum'
      Period: 300
      EvaluationPeriods: 1
      Threshold: 1
      ComparisonOperator: 'GreaterThanOrEqualToThreshold'
      AlarmActions:
        - !Sub 'arn:aws:sns:${AWS::Region}:${AWS::AccountId}:your-sns-topic'  # 置き換え必要


** その66 [#f039360e]
以下に、CloudFormationテンプレートを使用してIAMロールを作成し、そのロールを使用してWorkspacesで生成されたログファイルをCloudWatchに送信する方法を示します。

CloudFormationテンプレート
このテンプレートは、必要なIAMロールとポリシーを作成し、CloudWatch Logsエージェントの設定ファイルを出力するためのものです。

 AWSTemplateFormatVersion: '2010-09-09'
 Resources:
   CloudWatchLogsIAMRole:
     Type: 'AWS::IAM::Role'
     Properties: 
       AssumeRolePolicyDocument: 
         Version: '2012-10-17'
         Statement: 
           - Effect: 'Allow'
             Principal: 
               Service: 
                 - 'ec2.amazonaws.com'
                 - 'workspaces.amazonaws.com'
             Action: 
               - 'sts:AssumeRole'
       Policies: 
         - PolicyName: 'CloudWatchLogsPolicy'
           PolicyDocument: 
             Version: '2012-10-17'
             Statement: 
               - Effect: 'Allow'
                 Action: 
                   - 'logs:CreateLogGroup'
                   - 'logs:CreateLogStream'
                   - 'logs:PutLogEvents'
                 Resource: 
                   - 'arn:aws:logs:*:*:*'
   CloudWatchLogsAgentConfig:
     Type: 'AWS::SSM::Document'
     Properties:
       DocumentType: 'Command'
       Content:
         schemaVersion: '2.2'
         description: 'CloudWatch Logs Agent configuration document'
         parameters:
           log_group_name:
             type: 'String'
             description: '(Required) CloudWatch Log Group name'
           log_stream_name:
             type: 'String'
             description: '(Required) CloudWatch Log Stream name'
           log_file_path:
             type: 'String'
             description: '(Required) Log file path'
         mainSteps:
           - action: 'aws:configureCloudWatchLogs'
             name: 'configureCloudWatchLogs'
             inputs:
               logGroupName: '{{ log_group_name }}'
               logStreamName: '{{ log_stream_name }}'
               file: '{{ log_file_path }}'
               state: 'Enabled'

手順
CloudFormationテンプレートをデプロイ:

上記のテンプレートを cloudformation-template.yaml という名前で保存し、AWS CloudFormationスタックとしてデプロイします。
AWS CLIを使用してスタックを作成する場合:

 aws cloudformation create-stack --stack-name CloudWatchLogsSetup --template-body file://cloudformation-template.yaml --capabilities CAPABILITY_IAM




CloudWatch Logsエージェントの設定:

Workspaces上でログファイルをCloudWatch Logsに送信するために、CloudWatch Logsエージェントを設定します。
エージェントの設定ファイルは、上記のテンプレートの一部として SSM Document として作成されます。SSMドキュメントを使用してエージェントを設定します。
以下のようにAWS CLIでSSMドキュメントを実行できます:

 aws ssm send-command \
   --document-name "CloudWatchLogsAgentConfig" \
   --targets "Key=instanceIds,Values=your-instance-id" \
   --parameters log_group_name="your-log-group",log_stream_name="your-log-stream",log_file_path="C:\path\to\log\file.log"



CloudWatch Logsエージェントの設定
インストール:

CloudWatch Logsエージェントをインストールします。Windowsの場合、以下のPowerShellコマンドを実行します:

 powershell -Command "Install-Module -Name AWS.Tools.CloudWatchLogs -Force -AllowClobber"


設定ファイル:

設定ファイルを作成します。以下の例では、Windowsのログファイルパスを指定します。

 [general]
 state_file = C:\ProgramData\Amazon\CloudWatchLogs\state
 
 [logstreamname]
 log_group_name = your-log-group
 log_stream_name = your-log-stream
 file = C:\path\to\log\file.log


エージェントの開始:

エージェントを開始します。Windowsの場合、以下のPowerShellコマンドを実行します:

 powershell -Command "Start-Service -Name AmazonCloudWatchAgent"

この手順に従うことで、Workspaces上のログファイルをCloudWatchに送信するための設定を行うことができます。

** その67 [#w7a09e31]
 AWSTemplateFormatVersion: '2010-09-09'
Resources:
  CloudWatchAgentUser:
    Type: 'AWS::IAM::User'
    Properties: 
      UserName: 'CloudWatchAgentUser'
      Policies: 
        - PolicyName: 'CloudWatchAgentAdminPolicy'
          PolicyDocument: 
            Version: '2012-10-17'
            Statement: 
              - Effect: 'Allow'
                Action: 
                  - 'cloudwatch:PutMetricData'
                  - 'cloudwatch:PutDashboard'
                  - 'cloudwatch:GetDashboard'
                  - 'cloudwatch:GetMetricData'
                  - 'cloudwatch:ListMetrics'
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: '*'

** その68 [#e2488c1d]
 import plotly.graph_objects as go
 
 # データ
 months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
 
 # 各グループのデータセット(データの数は任意)
 groups = {
     'Group A': [20, 14, 23, 17, 12, 30, 10, 28, 21, 19, 25, 15],
     'Group B': [12, 18, 29, 14, 22, 19, 9, 16, 18, 21, 17, 20],
     'Group C': [9, 12, 15, 20, 14, 13, 22, 15, 13, 16, 11, 17],
     'Group D': [5, 8, 9, 11, 8, 7, 9, 11, 10, 9, 8, 10],
     'Group E': [10, 15, 8, 12, 14, 11, 12, 9, 11, 8, 9, 10]
 }
 
 # カラーパターンを指定
 colors = ['blue', 'orange', 'green', 'red', 'purple']
 
 # グラフ作成
 fig = go.Figure()
 
 # グループデータを動的に追加する
 for idx, (group_name, values) in enumerate(groups.items()):
     fig.add_trace(go.Bar(
         x=months,
         y=values,
         name=group_name,
         marker_color=colors[idx % len(colors)]  # カラーを循環させる
     ))
 
 # グラフレイアウトの設定
 fig.update_layout(
     barmode='stack',  # 棒を積み上げるモード
     title='Monthly Stacked Bar Chart',
     xaxis_title='Month',
     yaxis_title='Values',
     xaxis_tickangle=-45  # X軸のラベルを傾ける
 )
 
 # グラフを表示
 fig.show()



トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS