【D3.js】約97,000件の位置情報を地図にプロットしてみた。
医療経済研究機構にて、公開されている「全国保険薬局一覧」と「全国保険医療機関(病院・診療所)一覧」データをD3.jsを使って地図上にプロットしてみた。
データの数は、保険薬局一覧が56,341件、医療機関一覧が95,762件となっている。
保険薬局一覧(56,341件)
1万件を超えるとSVGではレンタリングの負荷が高すぎてまったく動かない。パン/ズームに対応させるためにはcanvasを使う必要がある。CanvasRenderingContext2Dインターフェイスの、drowing機能を使って保険薬局位置を描画した。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
d3.select("canvas") .call(zoom.on("zoom", zoomed)) .call(zoom.event); function zoomed() { translate = zoom.translate(); scale = zoom.scale(); context.clearRect(0, 0, width, height); context.save(); context.beginPath(); path(topo); context.fillStyle = "#222"; context.fill(); context.closePath(); PHA.forEach(function(d){ context.beginPath(); var point = projection([d.X, d.Y]) // context.arc(~~(point[0]* scale + translate[0]), ~~(point[1]* scale + translate[1]), 0.5, 0, Math.PI*2, false) // 遅い context.rect(~~(point[0]* scale + translate[0]), ~~(point[1]* scale + translate[1]), 1, 1); context.fillStyle = "#f00"; context.fill(); context.closePath(); }) context.restore(); } |
全体的に結構重い。rect(四角)ではなく、arc(円)を使って描画するとさらに遅くなる。
医療機関一覧データはさらに件数が多いので、別の手段を使って描画する。
全国保険医療機関一覧(95,762件)
日本列島はsvgで描画し、その上に重ねたcanvasのイメージデータを取得してピクセルの値を直接変更する方法で描画した。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
d3.select("body") .call(zoom.on("zoom", zoomed)) .call(zoom.event) function zoomed() { var canvasWidth = width var canvasHeight = height var ctx = context var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight) var buf = new ArrayBuffer(imageData.data.length) var buf8 = new Uint8ClampedArray(buf) var ndata = new Uint32Array(buf) translate = zoom.translate() scale = zoom.scale() hosp.forEach(function(d){ var point = projection([+d.X, +d.Y]) var x = ~~(point[0]* scale + translate[0]) var y = ~~(point[1]* scale + translate[1]) if (x > width || y > height || x < 0 || y < 0) return ndata[y * canvasWidth + x] = (255 << 24) | // alpha (0x99 << 16) | // blue (0xff << 8) | // green 0x99 }) imageData.data.set(buf8) ctx.putImageData(imageData, 0, 0) base.attr({ d:path, fill:"#222", stroke:"#000" }) } |
この方法だと、位置をドットとしてしか表現できないが、早い。