背景
- 空間的な温度分布や白黒画像のピクセル配列などのように、二次元配列を画像として可視化したい場合がある。
- Pythonではmatplotlib.pyplot.imshow()を使えば良いが、JavaScriptでブラウザ上に可視化したい
1. Reactを使う場合
1.1. 実装
可視化したい配列とカラースケールをprops
として与えることで描画を行うコンポーネントを実装する。内部ではcanvasのImageDataオブジェクトを利用してピクセルを操作している。
Imshow.jsx
import React from "react";
import * as d3 from "d3";
export default class Imshow extends React.Component {
componentDidMount() {
this.imshow();
}
componentDidUpdate(prevProps) {
if ( (this.props.data!==prevProps.data) || (this.props.interpolate!==prevProps.interpolate) ) {
this.imshow();
}
}
imshow = () => {
const canvas = this.refs.canvas;
// Square only
const resolution = Math.sqrt(this.props.data.length);
["width", "height"].forEach(a => canvas.setAttribute(a, resolution));
const context = canvas.getContext("2d");
const imageData = context.createImageData(resolution, resolution);
this.props.data.forEach((d, i) => {
let color = isNaN(d) ? {r: 0, g: 0, b: 0} : d3.color(this.props.interpolate(d));
imageData.data[i*4 ] = color.r;
imageData.data[i*4+1] = color.g;
imageData.data[i*4+2] = color.b;
imageData.data[i*4+3] = 255;
});
context.putImageData(imageData, 0, 0);
}
render() {
return (
<canvas style={{ width: "100%", height: "100%" }} ref="canvas" />
);
}
}
1.2. 例
複素対数関数のDomain Coloringや富士山の標高に利用すると以下のようになる。
ソースコードはGitHubにある(複素対数関数, 富士山)が、データさえ用意できれば以下のような感じで使える。
<Imshow data={this.state.imshowData} interpolate={this.state.colorScale}/>
1.3. 注意点
上記の実装では、
- 可視化する配列
props.data
は一次元配列で、正方形の可視化に限る(従って要素数は自然数の二乗である前提)- 二次元配列
d
を可視化したければ[].concat.apply([], d)
で 一次元に変換できる
- 二次元配列
- 配列のshapeと画面上のピクセル数は独立に設定できる
-
width
,height
を100%に設定しているため、画面上のピクセル数は親要素によって規定される - 画面上のピクセル数に対して配列が小さければ当然解像度は低くなる
-
- カラースケール
props.interpolate
は、props.data
の値を色に変換する関数- d3.jsのカラースケールを使うのが簡単だが、これは引数が0-1になっていることを前提としているので適宜スケールを調整する
という点に注意。拡張が必要であれば簡単に実装できるはず。
2. Reactを使わない場合
要するにcanvas要素のピクセル値を指定しているだけなので、「Reactを使う場合」のimshow()
内とほぼ同じ。ソースコードは省略するが、this.props.***
を変数に置き換えたり、this.refs.canvas
をdocument.getElementBy***
のようにしたりすれば良いと思う。