はじめに
- Yahoo!ローカルサーチAPIで牛丼チェーン店の位置情報を取得してdeck.glで表示してみました。
- Yahoo!ローカルサーチAPIでは「丼もの、牛丼、親子丼(業種コード:0101031)」で絞り込み、位置情報を取得しています。
- 取得した牛丼チェーン店の位置情報はエクセル等で「すき家」「吉野家」「松屋」で抽出してdeck.glで表示しています。
アウトプットイメージ
YahooローカルサーチAPIで牛丼チェーン店の位置情報を取得して https://t.co/j5x1odcLvTで表示してみた。すき家:赤色、松屋:橙色、吉野家:緑色。吉野家はデータに抜けがあるため参考。すき家は郊外型、松屋は鉄道沿線型という棲み分けが見えたかな。三大都市圏は同様の傾向。牛丼食べたい。#Mapbox https://t.co/plH5GpH7mf pic.twitter.com/T221y8tzvr
— shi_works☀ (@syanseto) September 6, 2021
前提条件
- Yahoo!ローカルサーチAPIのアプリケーションIDが必要です。
- 都道府県ごとに位置情報を取得して出力しているため、都道府県コードのリストが必要です。
- 都道府県コードのリスト(PrefCode.csv)は以下のとおりとします(01:北海道~47:沖縄県)。
- 今回は、業種コードが「0101031(丼もの、牛丼、親子丼)」を用いていますが、業種コードは変更可能です。
- 業種コードはこちらで確認することができます。
python
localSearchAPI.py
import json
import socket
import urllib.error
import urllib.request
import csv
# Yahoo!ローカルサーチAPI
baseurl = 'https://map.yahooapis.jp/search/local/V1/localSearch'
# アプリケーションIDを指定
appid = 'Yahoo!ローカルサーチAPIのアプリケーションIDを入力してください'
# 都道府県コードのリストを作成する
PrefCodelist = []
# csvファイル(都道府県コードのリスト)の読み込み
with open('都道府県コードのリスト(PrefCode.csv)のパスを入力してください') as f:
header = next(csv.reader(f))
for row in csv.reader(f):
s = row[0]
PrefCodelist.append(s)
print(PrefCodelist)
# 都道府県コードのリストの数でループ
for PrefCode in PrefCodelist:
# 出力csvファイルの指定
output_csvfile = "出力フォルダのパスを入力してください" + "/" + PrefCode + ".csv"
result = []
i = 1
total = 3102
while i < total:
params = {
'appid': appid,
'ac': str(PrefCode), # 住所コード(都道府県コード)
'gc': '0101031', # 業種コード(丼もの、牛丼、親子丼)
'output': 'json',
'sort': 'score',
'start': i,
'results': 100
}
url = '{}?{}'.format(baseurl, urllib.parse.urlencode(params))
req = urllib.request.Request(url)
with urllib.request.urlopen(req, timeout=3) as res:
data = res.read()
# print(data)
ydf = json.loads(data)
# print(ydf)
# Count(データ件数)取得
Count = ydf['ResultInfo']['Count']
# Countがゼロの場合、ループを抜ける
if Count == 0:
break
features = ydf['Feature']
for f in features:
if f['Geometry']['Type'] == 'point':
latlng = f['Geometry']['Coordinates'].split(',')
poi = {
'uid': f['Property']['Uid'], # ユニークID
'name': f['Name'], # 地域・拠点情報名
'address': f['Property']['Address'], # 住所
'lat': latlng[1], # 緯度
'lng': latlng[0] # 経度
}
result.append(poi)
i += 100
# 出力ファイルオープン
with open(output_csvfile, 'a', encoding='cp932') as f:
# ヘッダー行出力
fieldnames = ['i', 'uid', 'name', 'address', 'lat', 'lng']
# writeオブジェクト作成
csvfile_writer = csv.DictWriter(
f, fieldnames=fieldnames, lineterminator='\n')
csvfile_writer.writeheader()
for j, poi in enumerate(result, 1):
csvfile_writer.writerow({
'i': j,
'uid': poi['uid'],
'name': poi['name'],
'address': poi['address'],
'lat': poi['lat'],
'lng': poi['lng']
})
print(u'処理終了')
deck.gl
- 上記で取得した牛丼チェーン店の位置情報(csvファイル)をdeck.glで表示します。
- Mapboxのアクセストークンが必要になります。
- 牛丼チェーン店の位置情報(csvファイル)をdeck.glで表示するためにQGIS等でgeojson形式(yahoo_gc0101031_MergeFile.geojson)に変換しています。
- また、国土数値情報の鉄道データ(令和元年)から鉄道路線のラインデータ(N02-19_RailroadSection.geojson)を読み込んでいます。
html
Yahoo_Gyudon_chain_store.html
<html>
<head>
<title>牛丼チェーン店の立地状況(Yahoo!ローカルサーチAPI)</title>
<meta charset="UTF-8">
<script src="https://unpkg.com/deck.gl@^7.0.0/dist.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="tooltip"></div>
<script src="script.js"></script>
</body>
</html>
CSS
style.css
html,body {
font-family: Helvetica, Arial, sans-serif;
width: 100vw;
height: 100vh;
margin: 0;
}
.deck-tooltip {
font-family: Helvetica, Arial, sans-serif;
padding: 6px !important;
margin: 8px;
max-width: 300px;
font-size: 20px;
}
#control-panel {
position: absolute;
top: 0;
left: 0;
margin: 12px;
padding: 20px;
font-size: 12px;
line-height: 1.5;
z-index: 1;
background: #fff;
font-family: Helvetica, Arial, sans-serif;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.15);
}
label {
display: inline-block;
width: 140px;
}
javascript
script.js
const deckgl = new deck.DeckGL({
mapboxApiAccessToken: 'Mapboxのアクセストークンを入力してください',
mapStyle: 'mapbox://styles/mapbox/dark-v9',
// mapStyle: 'mapbox://styles/mapbox/streets-v9',
initialViewState: {
latitude: 35.1801494,
longitude: 136.9034925,
zoom: 5,
maxZoom: 16
},
controller: true,
});
const railway = d3.json('data/N02-19_RailroadSection.geojson');
const yahoo = d3.json('data/yahoo_gc0101031_MergeFile.geojson');
const renderLayer = () => {
const LINE_COLOR_SCALE = d3.scaleLinear()
.domain([1, 2, 3])
.range([
[216, 25, 0],
[0, 65, 33],
[255, 217, 58]
]);
const FILL_COLOR_SCALE = d3.scaleLinear()
.domain([1, 2, 3])
.range([
[255, 204, 216],
[216, 255, 204],
[255, 255, 204]
]);
const geoJsonLayer_1 = new deck.GeoJsonLayer({
id: 'railway-geojson',
data: railway,
stroked: false,
filled: false,
lineWidthMinPixels: 1,
parameters: {
depthTest: false
},
opacity: 0.5,
getLineColor: [240, 240, 240],
getLineWidth: 1,
pickable: false,
});
const geoJsonLayer_2 = new deck.GeoJsonLayer({
id: 'yahoo-geojson',
data: yahoo,
lineWidthMinPixels: 2,
pointRadiusUnits: 'meters',
pointRadiusScale: 20,
getRadius: 50,
getLineColor: d => LINE_COLOR_SCALE(d.properties.flg),
getFillColor: d => FILL_COLOR_SCALE(d.properties.flg),
opacity: 0.5,
pickable: true
});
deckgl.setProps({
layers: [geoJsonLayer_2, geoJsonLayer_1],
getTooltip: ({ object }) => object && `${object.properties.name}`
});
}
renderLayer();
参考文献