PYTHONではじめてのWEBサイトを作成 11
さてさて今回は分析ページを作りたいと思います。
コンテンツは2つ
・毎月日本のバインミーショップの数をグラフ化
・現在のバインミーショップの数を日本地図に都道府県別にヒートマップで表現
分析ページの作成
分析ページには、都道府県別の店舗数のヒートマップと、毎月の店舗数の増加グラフを表示します。
日本地図のヒートマップの作成方法
使用ライブラリとAPI
Google Charts API geochartパッケージ:
ヒートマップを作成するためには、Google Chartsのgeochartパッケージを使用します。
Google Maps JavaScript API:
ヒートマップや他の地理情報を表示するために、geochartパッケージと組み合わせて使用されます。
GEOCHARTでの日本地図のヒートマップの実現方法
データ収集:
Google Places APIを使用して、データベースを作成。すでにデータはあるので今回は都道府県の英語のフィールドを追加。
データベースの更新:
取得したデータをDjangoモデル(例:Storeモデル)に保存します。データベースには、日本語の都道府県名と対応する英語名の両方を保持。
データの加工:
Djangoビューで、指定された月の都道府県別店舗数を集計します。この集計結果をヒートマップ用のデータとしてフォーマット。
ヒートマップの描画:
Google Charts APIのgeochartパッケージを使用して、日本地図上にヒートマップを描画します。具体的には、都道府県ごとの店舗数を色で示します。
GEOCHARTでの日本地図のヒートマップの手順
使用ライブラリとAPI
Google Maps JavaScript APIのロード:
必要なAPIキーを使用して、Google Maps JavaScript APIをロード。
geochartパッケージをロード。
データの準備:
Djangoから提供されたデータをJavaScriptで受け取り、Google ChartsのarrayToDataTableメソッドを使用してデータテーブルを作成。
ヒートマップのオプション設定:
regionオプションをJPに設定し、日本全体を表示。
displayModeをregionsに設定し、resolutionをprovincesに設定。
ヒートマップの描画:
Google ChartsのGeoChartクラスを使用して、データテーブルを地図上に描画。
CORECHARTで全国のバインミー店舗数のグラフ作成方法
Google Charts API:
店舗数の推移を視覚化するために、corechartパッケージを使用。
CORECHARTで全国のバインミー店舗数のグラフ作成実現方法
データ収集:
各月ごとの店舗数をDjangoモデル(例:MonthlyDataモデル)に保存。
データの加工:
Djangoビューで、月別の店舗数を集計し、グラフ用のデータとしてフォーマット。
グラフの描画:
Google Charts APIのcorechartパッケージを使用して、折れ線グラフを描画。
CORECHARTで全国のバインミー店舗数の推移グラフの手順
データの準備:
Djangoから提供されたデータをJavaScriptで受け取り、Google ChartsのarrayToDataTableメソッドを使用してデータテーブルを作成。
グラフのオプション設定:
titleオプションを設定し、グラフのタイトルを設定。
curveTypeをfunctionに設定し、曲線をスムーズに。
legendオプションで凡例の位置を設定。
グラフの描画:
Google ChartsのLineChartクラスを使用して、データテーブルをグラフ上に描画。
分析ページのコーディング
models.pyを更新
表示のために都道府県名を漢字に置き換えたが、漢字だとヒートマップの表示がうまくいかずに苦戦した結果、modelsに都道府県を英語と漢字で持たせることにする
class Store(models.Model):
name = models.CharField(max_length=255) # 店名
prefecture = models.CharField(max_length=100) # 都道府県
prefecture_en = models.CharField(max_length=100, default="Unknown")
city = models.CharField(max_length=100) # 市区町村
website = models.URLField(blank=True, null=True)
url = models.URLField() # URL
rating = models.FloatField() # レーティング
review_count = models.IntegerField() # レビュー数
latitude = models.FloatField() # 緯度
longitude = models.FloatField() # 経度
place_id = models.CharField(max_length=255, unique=True) # Google Place ID
weighted_score = models.FloatField(null=True, blank=True) # 加重スコア
registered_date = models.DateField() # 取得日
registered_month = models.CharField(max_length=7, default='2024-01') # 取得月 (YYYY-MM形式)
def calculate_weighted_score(self):
if self.review_count == 0:
self.weighted_score = 0
print(f'{self.name}: Review count is zero, weighted score set to 0')
return
prefecture_en = models.CharField(max_length=100, default="Unknown")
デフォルトも設定
慣れてきたマイグレーション
python manage.py makemigrations
python manage.py migrate
コマンドで都道府県を英語に再変換
banhmilove/banhmilove_app/management/commands/update_prefecture_en.py
from django.core.management.base import BaseCommand
from banhmilove_app.models import Store
# 都道府県名のマッピング
prefecture_mapping = {
"北海道": "Hokkaido",
"青森県": "Aomori",
"岩手県": "Iwate",
"宮城県": "Miyagi",
"秋田県": "Akita",
"山形県": "Yamagata",
"福島県": "Fukushima",
"茨城県": "Ibaraki",
"栃木県": "Tochigi",
"群馬県": "Gunma",
"埼玉県": "Saitama",
"千葉県": "Chiba",
"東京都": "Tokyo",
"神奈川県": "Kanagawa",
"新潟県": "Niigata",
"富山県": "Toyama",
"石川県": "Ishikawa",
"福井県": "Fukui",
"山梨県": "Yamanashi",
"長野県": "Nagano",
"岐阜県": "Gifu",
"静岡県": "Shizuoka",
"愛知県": "Aichi",
"三重県": "Mie",
"滋賀県": "Shiga",
"京都府": "Kyoto",
"大阪府": "Osaka",
"兵庫県": "Hyogo",
"奈良県": "Nara",
"和歌山県": "Wakayama",
"鳥取県": "Tottori",
"島根県": "Shimane",
"岡山県": "Okayama",
"広島県": "Hiroshima",
"山口県": "Yamaguchi",
"徳島県": "Tokushima",
"香川県": "Kagawa",
"愛媛県": "Ehime",
"高知県": "Kochi",
"福岡県": "Fukuoka",
"佐賀県": "Saga",
"長崎県": "Nagasaki",
"熊本県": "Kumamoto",
"大分県": "Oita",
"宮崎県": "Miyazaki",
"鹿児島県": "Kagoshima",
"沖縄県": "Okinawa"
}
class Command(BaseCommand):
help = 'Update stores with prefecture English names'
def handle(self, *args, **kwargs):
stores = Store.objects.all()
for store in stores:
store.prefecture_en = prefecture_mapping.get(store.prefecture, store.prefecture)
store.save()
self.stdout.write(self.style.SUCCESS(f'Updated {store.name} with prefecture_en {store.prefecture_en}'))
python manage.py update_prefecture_en.py
ヒートマップとラインチャートの関数をviews.pyに更新
from django.shortcuts import render
from .models import Store
from collections import defaultdict
def analysis(request):
# 都道府県別の店舗数をカウント
prefecture_counts = Store.objects.values('prefecture').annotate(count=models.Count('id'))
# ヒートマップ用データの準備
heatmap_data = [["都道府県", "店舗数"]]
for item in prefecture_counts:
heatmap_data.append([item['prefecture'], item['count']])
# 月別の店舗数をカウント
monthly_counts = Store.objects.values('registered_month').annotate(count=models.Count('id')).order_by('registered_month')
# グラフ用データの準備
graph_data = [["月", "店舗数"]]
for item in monthly_counts:
graph_data.append([item['registered_month'], item['count']])
return render(request, 'banhmilove_app/analysis.html', {
'heatmap_data': heatmap_data,
'graph_data': graph_data
})
分析ページのテンプレート作成
analysis.html
{% extends 'banhmilove_app/base.html' %}
{% block content %}
<div class="container">
<h1>店舗分析</h1>
<ul class="nav nav-tabs" id="analysisTabs" role="tablist">
<li class="nav-item" role="presentation">
<a class="nav-link active" id="heatmap-tab" data-bs-toggle="tab" href="#heatmap" role="tab" aria-controls="heatmap" aria-selected="true">ヒートマップ</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="linechart-tab" data-bs-toggle="tab" href="#linechart" role="tab" aria-controls="linechart" aria-selected="false">店舗数推移</a>
</li>
</ul>
<div class="tab-content" id="analysisTabsContent">
<div class="tab-pane fade show active" id="heatmap" role="tabpanel" aria-labelledby="heatmap-tab">
<div id="heatmapChart" style="width: 100%; height: 500px;"></div>
</div>
<div class="tab-pane fade" id="linechart" role="tabpanel" aria-labelledby="linechart-tab">
<div id="linechartChart" style="width: 100%; height: 500px;"></div>
</div>
</div>
</div>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
function loadGoogleMapsApi() {
var script = document.createElement('script');
script.src = 'https://maps.googleapis.com/maps/api/js?key={{ GOOGLE_MAPS_API_KEY }}&libraries=places&callback=initMap';
script.async = true;
script.defer = true;
document.head.appendChild(script);
}
function initMap() {
google.charts.load('current', {
'packages': ['geochart', 'corechart']
});
google.charts.setOnLoadCallback(drawCharts);
}
function drawCharts() {
console.log("Drawing charts...");
// ヒートマップ
var heatmapData = google.visualization.arrayToDataTable({{ heatmap_data|safe }});
console.log("Heatmap data:", heatmapData.toJSON());
var heatmapOptions = {
region: 'JP',
displayMode: 'regions',
resolution: 'provinces'
};
var heatmapChart = new google.visualization.GeoChart(document.getElementById('heatmapChart'));
heatmapChart.draw(heatmapData, heatmapOptions);
// ラインチャート
var linechartData = google.visualization.arrayToDataTable({{ graph_data|safe }});
console.log("Linechart data:", linechartData.toJSON());
var linechartOptions = {
title: '毎月の店舗数の増加',
curveType: 'function',
legend: { position: 'bottom' }
};
var linechart = new google.visualization.LineChart(document.getElementById('linechartChart'));
linechart.draw(linechartData, linechartOptions);
}
// Google Maps APIを非同期にロード
loadGoogleMapsApi();
</script>
{% endblock %}
できたー
最近、苦戦が続くのでできた時の喜びもひとしお
まとめ
今回はGoogle Charts APIのgeochartパッケージとcorechartパッケージを利用して日本地図上にヒートマップでバインミーの都道府県の店舗数を表示して、ラインチャートで全国のバインミーの店舗数の推移を表現しました。
あとやることは、
・ハッシュタグを取得してNEWSを表示
・google ad導入
・AWSにデプロイ
その後に色々改善しようと思います。
システム開発は設計が大事だと痛感できた今日この頃
データや機能追加の際によく考えておかないと
後でやり直しが複雑になりますね!
理屈ではわかるけどやってみてはいめて痛感することが多くありますね。
ではまた