1年9ヶ月前との比較： ChatGPT でグラフ作成と PowerPoint のスライド化（ダウンロードできるファイルの生成）

## はじめに

2023年の7月に、ChatGPT の Plusプランユーザー向けに Code Interpreter（Advanced Data Analysis）がリリースされた際、以下の記事に書いた内容を試していました。
※ 内容は「Python での QRコード生成」、「グラフを作成して、そのグラフをのせたダウンロード可能な PowerPoint のスライドを生成してもらう」でした

●ChatGPT Plusユーザー向けの Code Interpreter で QRコード生成を試す！（Pythonの qrcode パッケージを使用した処理） - Qiita
　https://qiita.com/youtoy/items/89a944fc9125ee6b8426

●ChatGPT Plus で使える Code Interpreter でのグラフ描画と PowerPoint のスライド化（ダウンロードできるファイルの生成） - Qiita
　https://qiita.com/youtoy/items/c9a4ca1bf864ed4ad766

このダウンロード可能な PowerPoint のスライド生成について、最近リリースされたばかりの o3・o4-mini などのモデルだと、当時よりかなり整ったものが作れるのではないか、と思って試してみます。

### 当時の公式のポスト

当時、Code Interpreter がリリースされた際、公式のポストで QRコードを生成した事例がポストされたりしていました。

https://x.com/OpenAI/status/1677015057316872192

その際、公式のデモの内容を見つつ、自分でも画像生成などを試していました。


### ChatGPT などを使ったスライド生成の別の方法

なお今回は扱わないですが、ChatGPT などの生成AI でスライドを作成する方法は、他にもあります。
一例として、テキストベースの出力（スライドにできるもの）を得て、それをスライドに変換する方法があります。

例えば、生成AI で以下の Marp CLI などに入力する、スライド作成用になっている Markdown を得て、そして PowerPoint に変換する方法があるかと思います。

●Marp CLI v4.1.0 に新しく追加された「編集可能な PowerPointファイルの出力」を試してみた - Qiita
　https://qiita.com/youtoy/items/e7168d762d3fe909d278


## 実際に試してみる
### 今回試す内容

今回試す内容は、2023年7月に試したものとほぼ同じ内容にしています。

- グラフ描画のプロンプト
   - 1/sin(x)のグラフを描画して
   - 0から1の範囲をズームして描画して
- スライド作成
   - 先ほどのグラフの画像をPowerPointのファイルにして
   - 先ほどのグラフの画像をPowerPointのファイルにして。その画像の上に「1/sin(x)のグラフ」と書いたテキストボックスを置いて

上記のグラフ描画のプロンプトは、当時の公式のデモ動画を参考にして作ったものです。公式のデモで、「plot function 1/sin(x)」「zoom in to range of x value between 0 and 1」というプロンプトを使っていたのを見かけて、それを少し変えたり日本語にしたりして試していました。

そして、それを PowerPoint のファイルにするということも試してみていました。
以前のお試しで使っていたプロンプトの中で「グラフ画像の大きさは、スライドの半分くらいのサイズにしてください。」というものがあったのですが、今回は自動でサイズ調整の処理が入っていたので、今回のプロンプトからその部分は省いています。



### 試した結果

#### 利用したモデル

今回、直近でリリースされたモデルである o3・o4-mini のうち、o4-mini を使って試しました。


#### グラフの作成

まずはグラフ作成の 1つ目です（プロンプト： 1/sin(x)のグラフを描画して）。
以下のとおり、きれいなグラフが描画されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/5428be79-7464-4ed6-8c03-c14148ff0676.png)

ちなみに、1年9ヶ月前もきれいなグラフが出力されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/fae71317-80e3-4b09-862d-6387b81561f9.png)

前回との差分として、今回は「以下のインタラクティブな要素が入ったグラフになっている」というものがありました。

<iframe width="560" height="315" src="https://www.youtube.com/embed/-vTvXyjYA4U?si=FMfsdERNFZTRcEy0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>


続きも試します。
プロンプトは「0から1の範囲をズームして描画して」で、以下のとおりグラフが描画されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ce87589e-c75a-4115-9d96-c84ca83a7594.png)

これは前回も、きれいなグラフが得られていたところでした。



#### スライドの作成

残りのスライド作成を試します。
こちらは前回は、以下のようにオブジェクトの配置やそのサイズに関して、微妙な部分があったところです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/87ad5400-340e-413b-b1ea-fd9093382bf8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/6b45a194-505d-4c29-8cda-975d047cf0f9.png)



今回のプロンプトを入れた後の状態は以下のとおりで、ダウンロードできるファイルが生成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1738f893-f022-45a0-a670-87b4e2f3d312.png)


ダウンロードした PowerPointのファイル 2つの内容を以下に示します。
サイズは少し小さめにされていて、2つ目のほうのファイルではテキスト追加も良い感じになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/601d950c-81d0-4e6f-8b09-d02e1be6423d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/cbc9da16-98a6-422b-8a21-36dfd0406ed0.png)


試す前に想像がついてはいましたが、Code Interpreter（Advanced Data Analysis）の処理がパワーアップしていそうです。

今回の内容は、o3・o4-mini が o1 などより良い感じの処理ができるようになった、という話を見かけたのがきっかけで試したものでした。


## おわりに

1年9ヶ月前に、ChatGPT で Python を使った内部処理が初めて行われるようになった時と、今現在とで簡単なグラフ作成・生成したグラフを含んだ PowerPoint のスライド作成を試しました。

現在だと、もちろんもっと複雑な処理や、複数毎にわたるスライドの生成など、より複雑な処理もこなせるかと思うので、それも試せればと思います



## その他

その他、今回のグラフ作成などで、裏で生成されていたコードを掲載してみます。

### グラフ作成

#### グラフ 1つ目

```python
import numpy as np
import matplotlib.pyplot as plt

# x range from -2π to 2π, dense sampling
x = np.linspace(-2 * np.pi, 2 * np.pi, 10000)
y = 1 / np.sin(x)

# Mask to avoid plotting near singularities
mask = np.abs(np.sin(x)) > 0.01
x_plot = x[mask]
y_plot = y[mask]

plt.figure()
plt.plot(x_plot, y_plot)
# Plot vertical dashed lines at x = nπ to indicate asymptotes
for k in range(-2, 3):
    plt.axvline(k * np.pi, linewidth=0.5, linestyle='--')
plt.xlim(-2 * np.pi, 2 * np.pi)
plt.ylim(-10, 10)
plt.title('y = 1/sin(x)')
plt.xlabel('x')
plt.ylabel('1/sin(x)')
plt.show()
```


#### グラフ 2つ目

```python
import numpy as np
import matplotlib.pyplot as plt

# x range from 0 to 1, dense sampling
x = np.linspace(0, 1, 5000)
y = 1 / np.sin(x)

# Mask to avoid plotting too-close-to-singularity values
mask = np.abs(np.sin(x)) > 0.01
x_plot = x[mask]
y_plot = y[mask]

plt.figure()
plt.plot(x_plot, y_plot)
# Plot vertical dashed line at x = 0 to indicate asymptote
plt.axvline(0, linewidth=0.5, linestyle='--')
plt.xlim(0, 1)
plt.ylim(-10, 10)
plt.title('y = 1/sin(x) （0 ≤ x ≤ 1）')
plt.xlabel('x')
plt.ylabel('1/sin(x)')
plt.show()
```

以下の情報も出力されていました。

```zsh
STDOUT/STDERR
/tmp/ipykernel_12/1829742448.py:6: RuntimeWarning: divide by zero encountered in divide
  y = 1 / np.sin(x)
/home/sandbox/.local/lib/python3.11/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 65288 (\N{FULLWIDTH LEFT PARENTHESIS}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
/home/sandbox/.local/lib/python3.11/site-packages/IPython/core/pylabtools.py:170: UserWarning: Glyph 65289 (\N{FULLWIDTH RIGHT PARENTHESIS}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
```


### PowerPoint のファイルの生成

#### PowerPoint のファイル生成 1つ目

```python
import numpy as np
import matplotlib.pyplot as plt
from pptx import Presentation
from pptx.util import Inches

# 1. グラフを再生成して画像として保存
x = np.linspace(0, 1, 5000)
y = 1 / np.sin(x)
mask = np.abs(np.sin(x)) > 0.01
x_plot = x[mask]
y_plot = y[mask]

fig, ax = plt.subplots()
ax.plot(x_plot, y_plot)
ax.axvline(0, linewidth=0.5, linestyle='--')
ax.set_xlim(0, 1)
ax.set_ylim(-10, 10)
ax.set_title('y = 1/sin(x) （0 ≤ x ≤ 1）')
ax.set_xlabel('x')
ax.set_ylabel('1/sin(x)')
fig.savefig('/mnt/data/graph_zoom.png', dpi=300)
plt.close(fig)

# 2. PowerPoint ファイルを作成し、画像を貼り付け
prs = Presentation()
blank_slide_layout = prs.slide_layouts[6]  # 空白レイアウト
slide = prs.slides.add_slide(blank_slide_layout)
left = top = Inches(1)
slide.shapes.add_picture('/mnt/data/graph_zoom.png', left, top, width=Inches(8))
prs.save('/mnt/data/graph.pptx')

# 完成したファイルへのパスを表示
print("Created PowerPoint at /mnt/data/graph.pptx")
```

以下の情報も出力されていました。

```zsh
STDOUT/STDERR
/tmp/ipykernel_12/2629155840.py:8: RuntimeWarning: divide by zero encountered in divide
  y = 1 / np.sin(x)
/tmp/ipykernel_12/2629155840.py:21: UserWarning: Glyph 65288 (\N{FULLWIDTH LEFT PARENTHESIS}) missing from current font.
  fig.savefig('/mnt/data/graph_zoom.png', dpi=300)
/tmp/ipykernel_12/2629155840.py:21: UserWarning: Glyph 65289 (\N{FULLWIDTH RIGHT PARENTHESIS}) missing from current font.
  fig.savefig('/mnt/data/graph_zoom.png', dpi=300)
Created PowerPoint at /mnt/data/graph.pptx
```


#### PowerPoint のファイル生成 2つ目

```python
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.enum.text import PP_ALIGN

# Load the existing presentation
prs = Presentation('/mnt/data/graph.pptx')
slide = prs.slides[0]

# Add a text box above the image
left = Inches(1)
top = Inches(0.2)
width = Inches(8)
height = Inches(0.5)
txBox = slide.shapes.add_textbox(left, top, width, height)
tf = txBox.text_frame
p = tf.paragraphs[0]
p.alignment = PP_ALIGN.CENTER
run = p.add_run()
run.text = "1/sin(x)のグラフ"
run.font.size = Pt(24)

# Save the updated presentation
prs.save('/mnt/data/graph_with_title.pptx')

# Provide the output path
print("Created PowerPoint at /mnt/data/graph_with_title.pptx")
```

以下の情報も出力されていました。


```zsh
STDOUT/STDERR
Created PowerPoint at /mnt/data/graph_with_title.pptx
```