BLOG

Plotly.js のカメラ位置をリセットしたい

# React# Next.js# Plotly.js
Plotly.js のカメラ位置をリセットしたい

前提

  • Next.js: v13
  • plotly.js: v2.23
  • react-plotly.js: v2.6
  • グラフを拡大縮小などしてカメラ位置がデフォルトからずれている状態
  • JavaScript の制御によってカメラ位置をデフォルトの位置に戻したい
  • つまるところデフォルト機能のダブルクリックによる位置リセットと同等の挙動をさせたい

答え

<Plot>props で渡す時の layout.xaxis.autorangelayout.yaxis.autorangetrue に変更するだけ😇

// 例:x軸のカメラ位置が常にリセットされる
<Plot layout={{ xaxis: { autorange: true } }}

実際はどう使うか

カメラ位置をリセットしたいタイミングで autorangetrue に更新すれば良い。
自分は React(Next.js) で書いていたので layout 情報を useState で取り回す様にした。
以下実装例

import dynamic from "next/dynamic";
import { Layout, PlotData } from "plotly.js";
import { useState, useEffect } from "react";

// See: https://github.com/plotly/react-plotly.js/issues/21#issuecomment-367452887
const Plot = dynamic(() => import("react-plotly.js"), { ssr: false });

interface Props {
  data: Partial<PlotData>[];
}

const defaultLayout: Partial<Layout> = {/* グラフのモードや色・サイズなど動的に変わらない設定 */}

export function HogeChart({ data = [] }: Props) {
  const [layout, setLayout] = useState(defaultLayout)
  useEffect(() => {
    if (data.length === 0) return null;

    // グラフの描画データが変わったらカメラ位置をリセット
    setLayout({ ...defaultLayout, xaxis: { ...defaultLayout.xaxis, autorange: true } });
  }, [data]);

  if (data.length === 0) return null;

  return (
    <Plot
      data={data}
      layout={layout}
    />
  );
}

なんで詰まってたか

1. autorangetrue に変えて渡すというインターフェースが直感的ではなかった

JSX 的にはスタンダードな指定方法だが、カメラ位置をリセットしたいのはその瞬間なので、API(メソッド)を呼ぶ様なインターフェースがしっくりくる。
autorange: true に変えて渡してしまうと、その後ずっとちょっとスクロールしてもリセットされてしまいそうな感覚が残る。
内部的には autorange: true が渡された時にカメラ位置をリセットし、リセット後に autorange: false に書き換えているっぽい

2. ドキュメントから読み解くのに少々苦労した

他のプロパティにもそれっぽい名前のやつが色々あってややこしかった。
英語力の問題もあるかもしれないが...

サンプルが結構充実している Plotly.js だったが、このカメラ位置のリセットのユースケースに関しては有用なサンプルを見つけることができなかった。

3. デバッグ方法がバカだった

また、元々の実装では layoutuseState に入れていない状態だったし、デバッグする時に下記の様に autorange: true を指定していた

const defaultLayout: Partial<Layout> = {/* グラフのモードや色・サイズなど動的に変わらない設定 */}

export function HogeChart({ data = [] }: Props) {
  if (data.length === 0) return null;

  return (
    <Plot
      data={data}
      layout={{ ...defaultLayout, xaxis: { ...defaultLayout.xaxis, autorange: true }}}
    />
  );
}

解決した後に見るとバカだなーと思う。
でも機能確認でパッと書くからこんな感じで陥るのもそうだよなーと。

上記のデバッグ方法だと、レンダリングのたびに毎回新しい autorange: true が指定されるのであらゆる場面でカメラ位置がリセットされ盛大にバグって混乱していた。


Plotly.js くん、ちょっとややこしいところもあるけどグラフデータ大量でもサクサク動くし機能豊富で好き😘
みんなも使おう!

SHARE

新着記事