Skip to content

Instantly share code, notes, and snippets.

@Kenji-Hata
Last active January 9, 2024 15:26
Show Gist options
  • Save Kenji-Hata/52e3f3d05b97f16450e67ca2cacf591e to your computer and use it in GitHub Desktop.
Save Kenji-Hata/52e3f3d05b97f16450e67ca2cacf591e to your computer and use it in GitHub Desktop.
Create a plotly graph for embedding in zenn.
import textwrap
from pathlib import Path
from typing import Tuple
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from bs4 import BeautifulSoup
from scipy.interpolate import RectBivariateSpline
def create_sample_data(n: int = 25):
# データセットの取得
z = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv",
).values
# テスト用のデータ水増し
x = np.linspace(0, 1, n)
y = np.linspace(0, 1, n)
z = RectBivariateSpline(
x=np.linspace(0, 1, z.shape[0]),
y=np.linspace(0, 1, z.shape[1]),
z=z,
)(x, y)
return x, y, z
def to_full_html(div: str, margin: str = "0", overflow: str = "auto") -> str:
"""グラフの div タグを埋め込み用にカスタマイズする。
Args:
div: 入力の div タグの中身。
margin: グラフの外側に付くマージン。0 を指定するとマージンなしになる。
overflow: スクロールバーの挙動を制御する。hidden を指定すると(スクロールバーが必要でも)表示しない。
Returns: 生成した html 文字列。
"""
return textwrap.dedent(
f"""\
<html>
<head><meta charset="utf-8" /></head>
<body style="margin: {margin}; overflow: {overflow}">
{div}
</body>
</html>
"""
)
def separate_js(html_content: str, js_src: str) -> Tuple[str, str]:
"""HTML と JavaScript を分離して返す。
Args:
html_content: HTML 文字列。
js_src: 分離した JavaScript コードの置換対象。
<script src="{js_src}"></script> に置き換えられる。
Returns: JavaScript を取り除いた HTML 文字列と、分離した JavaScript 文字列のタプル。
"""
html = BeautifulSoup(html_content, "html.parser")
# グラフデータを含む script タグを探す。
# この機能を使うのはサイズが大きい時なので、一番サイズが大きいものにする。
graph_script = max(html.find_all("script"), key=lambda s: len(s.string or ""))
# タグの分離と差し替え。
graph_content = graph_script.string.strip()
graph_script.clear()
graph_script["src"] = js_src
return str(html), graph_content
def main():
output_html = Path("./temp.html")
# output_js = Path("./temp.js")
data_size = 25
# データ生成。
x, y, z = create_sample_data(n=data_size)
# 適当な桁数で丸める。必要な桁数はデータ次第なので要確認。
x = x.round(3)
y = y.round(3)
z = z.round(1)
# グラフの作成。
fig = go.Figure(
data=[go.Surface(x=x, y=y, z=z)],
layout=go.Layout(
margin={"l": 0, "r": 0, "b": 0, "t": 0}, # マージンの除去。
# paper_bgcolor="lightgray", # 背景色
),
)
# HTML化。加工するので div タグだけ生成する。
div = fig.to_html(
full_html=False,
include_plotlyjs="cdn",
# サイズを指定する場合はここで。埋め込みの大きさではないので注意。
# スクロールバーを表示させたくない場合は下記の設定を使う。
# codepen: "351px"
# jsfiddle: "381px"
# default_width="100%",
# default_height="100%",
# ダウンロードボタンを無効化する。
# config={"modeBarButtonsToRemove": ["toImage"]},
)
html = to_full_html(
div,
overflow="hidden",
)
# HTML と JavaScript を分離したい場合こうする。
# html, js = separate_js(html, js_src=str(output_js))
output_html.write_text(html)
# output_js.write_text(js)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment