地域課題を探る課題で、住んでいる八王子市内の各地域の人口増減がどうなっているか調査していました。
表データとしてではなく地理的な特徴をみたいと思い、Gemini 2.5 Proに依頼したところ、まさかの たった1時間 でGoogle Map APIを使ったヒートマップができあがりました。
生成AIを活用することで、エクセルだけでは難しいグラフィカルな表現も簡単に実現可能になりましたが、手順的な注意点もあるので、紹介します。
住んでいる地域を調べる課題
今年から事業構想大学院のプロジェクト研究員になり、地域の課題を事業構想で解決するプロジェクトに取り組んでいます。
そのプロジェクトの課題として出されたのが住んでいる地域の課題を探ることでした。
現在私は八王子市に住んでいるので、八王子市公式ホームページに掲示されている統計データを調べました。
八王子市としては人口減少が始まっていますが、八王子のあらゆる地域で人口減少しているわけではありません。
人口が増えているエリアもあり、人口減少地域との差異が課題へのアプローチになるのではと仮説を立てました。
当初はエクセルで増減を算出
八王子市の統計データには毎年、月毎の町丁別の人口データが掲示されていたので、2021年4月→2025年4月の人口を調べ、増減を算出しました。
当初は統計データから町丁別の人口増減をエクセルでまとめていただけでした。
町丁によっては人口が増えている地域も判明し、町丁の並びで関連性はある程度把握できたものの、八王子市は東京都で最も面積が大きく、自分が住んでいるエリア以外の地理はそこまで理解できていません。
そのため、人口増減に関する地理的な特性まではつかむことがエクセルでは困難でした。
人口増減をヒートマップで表現
しかし地理的な特性は地域の課題を探る上で知りたいポイントです。
ただ、エクセルでは市区町村よりも小さいエリアでのヒートマップは対応してなさそうでした。
そこで、Google MapのAPIで増減を地図上にプロットしてヒートマップで見てみたいなと考えました。
Googleマップでそれぞれの町丁の緯度経度に人口増減の数値をプロットすれば、地域特性をつかめると考えました。
Gemini 2.5 ProにGoogleマップのヒートマップを依頼
そこで生成AIにGoogleマップのヒートマップを作ってもらう作戦をとりました。
Googleマップなので生成AIのチョイスとしては、同じくGoogleのGemniの中で上位モデルを採用しました。
以下の流れで作成を依頼しました。
1.Geminiに町丁別名リストを提示して緯度・経度を出力依頼
以下は東京都八王子市の町丁リストです。それぞれの緯度・軽度をテーブル形式でスプレッドシートに貼り付けられるフォーマットで出力してください。
【八王子市の町丁リスト】
2.「町丁名、緯度、経度、人口増減」からGoogleマップのヒートマップを表示するJavascriptを作成依頼
下記の八王子の人口増減をGoogleマップのヒートマップ機能を使い、Javascriptで表現したいです。
そのためのコードを生成してください。
【八王子市の町丁別人口増減データ】
生成されたヒートマップのコード
<!DOCTYPE html>
<html>
<head>
<title>八王子市 人口増減ヒートマップ</title>
<style>
/* Mapのサイズを画面全体に設定 */
#map {
height: 100%;
}
/* HTMLとBodyの余白をなくす */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
/* 凡例のスタイル */
#legend {
position: absolute;
bottom: 20px;
left: 10px;
background: rgba(255, 255, 255, 0.9);
padding: 10px;
border: 1px solid #777;
border-radius: 5px;
font-family: sans-serif;
font-size: 14px;
z-index: 5;
}
#legend h3 {
margin-top: 0;
margin-bottom: 10px;
font-size: 16px;
}
.legend-item {
display: flex;
align-items: center;
margin-bottom: 5px;
}
.legend-color {
width: 30px;
height: 15px;
margin-right: 8px;
border: 1px solid #ccc;
}
.increase-color {
background: linear-gradient(to right, rgba(255, 255, 0, 0.7), rgba(255, 0, 0, 0.7));
}
.decrease-color {
background: linear-gradient(to right, rgba(0, 255, 255, 0.7), rgba(0, 0, 255, 0.7));
}
</style>
</head>
<body>
<div id="map"></div>
<div id="legend">
<h3>人口増減</h3>
<div class="legend-item">
<div class="legend-color increase-color"></div>
<span>増加</span>
</div>
<div class="legend-item">
<div class="legend-color decrease-color"></div>
<span>減少</span>
</div>
</div>
<script>
// 人口増減データ
const populationData = [
{ name: "横山町", lat: 35.658091, lng: 139.338006, change: 136 },
{ name: "八日町", lat: 35.657095, lng: 139.335967, change: 316 },
{ name: "八幡町", lat: 35.656914, lng: 139.332766, change: 505 },
{ name: "八木町", lat: 35.658252, lng: 139.332064, change: 23 },
{ name: "追分町", lat: 35.658498, lng: 139.324397, change: 79 },
{ name: "千人町1丁目", lat: 35.657386, lng: 139.325983, change: 83 },
{ name: "千人町2丁目", lat: 35.656847, lng: 139.321798, change: 128 },
{ name: "千人町3丁目", lat: 35.655979, lng: 139.317513, change: -4 },
{ name: "千人町4丁目", lat: 35.654877, lng: 139.312948, change: 73 },
{ name: "日吉町", lat: 35.660855, lng: 139.330836, change: 16 },
{ name: "元本郷町1丁目", lat: 35.661139, lng: 139.326296, change: 73 },
{ name: "元本郷町2丁目", lat: 35.663185, lng: 139.323984, change: 45 },
{ name: "元本郷町3丁目", lat: 35.665319, lng: 139.321714, change: -4 },
{ name: "元本郷町4丁目", lat: 35.666014, lng: 139.325603, change: 15 },
{ name: "平岡町", lat: 35.662703, lng: 139.331575, change: -32 },
{ name: "本郷町", lat: 35.661646, lng: 139.334185, change: 3 },
{ name: "大横町", lat: 35.660161, lng: 139.337197, change: -46 },
{ name: "本町", lat: 35.658269, lng: 139.334114, change: 40 },
{ name: "元横山町1丁目", lat: 35.659972, lng: 139.340078, change: 1 },
{ name: "元横山町2丁目", lat: 35.662125, lng: 139.338781, change: 182 },
{ name: "元横山町3丁目", lat: 35.664402, lng: 139.336496, change: 11 },
{ name: "田町", lat: 35.656363, lng: 139.340328, change: -33 },
{ name: "新町", lat: 35.657685, lng: 139.341846, change: 66 },
{ name: "明神町1丁目", lat: 35.659021, lng: 139.344406, change: -4 },
{ name: "明神町2丁目", lat: 35.657688, lng: 139.345869, change: 88 },
{ name: "明神町3丁目", lat: 35.656514, lng: 139.348624, change: -16 },
{ name: "明神町4丁目", lat: 35.658066, lng: 139.351052, change: 7 },
{ name: "子安町1丁目", lat: 35.653697, lng: 139.342938, change: 171 },
{ name: "子安町2丁目", lat: 35.652159, lng: 139.346853, change: -88 },
{ name: "子安町3丁目", lat: 35.651717, lng: 139.351235, change: 100 },
{ name: "子安町4丁目", lat: 35.653427, lng: 139.346917, change: 10 },
{ name: "東町", lat: 35.656608, lng: 139.341868, change: -5 },
{ name: "旭町", lat: 35.656156, lng: 139.339257, change: -27 },
{ name: "三崎町", lat: 35.655452, lng: 139.340263, change: -31 },
{ name: "中町", lat: 35.655928, lng: 139.337149, change: -11 },
{ name: "南町", lat: 35.654261, lng: 139.337583, change: 66 },
{ name: "寺町", lat: 35.653063, lng: 139.336974, change: 135 },
{ name: "万町", lat: 35.652145, lng: 139.334758, change: -27 },
{ name: "上野町", lat: 35.651203, lng: 139.332308, change: 59 },
{ name: "天神町", lat: 35.653147, lng: 139.329868, change: -29 },
{ name: "南新町", lat: 35.654406, lng: 139.334335, change: -15 },
{ name: "小門町", lat: 35.655829, lng: 139.330752, change: 93 },
{ name: "台町1丁目", lat: 35.652787, lng: 139.326888, change: -31 },
{ name: "台町2丁目", lat: 35.652431, lng: 139.323382, change: 161 },
{ name: "台町3丁目", lat: 35.651919, lng: 139.319502, change: -1 },
{ name: "台町4丁目", lat: 35.650638, lng: 139.315024, change: 91 },
{ name: "中野町", lat: 35.679105, lng: 139.317808, change: -52 },
{ name: "暁町1丁目", lat: 35.669837, lng: 139.332029, change: -72 },
{ name: "暁町2丁目", lat: 35.673898, lng: 139.329068, change: 0 },
{ name: "暁町3丁目", lat: 35.678129, lng: 139.324831, change: -52 },
{ name: "中野山王1丁目", lat: 35.670699, lng: 139.323555, change: 27 },
{ name: "中野山王2丁目", lat: 35.674483, lng: 139.321415, change: 109 },
{ name: "中野山王3丁目", lat: 35.677329, lng: 139.321484, change: -157 },
{ name: "中野上町1丁目", lat: 35.668784, lng: 139.320499, change: 23 },
{ name: "中野上町2丁目", lat: 35.671393, lng: 139.317424, change: 19 },
{ name: "中野上町3丁目", lat: 35.673552, lng: 139.314227, change: -64 },
{ name: "中野上町4丁目", lat: 35.676104, lng: 139.311756, change: -73 },
{ name: "中野上町5丁目", lat: 35.679044, lng: 139.310619, change: -53 },
{ name: "大和田町1丁目", lat: 35.667865, lng: 139.347537, change: -49 },
{ name: "大和田町2丁目", lat: 35.666138, lng: 139.351859, change: -11 },
{ name: "大和田町3丁目", lat: 35.664119, lng: 139.354146, change: -32 },
{ name: "大和田町4丁目", lat: 35.662174, lng: 139.356394, change: 3 },
{ name: "大和田町5丁目", lat: 35.660307, lng: 139.358245, change: 289 },
{ name: "大和田町6丁目", lat: 35.662363, lng: 139.361957, change: -116 },
{ name: "大和田町7丁目", lat: 35.666014, lng: 139.358055, change: -10 },
{ name: "富士見町", lat: 35.652759, lng: 139.320743, change: -47 },
{ name: "緑町", lat: 35.645731, lng: 139.309068, change: -46 },
{ name: "清川町", lat: 35.644155, lng: 139.326269, change: -16 },
{ name: "東浅川町", lat: 35.640698, lng: 139.304856, change: -53 },
{ name: "初沢町", lat: 35.637209, lng: 139.293425, change: -79 },
{ name: "高尾町", lat: 35.626493, lng: 139.271384, change: 8 },
{ name: "南浅川町", lat: 35.637172, lng: 139.278308, change: -3 },
{ name: "西浅川町", lat: 35.635873, lng: 139.259929, change: -25 },
{ name: "裏高尾町", lat: 35.633758, lng: 139.243542, change: -40 },
{ name: "廿里町", lat: 35.617181, lng: 139.252033, change: -38 },
{ name: "下柚木", lat: 35.622329, lng: 139.369796, change: -35 },
{ name: "下柚木2丁目", lat: 35.620021, lng: 139.365313, change: 17 },
{ name: "下柚木3丁目", lat: 35.618698, lng: 139.370502, change: -102 },
{ name: "上柚木", lat: 35.613396, lng: 139.371302, change: -30 },
{ name: "上柚木2丁目", lat: 35.611037, lng: 139.362157, change: -62 },
{ name: "上柚木3丁目", lat: 35.607412, lng: 139.364234, change: -147 },
{ name: "中山", lat: 35.610543, lng: 139.378997, change: 51 },
{ name: "鑓水", lat: 35.616641, lng: 139.345688, change: -75 },
{ name: "鑓水2丁目", lat: 35.619934, lng: 139.351147, change: 231 },
{ name: "南大沢1丁目", lat: 35.615286, lng: 139.379119, change: 23 },
{ name: "南大沢2丁目", lat: 35.616782, lng: 139.383792, change: 11 },
{ name: "南大沢3丁目", lat: 35.611915, lng: 139.385718, change: -259 },
{ name: "南大沢4丁目", lat: 35.607902, lng: 139.383321, change: -114 },
{ name: "南大沢5丁目", lat: 35.604945, lng: 139.377626, change: -255 },
{ name: "越野", lat: 35.605273, lng: 139.390772, change: 30 },
{ name: "松木", lat: 35.610582, lng: 139.397191, change: -71 },
{ name: "別所1丁目", lat: 35.603314, lng: 139.400511, change: -315 },
{ name: "別所2丁目", lat: 35.609439, lng: 139.407289, change: -382 },
{ name: "南陽台1丁目", lat: 35.597384, lng: 139.370846, change: -23 },
{ name: "南陽台2丁目", lat: 35.595982, lng: 139.374944, change: -74 },
{ name: "南陽台3丁目", lat: 35.594247, lng: 139.378513, change: -11 },
{ name: "堀之内", lat: 35.604719, lng: 139.412952, change: 150 },
{ name: "堀之内2丁目", lat: 35.600941, lng: 139.420067, change: 44 },
{ name: "堀之内3丁目", lat: 35.602506, lng: 139.427773, change: 181 },
{ name: "東中野", lat: 35.600293, lng: 139.432328, change: 695 },
{ name: "大塚", lat: 35.603332, lng: 139.438519, change: 298 },
{ name: "鹿島", lat: 35.599696, lng: 139.396558, change: -162 },
{ name: "松が谷", lat: 35.601552, lng: 139.404886, change: -111 },
{ name: "並木町", lat: 35.643353, lng: 139.320478, change: -28 },
{ name: "散田町1丁目", lat: 35.647976, lng: 139.324275, change: -75 },
{ name: "散田町2丁目", lat: 35.646584, lng: 139.320427, change: -31 },
{ name: "散田町3丁目", lat: 35.646083, lng: 139.315926, change: -4 },
{ name: "散田町4丁目", lat: 35.642959, lng: 139.313886, change: 87 },
{ name: "散田町5丁目", lat: 35.640277, lng: 139.316827, change: -2 },
{ name: "山田町", lat: 35.632204, lng: 139.318859, change: 77 },
{ name: "めじろ台1丁目", lat: 35.638407, lng: 139.309995, change: -46 },
{ name: "めじろ台2丁目", lat: 35.635817, lng: 139.311545, change: 49 },
{ name: "めじろ台3丁目", lat: 35.636605, lng: 139.315967, change: -34 },
{ name: "めじろ台4丁目", lat: 35.634125, lng: 139.314811, change: -40 },
{ name: "長房町", lat: 35.651792, lng: 139.300582, change: -215 },
{ name: "城山手1丁目", lat: 35.655815, lng: 139.289133, change: -73 },
{ name: "城山手2丁目", lat: 35.658397, lng: 139.294132, change: -94 },
{ name: "狭間町", lat: 35.634568, lng: 139.303964, change: -172 },
{ name: "椚田町", lat: 35.630514, lng: 139.309028, change: -140 },
{ name: "館町", lat: 35.619084, lng: 139.299525, change: -125 },
{ name: "寺田町", lat: 35.617158, lng: 139.313988, change: -64 },
{ name: "大船町", lat: 35.612542, lng: 139.323594, change: -56 },
{ name: "大楽寺町", lat: 35.654868, lng: 139.273183, change: -174 },
{ name: "上壱分方町", lat: 35.660601, lng: 139.279649, change: 55 },
{ name: "諏訪町", lat: 35.660127, lng: 139.289945, change: -91 },
{ name: "四谷町", lat: 35.665243, lng: 139.283151, change: -134 },
{ name: "叶谷町", lat: 35.667828, lng: 139.276632, change: -22 },
{ name: "泉町", lat: 35.667104, lng: 139.272545, change: -107 },
{ name: "横川町", lat: 35.668791, lng: 139.302391, change: -111 },
{ name: "弐分方町", lat: 35.666996, lng: 139.263592, change: 25 },
{ name: "川町", lat: 35.662283, lng: 139.255909, change: -136 },
{ name: "元八王子町1丁目", lat: 35.652136, lng: 139.281867, change: -120 },
{ name: "元八王子町2丁目", lat: 35.653495, lng: 139.263919, change: -206 },
{ name: "元八王子町3丁目", lat: 35.659918, lng: 139.262174, change: -90 },
{ name: "下恩方町", lat: 35.670381, lng: 139.242502, change: -57 },
{ name: "上恩方町", lat: 35.688226, lng: 139.198359, change: -43 },
{ name: "西寺方町", lat: 35.677567, lng: 139.266209, change: -296 },
{ name: "小津町", lat: 35.701198, lng: 139.247854, change: -24 },
{ name: "川口町", lat: 35.689622, lng: 139.278788, change: -153 },
{ name: "上川町", lat: 35.707798, lng: 139.265228, change: -53 },
{ name: "犬目町", lat: 35.686616, lng: 139.296366, change: -25 },
{ name: "楢原町", lat: 35.682703, lng: 139.308233, change: 137 },
{ name: "美山町", lat: 35.714502, lng: 139.231268, change: -254 },
{ name: "尾崎町", lat: 35.685369, lng: 139.332306, change: 9 },
{ name: "左入町", lat: 35.683057, lng: 139.339695, change: -29 },
{ name: "滝山町1丁目", lat: 35.687508, lng: 139.349191, change: 186 },
{ name: "滝山町2丁目", lat: 35.690855, lng: 139.351235, change: -49 },
{ name: "梅坪町", lat: 35.691884, lng: 139.336423, change: -15 },
{ name: "谷野町", lat: 35.693452, lng: 139.343166, change: -85 },
{ name: "みつい台1丁目", lat: 35.698379, lng: 139.339459, change: -56 },
{ name: "みつい台2丁目", lat: 35.700588, lng: 139.334053, change: -42 },
{ name: "丹木町1丁目", lat: 35.696317, lng: 139.327096, change: 102 },
{ name: "丹木町2丁目", lat: 35.699411, lng: 139.321873, change: -99 },
{ name: "丹木町3丁目", lat: 35.702759, lng: 139.317424, change: -42 },
{ name: "加住町1丁目", lat: 35.695786, lng: 139.313462, change: 1 },
{ name: "加住町2丁目", lat: 35.691768, lng: 139.308221, change: -13 },
{ name: "宮下町", lat: 35.690855, lng: 139.302302, change: -54 },
{ name: "戸吹町", lat: 35.696162, lng: 139.293412, change: -86 },
{ name: "高月町", lat: 35.707742, lng: 139.292398, change: -33 },
{ name: "小比企町", lat: 35.626354, lng: 139.326317, change: -69 },
{ name: "片倉町", lat: 35.632943, lng: 139.350849, change: -11 },
{ name: "西片倉1丁目", lat: 35.627708, lng: 139.346394, change: -9 },
{ name: "西片倉2丁目", lat: 35.625624, lng: 139.341857, change: 24 },
{ name: "西片倉3丁目", lat: 35.622543, lng: 139.337771, change: 50 },
{ name: "宇津貫町", lat: 35.617329, lng: 139.332468, change: 1 },
{ name: "みなみ野1丁目", lat: 35.622352, lng: 139.333199, change: -43 },
{ name: "みなみ野2丁目", lat: 35.621425, lng: 139.327591, change: -21 },
{ name: "みなみ野3丁目", lat: 35.619084, lng: 139.324151, change: -84 },
{ name: "みなみ野4丁目", lat: 35.615174, lng: 139.326941, change: -62 },
{ name: "みなみ野5丁目", lat: 35.612089, lng: 139.329715, change: 547 },
{ name: "みなみ野6丁目", lat: 35.609467, lng: 139.332906, change: -53 },
{ name: "兵衛1丁目", lat: 35.610669, lng: 139.337728, change: -45 },
{ name: "兵衛2丁目", lat: 35.614539, lng: 139.340263, change: -48 },
{ name: "七国1丁目", lat: 35.607421, lng: 139.337583, change: 50 },
{ name: "七国2丁目", lat: 35.605386, lng: 139.342111, change: 41 },
{ name: "七国3丁目", lat: 35.603348, lng: 139.344849, change: 52 },
{ name: "七国4丁目", lat: 35.600989, lng: 139.348635, change: -103 },
{ name: "七国5丁目", lat: 35.599222, lng: 139.352422, change: -37 },
{ name: "七国6丁目", lat: 35.597148, lng: 139.355159, change: -100 },
{ name: "北野町", lat: 35.648119, lng: 139.358245, change: -38 },
{ name: "打越町", lat: 35.644143, lng: 139.366472, change: 26 },
{ name: "北野台1丁目", lat: 35.641662, lng: 139.362146, change: -93 },
{ name: "北野台2丁目", lat: 35.639148, lng: 139.363946, change: -45 },
{ name: "北野台3丁目", lat: 35.636914, lng: 139.366369, change: -57 },
{ name: "北野台4丁目", lat: 35.635832, lng: 139.370428, change: -62 },
{ name: "北野台5丁目", lat: 35.634125, lng: 139.374581, change: -143 },
{ name: "長沼町", lat: 35.646738, lng: 139.375283, change: -61 },
{ name: "絹ケ丘1丁目", lat: 35.632165, lng: 139.39075, change: -62 },
{ name: "絹ケ丘2丁目", lat: 35.629399, lng: 139.394142, change: -104 },
{ name: "絹ケ丘3丁目", lat: 35.627096, lng: 139.397624, change: -79 },
{ name: "高倉町", lat: 35.670984, lng: 139.365313, change: 17 },
{ name: "石川町", lat: 35.679169, lng: 139.364413, change: 116 },
{ name: "宇津木町", lat: 35.688862, lng: 139.372557, change: -26 },
{ name: "平町", lat: 35.681121, lng: 139.380721, change: -39 },
{ name: "小宮町", lat: 35.676646, lng: 139.38541, change: 24 },
{ name: "久保山町1丁目", lat: 35.683311, lng: 139.39009, change: -124 },
{ name: "久保山町2丁目", lat: 35.680018, lng: 139.39452, change: -105 },
{ name: "大谷町", lat: 35.675688, lng: 139.374241, change: 33 },
{ name: "丸山町", lat: 35.671393, lng: 139.34261, change: -85 },
];
// マップを初期化する関数
function initMap() {
// マップの中心を八王子市役所あたりに設定
const hachiojiCity = { lat: 35.655, lng: 139.33 };
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 12,
center: hachiojiCity,
});
// データを増加と減少に分ける
const increasePoints = [];
const decreasePoints = [];
for (const data of populationData) {
if (data.change > 0) {
increasePoints.push({
location: new google.maps.LatLng(data.lat, data.lng),
weight: data.change, // 増加量を重みとする
});
} else if (data.change < 0) {
decreasePoints.push({
location: new google.maps.LatLng(data.lat, data.lng),
weight: Math.abs(data.change), // 減少量の絶対値を重みとする
});
}
}
// 人口増加ヒートマップ(暖色系)
const increaseHeatmap = new google.maps.visualization.HeatmapLayer({
data: increasePoints,
map: map,
radius: 30, // ヒートマップの点の半径
gradient: [ // 色の変化(透明 -> 黄 -> 赤)
"rgba(255, 255, 0, 0)",
"rgba(255, 255, 0, 1)",
"rgba(255, 165, 0, 1)",
"rgba(255, 0, 0, 1)",
],
});
// 人口減少ヒートマップ(寒色系)
const decreaseHeatmap = new google.maps.visualization.HeatmapLayer({
data: decreasePoints,
map: map,
radius: 30, // 半径を合わせる
gradient: [ // 色の変化(透明 -> 水色 -> 青)
"rgba(0, 255, 255, 0)",
"rgba(0, 255, 255, 1)",
"rgba(0, 191, 255, 1)",
"rgba(0, 0, 255, 1)",
],
});
}
</script>
<!-- Google Maps APIを読み込む。YOUR_API_KEYはご自身のキーに置き換えてください -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=visualization&callback=initMap">
</script>
</body>
</html>
3.Google MapのAPIキーが必要になるので、GCPのAPIキーの発行手順を解説依頼
Maps JavaScript API と Maps Datasets API のAPI有効化とAPIキー発行手順を解説してください。
4.2で生成されたJavascriptに3で発行したAPIキーを埋め込み
なんと!上記の手順でたった30分でGoogle MapのAPIを使ってヒートマップを表示するHTML/Javascriptが完成しました!
Geminiで緯度経度の算出は注意
みなさんは掲示したヒートマップの違和感に気づいたでしょうか?
よくよく見ると、八王子市のはずなのに町田市や日野市にプロットされているエリアがあります。
実はGemini 2.5 Proが出力した緯度・経度は誤りも含まれていたのです。
正解が決まっている緯度経度とはいえ、生成AIはまだまだ間違いを犯すことは留意しておきましょう。
Google Geocoding APIで正確な緯度経度を取得
生成AIはまだまだ万能ではないものの、コーディングには長けているので、GoogleのGeocoding APIで緯度・経度を取得するJavascriptを作成依頼しました。
生成されたGeocodeingAPIのコード
<!DOCTYPE html>
<html>
<head>
<title>住所から緯度経度を取得 (ジオコーディング)</title>
<style>
/* 簡単なスタイル設定 */
body { font-family: sans-serif; }
#map {
height: 400px;
width: 100%;
margin-top: 15px;
border: 1px solid #ccc;
}
#controls { margin-bottom: 10px; }
#address-input { width: 350px; padding: 5px; }
#response {
margin-top: 15px;
padding: 10px;
background-color: #f0f0f0;
border-radius: 4px;
font-family: monospace;
white-space: pre-wrap; /* 結果が改行されるように */
}
</style>
</head>
<body>
<h1>住所から緯度・経度を取得</h1>
<div id="controls">
<input type="text" id="address-input" value="東京都八王子市元本郷町3丁目24−1">
<button onclick="geocodeAddress()">緯度・経度を取得</button>
</div>
<div id="response">ここに結果が表示されます。</div>
<div id="map"></div>
<script>
let map;
let geocoder;
let marker;
// 1. マップとジオコーダを初期化する関数
function initMap() {
// マップの初期中心地(例:八王子駅)
const hachiojiStation = { lat: 35.6559, lng: 139.3394 };
map = new google.maps.Map(document.getElementById("map"), {
zoom: 14,
center: hachiojiStation,
});
// ジオコーディングサービスを利用するためのインスタンスを作成
geocoder = new google.maps.Geocoder();
// 初期マーカーを地図上に作成
marker = new google.maps.Marker({
map: map,
});
}
// 2. 住所を緯度・経度に変換するメインの関数
function geocodeAddress() {
const address = document.getElementById("address-input").value;
const responseDiv = document.getElementById("response");
if (!address) {
responseDiv.textContent = "住所を入力してください。";
return;
}
// geocoder.geocodeメソッドを呼び出して、住所から緯度経度をリクエスト
geocoder.geocode({ 'address': address }, (results, status) => {
// 3. 結果を処理する
if (status === 'OK') {
// 成功した場合
const location = results[0].geometry.location;
const lat = location.lat(); // 緯度を取得
const lng = location.lng(); // 経度を取得
// 結果を表示
responseDiv.innerHTML =
`取得した住所: ${results[0].formatted_address}\n` +
`緯度 (Latitude): ${lat}\n` +
`経度 (Longitude): ${lng}`;
// マップの中心を取得した位置に移動
map.setCenter(location);
map.setZoom(17); // ズームインする
// マーカーの位置を更新
marker.setPosition(location);
marker.setVisible(true);
} else {
// 失敗した場合
responseDiv.textContent = `ジオコーディングに失敗しました。理由: ${status}`;
marker.setVisible(false); // エラー時はマーカーを非表示
}
});
}
</script>
<!--
Google Maps APIを読み込みます。
YOUR_API_KEYはご自身のキーに置き換えてください。
callback=initMap で、API読み込み完了後にinitMap関数を自動的に実行します。
-->
<script async
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
</body>
</html>
Geminiに作ってもらったGeocodingAPIのJavascriptで町丁リストの正しい緯度経度を出力できたので、緯度経度を差し替えてヒートマップを再度作り直しました。
再生成したヒートマップのコード
<!DOCTYPE html>
<html>
<head>
<title>八王子市 人口増減ヒートマップ (更新版)</title>
<style>
/* Mapのサイズを画面全体に設定 */
#map {
height: 100%;
}
/* HTMLとBodyの余白をなくす */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
/* 凡例のスタイル */
#legend {
position: absolute;
bottom: 20px;
left: 10px;
background: rgba(255, 255, 255, 0.9);
padding: 10px;
border: 1px solid #777;
border-radius: 5px;
font-family: sans-serif;
font-size: 14px;
z-index: 5;
}
#legend h3 {
margin-top: 0;
margin-bottom: 10px;
font-size: 16px;
}
.legend-item {
display: flex;
align-items: center;
margin-bottom: 5px;
}
.legend-color {
width: 30px;
height: 15px;
margin-right: 8px;
border: 1px solid #ccc;
}
.increase-color {
background: linear-gradient(to right, rgba(255, 255, 0, 0.7), rgba(255, 0, 0, 0.7));
}
.decrease-color {
background: linear-gradient(to right, rgba(0, 255, 255, 0.7), rgba(0, 0, 255, 0.7));
}
</style>
</head>
<body>
<div id="map"></div>
<div id="legend">
<h3>人口増減</h3>
<div class="legend-item">
<div class="legend-color increase-color"></div>
<span>増加</span>
</div>
<div class="legend-item">
<div class="legend-color decrease-color"></div>
<span>減少</span>
</div>
</div>
<script>
// --- データ定義 ---
// 1. 新しい緯度・経度データ
const newLocations = [
{ name: "横山町", lat: 35.6596515, lng: 139.3370821 },
{ name: "八日町", lat: 35.6601873, lng: 139.3313737 },
{ name: "八幡町", lat: 35.6604092, lng: 139.3263001 },
{ name: "八木町", lat: 35.6608889, lng: 139.3218611 },
{ name: "追分町", lat: 35.6607415, lng: 139.3186905 },
{ name: "千人町1丁目", lat: 35.6590357, lng: 139.3152032 },
{ name: "千人町2丁目", lat: 35.6597731, lng: 139.311399 },
{ name: "千人町3丁目", lat: 35.6569702, lng: 139.310131 },
{ name: "千人町4丁目", lat: 35.6565642, lng: 139.3063271 },
{ name: "日吉町", lat: 35.6609626, lng: 139.3136181 },
{ name: "元本郷町1丁目", lat: 35.663904, lng: 139.321544 },
{ name: "元本郷町2丁目", lat: 35.6651578, lng: 139.3190076 },
{ name: "元本郷町3丁目", lat: 35.6652683, lng: 139.3164713 },
{ name: "元本郷町4丁目", lat: 35.6653787, lng: 139.3139351 },
{ name: "平岡町", lat: 35.6643096, lng: 139.3253489 },
{ name: "本郷町", lat: 35.6618107, lng: 139.3269343 },
{ name: "大横町", lat: 35.6624283, lng: 139.329154 },
{ name: "本町", lat: 35.6623174, lng: 139.3316908 },
{ name: "元横山町1丁目", lat: 35.6642711, lng: 139.3393021 },
{ name: "元横山町2丁目", lat: 35.6620953, lng: 139.3367649 },
{ name: "元横山町3丁目", lat: 35.6652218, lng: 139.3339107 },
{ name: "田町", lat: 35.6659961, lng: 139.3358135 },
{ name: "新町", lat: 35.6611999, lng: 139.3408879 },
{ name: "明神町1丁目", lat: 35.6581077, lng: 139.349452 },
{ name: "明神町2丁目", lat: 35.6570756, lng: 139.3469144 },
{ name: "明神町3丁目", lat: 35.6566711, lng: 139.3431081 },
{ name: "明神町4丁目", lat: 35.6601019, lng: 139.3431081 },
{ name: "子安町1丁目", lat: 35.6526125, lng: 139.3443769 },
{ name: "子安町2丁目", lat: 35.649293, lng: 139.3418394 },
{ name: "子安町3丁目", lat: 35.6495161, lng: 139.3367649 },
{ name: "子安町4丁目", lat: 35.6540906, lng: 139.3367649 },
{ name: "東町", lat: 35.6581386, lng: 139.338985 },
{ name: "旭町", lat: 35.6562664, lng: 139.3393021 },
{ name: "三崎町", lat: 35.6571063, lng: 139.3364478 },
{ name: "中町", lat: 35.6585635, lng: 139.3358135 },
{ name: "南町", lat: 35.6586747, lng: 139.3332764 },
{ name: "寺町", lat: 35.6559728, lng: 139.3329593 },
{ name: "万町", lat: 35.6525421, lng: 139.3329593 },
{ name: "上野町", lat: 35.6547379, lng: 139.3285198 },
{ name: "天神町", lat: 35.6573842, lng: 139.3301053 },
{ name: "南新町", lat: 35.6585277, lng: 139.3301053 },
{ name: "小門町", lat: 35.6587496, lng: 139.3250318 },
{ name: "台町1丁目", lat: 35.6504775, lng: 139.3278856 },
{ name: "台町2丁目", lat: 35.6516404, lng: 139.3209099 },
{ name: "台町3丁目", lat: 35.6553843, lng: 139.3202758 },
{ name: "台町4丁目", lat: 35.6582981, lng: 139.3190076 },
{ name: "中野町", lat: 35.6803321, lng: 139.3183735 },
{ name: "暁町1丁目", lat: 35.6684397, lng: 139.3354964 },
{ name: "暁町2丁目", lat: 35.672386, lng: 139.3367649 },
{ name: "暁町3丁目", lat: 35.6752997, lng: 139.3354964 },
{ name: "中野山王1丁目", lat: 35.672202, lng: 139.3278856 },
{ name: "中野山王2丁目", lat: 35.676148, lng: 139.329154 },
{ name: "中野山王3丁目", lat: 35.674599, lng: 139.3253489 },
{ name: "中野上町1丁目", lat: 35.6671125, lng: 139.3266172 },
{ name: "中野上町2丁目", lat: 35.6700261, lng: 139.3253489 },
{ name: "中野上町3丁目", lat: 35.6725335, lng: 139.3202758 },
{ name: "中野上町4丁目", lat: 35.6698411, lng: 139.3164713 },
{ name: "中野上町5丁目", lat: 35.6744136, lng: 139.3164713 },
{ name: "大和田町1丁目", lat: 35.6569427, lng: 139.3564312 },
{ name: "大和田町2丁目", lat: 35.6640072, lng: 139.3583347 },
{ name: "大和田町3丁目", lat: 35.6604856, lng: 139.3538932 },
{ name: "大和田町4丁目", lat: 35.6652625, lng: 139.3557967 },
{ name: "大和田町5丁目", lat: 35.6640282, lng: 139.3513554 },
{ name: "大和田町6丁目", lat: 35.6642511, lng: 139.34628 },
{ name: "大和田町7丁目", lat: 35.6669631, lng: 139.3431081 },
{ name: "富士見町", lat: 35.6684002, lng: 139.349452 },
{ name: "緑町", lat: 35.6468443, lng: 139.325983 },
{ name: "清川町", lat: 35.6718313, lng: 139.310131 },
{ name: "東浅川町", lat: 35.6448537, lng: 139.2930156 },
{ name: "初沢町", lat: 35.6307631, lng: 139.2752717 },
{ name: "高尾町", lat: 35.6425485, lng: 139.2802113 },
{ name: "南浅川町", lat: 35.6178736, lng: 139.2617391 },
{ name: "西浅川町", lat: 35.6426176, lng: 139.2721038 },
{ name: "裏高尾町", lat: 35.6379289, lng: 139.2284034 },
{ name: "廿里町", lat: 35.6467668, lng: 139.2752717 },
{ name: "下柚木", lat: 35.6296166, lng: 139.3792777 },
{ name: "下柚木2丁目", lat: 35.6260701, lng: 139.3818168 },
{ name: "下柚木3丁目", lat: 35.6212912, lng: 139.3799125 },
{ name: "上柚木", lat: 35.6192543, lng: 139.3678533 },
{ name: "上柚木2丁目", lat: 35.6199711, lng: 139.3710265 },
{ name: "上柚木3丁目", lat: 35.6173679, lng: 139.3716612 },
{ name: "中山", lat: 35.6269745, lng: 139.3615074 },
{ name: "鑓水", lat: 35.6135354, lng: 139.3515875 },
{ name: "鑓水2丁目", lat: 35.6111803, lng: 139.3564312 },
{ name: "南大沢1丁目", lat: 35.6192032, lng: 139.3818168 },
{ name: "南大沢2丁目", lat: 35.6120212, lng: 139.3824516 },
{ name: "南大沢3丁目", lat: 35.6077572, lng: 139.3818168 },
{ name: "南大沢4丁目", lat: 35.6079847, lng: 139.3767388 },
{ name: "南大沢5丁目", lat: 35.6094699, lng: 139.3691226 },
{ name: "越野", lat: 35.6299931, lng: 139.3900695 },
{ name: "松木", lat: 35.6233269, lng: 139.3919742 },
{ name: "別所1丁目", lat: 35.6164591, lng: 139.3919742 },
{ name: "別所2丁目", lat: 35.6172618, lng: 139.3995934 },
{ name: "南陽台1丁目", lat: 35.63359, lng: 139.3735653 },
{ name: "南陽台2丁目", lat: 35.633364, lng: 139.378643 },
{ name: "南陽台3丁目", lat: 35.6351369, lng: 139.3773735 },
{ name: "堀之内", lat: 35.6366586, lng: 139.388165 },
{ name: "堀之内2丁目", lat: 35.6289093, lng: 139.4014983 },
{ name: "堀之内3丁目", lat: 35.6271353, lng: 139.4027683 },
{ name: "東中野", lat: 35.6357498, lng: 139.4084837 },
{ name: "大塚", lat: 35.6392429, lng: 139.4199161 },
{ name: "鹿島", lat: 35.6321458, lng: 139.4249979 },
{ name: "松が谷", lat: 35.6303137, lng: 139.4148348 },
{ name: "並木町", lat: 35.6535583, lng: 139.3031574 },
{ name: "散田町1丁目", lat: 35.653734, lng: 139.3155202 },
{ name: "散田町2丁目", lat: 35.6495753, lng: 139.3158372 },
{ name: "散田町3丁目", lat: 35.6529134, lng: 139.311399 },
{ name: "散田町4丁目", lat: 35.6513643, lng: 139.3075951 },
{ name: "散田町5丁目", lat: 35.6481554, lng: 139.3025235 },
{ name: "山田町", lat: 35.6441717, lng: 139.3152032 },
{ name: "めじろ台1丁目", lat: 35.6464774, lng: 139.308229 },
{ name: "めじろ台2丁目", lat: 35.6406495, lng: 139.310765 },
{ name: "めじろ台3丁目", lat: 35.6411847, lng: 139.3050592 },
{ name: "めじろ台4丁目", lat: 35.6435821, lng: 139.3025235 },
{ name: "長房町", lat: 35.6544055, lng: 139.2968186 },
{ name: "城山手1丁目", lat: 35.6545323, lng: 139.2873116 },
{ name: "城山手2丁目", lat: 35.6541255, lng: 139.2835093 },
{ name: "狭間町", lat: 35.6371818, lng: 139.2854104 },
{ name: "椚田町", lat: 35.6360754, lng: 139.310765 },
{ name: "館町", lat: 35.630816, lng: 139.289388 },
{ name: "寺田町", lat: 35.6198821, lng: 139.3018896 },
{ name: "大船町", lat: 35.6210967, lng: 139.313301 },
{ name: "大楽寺町", lat: 35.6738525, lng: 139.2898467 },
{ name: "上壱分方町", lat: 35.6828999, lng: 139.2854104 },
{ name: "諏訪町", lat: 35.679144, lng: 139.2930156 },
{ name: "四谷町", lat: 35.6769524, lng: 139.2974525 },
{ name: "叶谷町", lat: 35.6703918, lng: 139.3037914 },
{ name: "泉町", lat: 35.674134, lng: 139.3031574 },
{ name: "横川町", lat: 35.6639568, lng: 139.3006218 },
{ name: "弐分方町", lat: 35.6714726, lng: 139.2854104 },
{ name: "川町", lat: 35.6648637, lng: 139.2664018 },
{ name: "元八王子町1丁目", lat: 35.6656488, lng: 139.2879454 },
{ name: "元八王子町2丁目", lat: 35.6615154, lng: 139.2778063 },
{ name: "元八王子町3丁目", lat: 35.6536545, lng: 139.2613339 },
{ name: "下恩方町", lat: 35.6737726, lng: 139.2582563 },
{ name: "上恩方町", lat: 35.6712039, lng: 139.1980228 },
{ name: "西寺方町", lat: 35.6740047, lng: 139.2664018 },
{ name: "小津町", lat: 35.6873696, lng: 139.2208068 },
{ name: "川口町", lat: 35.6883659, lng: 139.2878456 },
{ name: "上川町", lat: 35.7039502, lng: 139.254221 },
{ name: "犬目町", lat: 35.6955492, lng: 139.2968186 },
{ name: "楢原町", lat: 35.6797389, lng: 139.3056932 },
{ name: "美山町", lat: 35.6893109, lng: 139.2503299 },
{ name: "尾崎町", lat: 35.6805729, lng: 139.3456456 },
{ name: "左入町", lat: 35.6796513, lng: 139.3405708 },
{ name: "滝山町1丁目", lat: 35.6906595, lng: 139.3437425 },
{ name: "滝山町2丁目", lat: 35.6929638, lng: 139.3367649 },
{ name: "梅坪町", lat: 35.6852754, lng: 139.3361306 },
{ name: "谷野町", lat: 35.68697, lng: 139.3234464 },
{ name: "みつい台1丁目", lat: 35.681449, lng: 139.3288369 },
{ name: "みつい台2丁目", lat: 35.6832276, lng: 139.3240806 },
{ name: "丹木町1丁目", lat: 35.6903819, lng: 139.3304224 },
{ name: "丹木町2丁目", lat: 35.6925749, lng: 139.325983 },
{ name: "丹木町3丁目", lat: 35.696317, lng: 139.3253489 },
{ name: "加住町1丁目", lat: 35.7019376, lng: 139.3209099 },
{ name: "加住町2丁目", lat: 35.6953001, lng: 139.3158372 },
{ name: "宮下町", lat: 35.7042535, lng: 139.3069611 },
{ name: "戸吹町", lat: 35.7077689, lng: 139.2962248 },
{ name: "高月町", lat: 35.7075418, lng: 139.3234464 },
{ name: "小比企町", lat: 35.6372905, lng: 139.3221781 },
{ name: "片倉町", lat: 35.6359502, lng: 139.3391719 },
{ name: "西片倉1丁目", lat: 35.6360041, lng: 139.3351792 },
{ name: "西片倉2丁目", lat: 35.6365308, lng: 139.3329593 },
{ name: "西片倉3丁目", lat: 35.6356102, lng: 139.3278856 },
{ name: "宇津貫町", lat: 35.6166582, lng: 139.3361306 },
{ name: "みなみ野1丁目", lat: 35.632179, lng: 139.3278856 },
{ name: "みなみ野2丁目", lat: 35.6276037, lng: 139.3278856 },
{ name: "みなみ野3丁目", lat: 35.630003, lng: 139.3253489 },
{ name: "みなみ野4丁目", lat: 35.6266833, lng: 139.3228123 },
{ name: "みなみ野5丁目", lat: 35.6300237, lng: 139.3183735 },
{ name: "みなみ野6丁目", lat: 35.632402, lng: 139.3228123 },
{ name: "兵衛1丁目", lat: 35.6293088, lng: 139.3313737 },
{ name: "兵衛2丁目", lat: 35.6233204, lng: 139.3342278 },
{ name: "七国1丁目", lat: 35.6191705, lng: 139.3310566 },
{ name: "七国2丁目", lat: 35.6197084, lng: 139.3253489 },
{ name: "七国3丁目", lat: 35.6171066, lng: 139.325983 },
{ name: "七国4丁目", lat: 35.6206714, lng: 139.3164713 },
{ name: "七国5丁目", lat: 35.6228474, lng: 139.3190076 },
{ name: "七国6丁目", lat: 35.6229379, lng: 139.3234464 },
{ name: "北野町", lat: 35.6503037, lng: 139.3513554 },
{ name: "打越町", lat: 35.6405249, lng: 139.3526243 },
{ name: "北野台1丁目", lat: 35.6326063, lng: 139.3570657 },
{ name: "北野台2丁目", lat: 35.6252258, lng: 139.3557967 },
{ name: "北野台3丁目", lat: 35.6259667, lng: 139.3519898 },
{ name: "北野台4丁目", lat: 35.6293989, lng: 139.3519898 },
{ name: "北野台5丁目", lat: 35.6316871, lng: 139.3519898 },
{ name: "長沼町", lat: 35.6415105, lng: 139.3691226 },
{ name: "絹ケ丘1丁目", lat: 35.6392458, lng: 139.362142 },
{ name: "絹ケ丘2丁目", lat: 35.6370701, lng: 139.3596038 },
{ name: "絹ケ丘3丁目", lat: 35.6330096, lng: 139.3608728 },
{ name: "高倉町", lat: 35.6656453, lng: 139.3665841 },
{ name: "石川町", lat: 35.6766777, lng: 139.3627765 },
{ name: "宇津木町", lat: 35.6816969, lng: 139.3526243 },
{ name: "平町", lat: 35.6925947, lng: 139.3583347 },
{ name: "小宮町", lat: 35.68789, lng: 139.3678533 },
{ name: "久保山町1丁目", lat: 35.6864531, lng: 139.3615074 },
{ name: "久保山町2丁目", lat: 35.6875052, lng: 139.3570657 },
{ name: "大谷町", lat: 35.6744313, lng: 139.3488176 },
{ name: "丸山町", lat: 35.6906409, lng: 139.3507209 },
];
// 2. 人口増減データ
const populationChange = [
{ name: "横山町", change: 136 }, { name: "八日町", change: 316 }, { name: "八幡町", change: 505 }, { name: "八木町", change: 23 }, { name: "追分町", change: 79 },
{ name: "千人町1丁目", change: 83 }, { name: "千人町2丁目", change: 128 }, { name: "千人町3丁目", change: -4 }, { name: "千人町4丁目", change: 73 },
{ name: "日吉町", change: 16 }, { name: "元本郷町1丁目", change: 73 }, { name: "元本郷町2丁目", change: 45 }, { name: "元本郷町3丁目", change: -4 },
{ name: "元本郷町4丁目", change: 15 }, { name: "平岡町", change: -32 }, { name: "本郷町", change: 3 }, { name: "大横町", change: -46 },
{ name: "本町", change: 40 }, { name: "元横山町1丁目", change: 1 }, { name: "元横山町2丁目", change: 182 }, { name: "元横山町3丁目", change: 11 },
{ name: "田町", change: -33 }, { name: "新町", change: 66 }, { name: "明神町1丁目", change: -4 }, { name: "明神町2丁目", change: 88 },
{ name: "明神町3丁目", change: -16 }, { name: "明神町4丁目", change: 7 }, { name: "子安町1丁目", change: 171 }, { name: "子安町2丁目", change: -88 },
{ name: "子安町3丁目", change: 100 }, { name: "子安町4丁目", change: 10 }, { name: "東町", change: -5 }, { name: "旭町", change: -27 },
{ name: "三崎町", change: -31 }, { name: "中町", change: -11 }, { name: "南町", change: 66 }, { name: "寺町", change: 135 },
{ name: "万町", change: -27 }, { name: "上野町", change: 59 }, { name: "天神町", change: -29 }, { name: "南新町", change: -15 },
{ name: "小門町", change: 93 }, { name: "台町1丁目", change: -31 }, { name: "台町2丁目", change: 161 }, { name: "台町3丁目", change: -1 },
{ name: "台町4丁目", change: 91 }, { name: "中野町", change: -52 }, { name: "暁町1丁目", change: -72 }, { name: "暁町2丁目", change: 0 },
{ name: "暁町3丁目", change: -52 }, { name: "中野山王1丁目", change: 27 }, { name: "中野山王2丁目", change: 109 }, { name: "中野山王3丁目", change: -157 },
{ name: "中野上町1丁目", change: 23 }, { name: "中野上町2丁目", change: 19 }, { name: "中野上町3丁目", change: -64 }, { name: "中野上町4丁目", change: -73 },
{ name: "中野上町5丁目", change: -53 }, { name: "大和田町1丁目", change: -49 }, { name: "大和田町2丁目", change: -11 }, { name: "大和田町3丁目", change: -32 },
{ name: "大和田町4丁目", change: 3 }, { name: "大和田町5丁目", change: 289 }, { name: "大和田町6丁目", change: -116 }, { name: "大和田町7丁目", change: -10 },
{ name: "富士見町", change: -47 }, { name: "緑町", change: -46 }, { name: "清川町", change: -16 }, { name: "東浅川町", change: -53 },
{ name: "初沢町", change: -79 }, { name: "高尾町", change: 8 }, { name: "南浅川町", change: -3 }, { name: "西浅川町", change: -25 },
{ name: "裏高尾町", change: -40 }, { name: "廿里町", change: -38 }, { name: "下柚木", change: -35 }, { name: "下柚木2丁目", change: 17 },
{ name: "下柚木3丁目", change: -102 }, { name: "上柚木", change: -30 }, { name: "上柚木2丁目", change: -62 }, { name: "上柚木3丁目", change: -147 },
{ name: "中山", change: 51 }, { name: "鑓水", change: -75 }, { name: "鑓水2丁目", change: 231 }, { name: "南大沢1丁目", change: 23 },
{ name: "南大沢2丁目", change: 11 }, { name: "南大沢3丁目", change: -259 }, { name: "南大沢4丁目", change: -114 }, { name: "南大沢5丁目", change: -255 },
{ name: "越野", change: 30 }, { name: "松木", change: -71 }, { name: "別所1丁目", change: -315 }, { name: "別所2丁目", change: -382 },
{ name: "南陽台1丁目", change: -23 }, { name: "南陽台2丁目", change: -74 }, { name: "南陽台3丁目", change: -11 }, { name: "堀之内", change: 150 },
{ name: "堀之内2丁目", change: 44 }, { name: "堀之内3丁目", change: 181 }, { name: "東中野", change: 695 }, { name: "大塚", change: 298 },
{ name: "鹿島", change: -162 }, { name: "松が谷", change: -111 }, { name: "並木町", change: -28 }, { name: "散田町1丁目", change: -75 },
{ name: "散田町2丁目", change: -31 }, { name: "散田町3丁目", change: -4 }, { name: "散田町4丁目", change: 87 }, { name: "散田町5丁目", change: -2 },
{ name: "山田町", change: 77 }, { name: "めじろ台1丁目", change: -46 }, { name: "めじろ台2丁目", change: 49 }, { name: "めじろ台3丁目", change: -34 },
{ name: "めじろ台4丁目", change: -40 }, { name: "長房町", change: -215 }, { name: "城山手1丁目", change: -73 }, { name: "城山手2丁目", change: -94 },
{ name: "狭間町", change: -172 }, { name: "椚田町", change: -140 }, { name: "館町", change: -125 }, { name: "寺田町", change: -64 },
{ name: "大船町", change: -56 }, { name: "大楽寺町", change: -174 }, { name: "上壱分方町", change: 55 }, { name: "諏訪町", change: -91 },
{ name: "四谷町", change: -134 }, { name: "叶谷町", change: -22 }, { name: "泉町", change: -107 }, { name: "横川町", change: -111 },
{ name: "弐分方町", change: 25 }, { name: "川町", change: -136 }, { name: "元八王子町1丁目", change: -120 }, { name: "元八王子町2丁目", change: -206 },
{ name: "元八王子町3丁目", change: -90 }, { name: "下恩方町", change: -57 }, { name: "上恩方町", change: -43 }, { name: "西寺方町", change: -296 },
{ name: "小津町", change: -24 }, { name: "川口町", change: -153 }, { name: "上川町", change: -53 }, { name: "犬目町", change: -25 },
{ name: "楢原町", change: 137 }, { name: "美山町", change: -254 }, { name: "尾崎町", change: 9 }, { name: "左入町", change: -29 },
{ name: "滝山町1丁目", change: 186 }, { name: "滝山町2丁目", change: -49 }, { name: "梅坪町", change: -15 }, { name: "谷野町", change: -85 },
{ name: "みつい台1丁目", change: -56 }, { name: "みつい台2丁目", change: -42 }, { name: "丹木町1丁目", change: 102 }, { name: "丹木町2丁目", change: -99 },
{ name: "丹木町3丁目", change: -42 }, { name: "加住町1丁目", change: 1 }, { name: "加住町2丁目", change: -13 }, { name: "宮下町", change: -54 },
{ name: "戸吹町", change: -86 }, { name: "高月町", change: -33 }, { name: "小比企町", change: -69 }, { name: "片倉町", change: -11 },
{ name: "西片倉1丁目", change: -9 }, { name: "西片倉2丁目", change: 24 }, { name: "西片倉3丁目", change: 50 }, { name: "宇津貫町", change: 1 },
{ name: "みなみ野1丁目", change: -43 }, { name: "みなみ野2丁目", change: -21 }, { name: "みなみ野3丁目", change: -84 }, { name: "みなみ野4丁目", change: -62 },
{ name: "みなみ野5丁目", change: 547 }, { name: "みなみ野6丁目", change: -53 }, { name: "兵衛1丁目", change: -45 }, { name: "兵衛2丁目", change: -48 },
{ name: "七国1丁目", change: 50 }, { name: "七国2丁目", change: 41 }, { name: "七国3丁目", change: 52 }, { name: "七国4丁目", change: -103 },
{ name: "七国5丁目", change: -37 }, { name: "七国6丁目", change: -100 }, { name: "北野町", change: -38 }, { name: "打越町", change: 26 },
{ name: "北野台1丁目", change: -93 }, { name: "北野台2丁目", change: -45 }, { name: "北野台3丁目", change: -57 }, { name: "北野台4丁目", change: -62 },
{ name: "北野台5丁目", change: -143 }, { name: "長沼町", change: -61 }, { name: "絹ケ丘1丁目", change: -62 }, { name: "絹ケ丘2丁目", change: -104 },
{ name: "絹ケ丘3丁目", change: -79 }, { name: "高倉町", change: 17 }, { name: "石川町", change: 116 }, { name: "宇津木町", change: -26 },
{ name: "平町", change: -39 }, { name: "小宮町", change: 24 }, { name: "久保山町1丁目", change: -124 }, { name: "久保山町2丁目", change: -105 },
{ name: "大谷町", change: 33 }, { name: "丸山町", change: -85 },
];
// --- データ処理 ---
// 3. 町丁名をキーにして、緯度経度データと人口増減データを結合する
const populationChangeByName = new Map(populationChange.map(item => [item.name, item.change]));
const mergedData = newLocations.map(location => ({
...location,
change: populationChangeByName.get(location.name) || 0 // 見つからない場合は0
}));
// --- マップ描画 ---
// マップを初期化する関数
function initMap() {
// マップの中心を八王子市役所あたりに設定
const hachiojiCity = { lat: 35.655, lng: 139.33 };
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 12,
center: hachiojiCity,
});
// データを増加と減少に分ける
const increasePoints = [];
const decreasePoints = [];
for (const data of mergedData) {
if (data.change > 0) {
increasePoints.push({
location: new google.maps.LatLng(data.lat, data.lng),
weight: data.change, // 増加量を重みとする
});
} else if (data.change < 0) {
decreasePoints.push({
location: new google.maps.LatLng(data.lat, data.lng),
weight: Math.abs(data.change), // 減少量の絶対値を重みとする
});
}
}
// 人口増加ヒートマップ(暖色系)
new google.maps.visualization.HeatmapLayer({
data: increasePoints,
map: map,
radius: 30, // ヒートマップの点の半径
gradient: [ // 色の変化(透明 -> 黄 -> 赤)
"rgba(255, 255, 0, 0)",
"rgba(255, 255, 0, 1)",
"rgba(255, 165, 0, 1)",
"rgba(255, 0, 0, 1)",
],
});
// 人口減少ヒートマップ(寒色系)
new google.maps.visualization.HeatmapLayer({
data: decreasePoints,
map: map,
radius: 30, // 半径を合わせる
gradient: [ // 色の変化(透明 -> 水色 -> 青)
"rgba(0, 255, 255, 0)",
"rgba(0, 255, 255, 1)",
"rgba(0, 191, 255, 1)",
"rgba(0, 0, 255, 1)",
],
});
}
</script>
<!-- Google Maps APIを読み込む。YOUR_API_KEYはご自身のキーに置き換えてください -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=visualization&callback=initMap">
</script>
</body>
</html>
今度はヒートマップが八王子市内に収まっており、正しく作成できました。
JRの八王子駅と西八王子駅の間のエリアや、東中野など一部増加傾向のある地域がヒートマップでよりわかりやすくなりました。
緯度・経度の再取得が発生しましたが、それでも1時間かからずにヒートマップができました。
生成AIでデータビジュアライズも簡単に
今回はGemini 2.5 Proを使いましたが、生成AIを使えば、GoogleMapを使ったデータビジュアライゼーションに誰でも取り組めます。
これまでGoogleマップのAPIはエンジニアなど詳しい人しか使えないものでした。
しかし、生成AIを使えば、指示に従えば、GCPの設定やAPIキーの発行でき、コードも生成してくれて簡単に地図的なビジュライズができます。
生成AIによってデータの民主化がますます広がることを強く感じました。
まとめ
今回、Googleの生成AIであるGemini 2.5 ProでGoogle Map APIを使ったヒートマップをたった1時間で作成できたことを紹介しました。
これまではGoogle MapのAPIを利用するのはエンジニアなどしかできませんでしたが、生成AIを使えば、詳しくない人でも扱えるレベルになりました。
地理的な側面でデータを表現することで、エクセルの表をにらめっこしているだけでは得られない仮説や知見が得られることもあります。
日本は人口減少社会と迎え、地域課題を考える機会が増えるため、地図を使ったデータビジュアライゼーションが重要となります。
ぜひ、地理的なデータ分析を行いたい場合は生成AIと二人三脚でヒートマップなどビジュアライズを試してください。
なお、まだまだ生成AIは市区町村の町丁レベルの緯度・経度は弱いようです。