Streamlit×Canvaによる新しいダッシュボードの可能性

## Canvaとは

> *信じられないほど、素晴らしく* ――― Canva

Canvaは、2013年にオーストラリアで誕生した、誰でも簡単に使えるデザインプラットフォームです。豊富なテンプレートと素材を活用することで、デザインの知識がなくても、プロフェッショナルな見た目のデザインを作成できます。  
特徴として、  

- ブラウザ上で利用可能でインストール不要
- 操作が直感的で簡単  
- たくさんの無料テンプレートが用意されている

…などが挙げられます。  
SNS投稿、プレゼン資料、チラシ、バナーなど、様々な用途に対応しており、個人利用から商用利用まで幅広く活用できます！  
基本機能は無料で利用可能で、スマートフォンやタブレットにも対応しているため、場所を選ばずデザインできるのも嬉しいですね。  

https://www.canva.com/

## デモ

https://x.com/AkSakatoku/status/1871368726739816495

今回は地図をクリックしたとき、それに対応してデザインを表示してみました。  
このようにダッシュボードを操作したときに必要に応じてデザインを表示することができます。  
今回は観光地のPRみたいなイメージで作ってみましたが、例えば社内向けのダッシュボードで特定のボタンを押したときにマニュアルを表示する、みたいなこともできるかも。  

## 実装

以下のように実装しました。  

```py:canva_with_streamlit.py
import streamlit as st
import pydeck as pdk
import streamlit.components.v1 as components

st.set_page_config(page_title="Canva with Streamlit", layout="wide")

st.title('Canva with Streamlit')

# 東京と大阪のPOIを用意
data = [
    {"latitude": 35.6895, "longitude": 139.6917, "name": "東京", "population": 14183261},
    {"latitude": 34.6937, "longitude": 135.5023, "name": "大阪", "population": 8773053},
]
for row in data:
    row["size"] = row["population"] / 400

# レイヤーを設定
layer = pdk.Layer(
    "ScatterplotLayer",
    data=data,
    get_position="[longitude, latitude]",
    get_color="[200, 30, 0, 160]",
    get_radius="size",
    pickable=True,
    auto_highlight=True,
    id="map",
)

# 初期表示の設定
view_state = pdk.ViewState(
    latitude=35.6895,
    longitude=139.6917,
    zoom=6,
)

# Pydeckチャートを表示
chart = pdk.Deck(
    layers=[layer],
    initial_view_state=view_state,
    map_style=None,
)

event = st.pydeck_chart(
    chart,
    selection_mode="single-object",
    on_select="rerun",
    width=1024,
    height=280,
)

# 選択されたPOIを表示
selected_poi_idx = None
if event.selection:
    if event.selection["indices"] is not None:
        if "map" in event.selection["indices"]:
            selected_poi_idx = event.selection["indices"]["map"][0]
            st.write(data[selected_poi_idx])

# Canvaの埋め込み
html_code_tokyo = """
<div style="position: relative; width: 100%; height: 0; padding-top: 56.2500%;
 padding-bottom: 0; box-shadow: 0 2px 8px 0 rgba(63,69,81,0.16); margin-top: 1.6em; margin-bottom: 0.9em; overflow: hidden;
 border-radius: 8px; will-change: transform;">
  <iframe loading="lazy" style="position: absolute; width: 100%; height: 100%; top: 0; left: 0; border: none; padding: 0;margin: 0;"
    src="https://www.canva.com/design/DAGaIVf20rQ/1xoOrZ93kSvmH1CfE_k8sw/view?embed" allowfullscreen="allowfullscreen" allow="fullscreen">
  </iframe>
</div>
"""
html_code_osaka = """
<div style="position: relative; width: 100%; height: 0; padding-top: 56.2500%;
 padding-bottom: 0; box-shadow: 0 2px 8px 0 rgba(63,69,81,0.16); margin-top: 1.6em; margin-bottom: 0.9em; overflow: hidden;
 border-radius: 8px; will-change: transform;">
  <iframe loading="lazy" style="position: absolute; width: 100%; height: 100%; top: 0; left: 0; border: none; padding: 0;margin: 0;"
    src="https://www.canva.com/design/DAGaIZun0l8/MtuzpkARbywZHwzkHGESxQ/view?embed" allowfullscreen="allowfullscreen" allow="fullscreen">
  </iframe>
</div>
"""

# 選択されたPOIに応じてCanvaを表示
if selected_poi_idx is not None:
    if selected_poi_idx == 0:
        html_code = html_code_tokyo
    elif selected_poi_idx == 1:
        html_code = html_code_osaka
    components.html(html_code, width=1024, height=800)
```

地図を表示するための```st.pydeck_chart```が大部分を占めていますが、重要なのはCanvaの埋め込みコード(```html_code_*```)を```streamlit.components.v1.html```に渡しているところです。  
この関数はDeprecatedな機能ですが、```st.html```がセキュリティ上の理由でJavaScriptに非対応なのでこちらを使いました。  

## まとめ

勉強しているものと勉強しているものを組み合わせたら何かできるんじゃね？くらいのネタですが、何かに使えそうな気がしますよね！  
Canvaは多彩な共有手段であちこちにデザインを展開できるのが便利。  
また、StreamlitもCanvaに限らずHTMLを埋め込むことで色々な拡張ができそうだと感じました。この組み合わせ、気に入ったらぜひ用途を考えてみてください！