背景
- 昨日のエントリーでPixelaを使ってグラフ化・可視化を行った
- やっぱりグラフ化して毎日の記録を見れるのはうれしい
- 年末だけではなくて、毎月やった方が良さそう
- 定期的に印刷して眺めたい欲が出て来た
達成するには
- Pixelaのグラフを画像として取得する
- 画像形式の変換
- 横幅576がMaxなので縦に画像を回転させる必要がある
試してみた
画像の取得
- https://pixe.la/v1/users/XXXX/graphs/test-graph ここで表示される物自体がsvgだった
- https://pixe.la/v1/users/XXXX/graphs/test-graph.svg と明示的に拡張子つけてアクセスが出来た
-CairoSVGというSVGをpngに変換する物があったのでpip install - 単に横に回転させただけだと40cmほどの巨大なレシートグラフになったので、高さを450に指定 - センター寄せ+前後のトリムをかける - 若い芝が見えづらいのでコントラストとシャープネスを調整
from escpos.printer import Serial
from PIL import Image, ImageChops, ImageEnhance
from cairosvg import svg2png
import io
import requests
SVG_URL = "https://pixe.la/v1/users/XXXX/graphs/test-graph.svg"
TARGET_WIDTH = 450 # 回転後の横幅
PRINTER_WIDTH = 576 # 用紙幅(プリンタのドット幅)
def fetch_svg(url: str) -> str:
r = requests.get(url, timeout=10)
r.raise_for_status()
return r.text
def svg_text_to_image(svg_text: str) -> Image.Image:
png_bytes = svg2png(bytestring=svg_text.encode("utf-8"))
img = Image.open(io.BytesIO(png_bytes))
img.load()
return img.convert("L")
def resize_by_width(img: Image.Image, target_w: int) -> Image.Image:
w, h = img.size
if w == target_w:
return img
ratio = target_w / float(w)
new_w = target_w
new_h = int(h * ratio)
return img.resize((new_w, new_h))
def trim_border(img: Image.Image) -> Image.Image:
bg_color = img.getpixel((0, 0))
bg = Image.new(img.mode, img.size, bg_color)
diff = ImageChops.difference(img, bg)
bbox = diff.getbbox()
if bbox:
return img.crop(bbox)
return img
def enhance_image(img: Image.Image) -> Image.Image:
contrast_factor = 1.8
sharpness_factor = 1.5
img = ImageEnhance.Contrast(img).enhance(contrast_factor)
img = ImageEnhance.Sharpness(img).enhance(sharpness_factor)
return img
def center_on_paper(img: Image.Image, paper_width: int) -> Image.Image:
"""
横幅 paper_width のキャンバスを作り、img を中央に貼る
"""
w, h = img.size
if w >= paper_width:
# すでに紙幅以上ならそのまま(もしくは縮小を検討)
return img
left = (paper_width - w) // 2
canvas = Image.new(img.mode, (paper_width, h), 255) # 背景は白
canvas.paste(img, (left, 0))
return canvas
def main():
svg_text = fetch_svg(SVG_URL)
img = svg_text_to_image(svg_text)
# 1. 回転
img = img.rotate(90, expand=True)
# 2. 幅450にリサイズ
img = resize_by_width(img, TARGET_WIDTH)
# 3. 余白トリム(縦の無駄を削る)
img = trim_border(img)
# 4. コントラスト・シャープネス調整
img = enhance_image(img)
# 5. 用紙幅576pxの中央に配置
img = center_on_paper(img, PRINTER_WIDTH)
# 6. 印刷
p = Serial(devfile="/dev/ttyACM0", baudrate=9600)
p.image(img)
p.cut()
if __name__ == "__main__":
main()
iPhone/iPadからの呼出
-ショートカットアプリで下記を作成

出力!

振り返り
白黒でも十分芝の生え具合が確認できた!最終的には30cmのレシートになったが、幅がワンサイズ小さい感熱紙でやると上下の余白が小さくなり横も短くなりそう。
ホワイトボードに貼って今年から頑張っている姿を見るとうれしい!今回ボルダリングの行った回数のグラフにしたが、いろんな毎日の積み重ねの記録に使えそう。いろいろ試していく!!