神社 地域 にデジタルを
❝地図とグラフで見る大阪府データ❞のコーディング
Django4 python3.10 wsl bootstrap folium geopandas shell_plus pandas plotly
foliumを使って目的のことができることまでは知っていましたが、具体的にコロプレス図について、WEBサイトに表示させるにはどうすれば良いのかは分からず手探りとなりました。
操作はシンプルかつ多くの項目を1箇所で簡便に行えるようにしたかったのですが、この対処に苦労しました。
大阪府の公開データをCSV加工し、DBモデルに投入する独自コマンドを作り、投入したDBモデルをPandasのDataFrameとして扱いました。
境界データを使うためにgeopandasを使いpandasと連携させることで、ポリゴンデータを含む意図したデータが仕上がりました。
Getパラメータの値を、Pandasサイドでgroupbyを用いて絞り込むなどして、目的の表示をさせています。
ただし、動きは遅いです。概要を記します。
<更新:2023-9-6>
グラフの描画が遅いため、plotlyのjsの読み方を工夫しました。
事前準備(手順の概略)
<Poetryで仮想環境を準備(例)>事前にPoetryをインストールしておく
仮想環境をフォルダ直下にする
poetry config virtualenvs.in-project true
~$ mkdir o_poetry_dj
~$ cd o_poetry_dj/
~/o_poetry_dj$ poetry init
以下の設問にEnter、yes、noを入力
This command will guide you through creating your pyproject.toml config.
Package name [o_poetry_dj]:※Enterキー
Version [0.1.0]:※Enterキー
Description []:※Enterキー
Author [user , n to skip]:※Enterキー
License []:※Enterキー
Compatible Python versions [^3.10]:※Enterキー
Would you like to define your main dependencies interactively? (yes/no) [yes] no
Would you like to define your development dependencies interactively? (yes/no) [yes] no
Generated file
[tool.poetry]
name = "o_poetry_dj"
version = "0.1.0"
description = ""
authors = ["user "]
[tool.poetry.dependencies]
python = "^3.10"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Do you confirm generation? (yes/no) [yes] yes
poetry shell
<venvの場合(例)>※venvがインストールされていることを確認
python3 -m venv app_area_data
source app_o_ytdl/bin/activate
以後、仮想環境で作業
必要なパッケージをインストール
<poetryの場合>
(仮想名) poetry add folium geopandas pandas plotly...
<pipの場合>
(仮想名) pip install folium geopandas pandas plotly...
加えて
shell_plusがつかえるようにする ※Djangoのshellでのモデルの操作などが格段に使いやすいものになります。
(仮想名) poetry add django-extensions ...or...
(仮想名) pip install django-extensions
使い方
(仮想名) python manage.py shell_plus
フォームを装飾できるように ※widget_tweaks
(仮想名) poetry add django-widgets-improved ...or...
(仮想名) pip install django-widgets-improved
settings.pyに追記
INSTALLED_APPS = [ … 'widget_tweaks', ]
以上
Djangoプロジェクトにアプリを作成
python manage.py startapp area_data
スーパーユーザーを作成
python manage.py createsuperuser
settings.py(config/settings.py)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
"area_data",
...省略...
# 3th party
'django_extensions',
"widget_tweaks",
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / "templates"],
...省略...
STATIC_URL = 'static/'
STATICFILES_DIRS = [BASE_DIR / "static"]
MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / 'media'
プロジェクトフォルダのsettings.pyに記述
urls.py(config/urls.py)
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path("osaka_data/", include("area_data.urls")),
...省略...
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
プロジェクトフォルダのurls.pyに記述
フォルダ構成
├── area_data/
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── __init__.py
│ ├── management/
│ ├── migrations/
│ ├── models.py
│ ├── __pycache__/
│ ├── tests.py
│ ├── urls.py
│ └── views.py
managementフォルダにcommandsフォルダを作り、load_area_osaka.pyを配置します。
├── management/
│ └── commands/
│ ├── load_area_osaka.py
models.py
from django.db import models
class OsakaBase(models.Model):
city_name = models.CharField(max_length=100)
area = models.FloatField() # 面積
households = models.IntegerField() # 世帯数
population = models.IntegerField()
male_pop = models.IntegerField() # 男性人口
female_pop = models.IntegerField() # 女性人口
n_increase = models.IntegerField() # 自然増
s_increase = models.IntegerField() # 社会増
pop_density = models.IntegerField() # 人口密度
under_15 = models.FloatField() # 15歳未満
over_65 = models.FloatField() # 65歳以上
office = models.IntegerField() # 事業所
employee = models.IntegerField() # 従業員
product_shipment = models.IntegerField() # 製造品出荷
sales = models.IntegerField() # 商品販売
famer = models.IntegerField() # 農家数
manegement_land = models.IntegerField() # 経営耕地
cars = models.IntegerField() # 自動車保有数
settlement_amount = models.IntegerField() # 歳出決算額
resident_tax = models.IntegerField() # 住民税
traffic_accidents = models.IntegerField() # 交通事故数
criminal_offense = models.IntegerField() # 刑法犯
def __str__(self):
return "{}-{}".format(self.city_name, self.area)
models.pyには、大阪府公開データ「データおおさか2023」の項目に合わせたモデルを設計します。
area_data/management/commands/load_area_osaka.py
modelにデータを投入するための独自コマンドを作成
import csv
from django.conf import settings
from django.core.management.base import BaseCommand
from area_data.models import OsakaBase
class Command(BaseCommand):
# データを更新する場合 削除して挿入し直す
# if OsakaBase.objects.count() > 0:
# OsakaBase.objects.all().delete()
help = "大阪府のデータをモデルに投入"
def handle(self, *args, **kwargs):
data_file = settings.BASE_DIR / "data" / "2022_osaka_data.csv"
keys = (
"市町村","面積","世帯数","総人口","男性人口","女性人口","自然増","社会増","人口密度",
"15歳未満","65歳以上","事業所","従業員","製造品出荷","商品販売額","農家数","経営耕地",
"自動車保有数","歳出決算額","住民税","交通事故数","刑法犯"
)
records = []
with open(data_file, "r") as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
records.append({k: row[k] for k in keys})
for record in records:
OsakaBase.objects.get_or_create(
city_name=record["市町村"],
area=record["面積"],
households=record["世帯数"],
population=record["総人口"],
male_pop=record["男性人口"],
female_pop=record["女性人口"],
n_increase=record["自然増"],
s_increase=record["社会増"],
pop_density=record["人口密度"],
under_15=record["15歳未満"],
over_65=record["65歳以上"],
office=record["事業所"],
employee=record["従業員"],
product_shipment=record["製造品出荷"],
sales=record["商品販売額"],
famer=record["農家数"],
manegement_land=record["経営耕地"],
cars=record["自動車保有数"],
settlement_amount=record["歳出決算額"],
resident_tax=record["住民税"],
traffic_accidents=record["交通事故数"],
criminal_offense=record["刑法犯"]
)
以下のコマンドで、DBにデータを投入さします。
(仮想名) python manage.py load_area_osaka
- 大阪府の「データおおさか2023」の一番上にあるexcelファイルを加工
- python manage.py shell_plus でshellを起動し、
- OsakaBase.objects.count() で実数値を見て、BDに投入できたかどうか確認
forms.py
選択可能なChiceFieldのフォームを用意します。
from django import forms
class OsakaDataForm(forms.Form):
DATA_CHOICE = (
("area", "面積:㎢"),
("households", "世帯数:世帯"),
("population", "総人口:人"),
("male_pop", "男性:人"),
("female_pop", "女性:人"),
("n_increase", "自然増減:人"),
("s_increase", "社会増減:人"),
("pop_density", "人口密度:人/k㎡"),
("under_15", "15歳未満:%"),
("over_65", "65歳以上:%"),
("office", "事業所数:所"),
("employee", "従業者数"),
("product_shipment", "製造品出荷:百万円"),
("sales", "年間商品販売:百万円"),
("famer", "総農家数:戸"),
("manegement_land", "経営耕地面積:ha"),
("cars", "保有自動車:台"),
("settlement_amount", "歳出決算額:百万円"),
("resident_tax", "個人住民税:千円"),
("traffic_accidents", "交通事故:件"),
("criminal_offense", "刑法犯:件")
)
cho = forms.ChoiceField(label="項目を選択", choices=DATA_CHOICE)
class OsakaProcessForm(forms.Form):
DATA_CHOICE = (
("per_person", "市町村の住民一人換算の住民税:千円"),
("car_person", "市町村の住民一人換算の自動車保有:台"),
("accident_peoples", "市町村の千人あたり換算の交通事故:件"),
("crime_peoples", "市町村の千人あたり換算の刑法犯:件"),
)
choice = forms.ChoiceField(label="項目を選択", choices=DATA_CHOICE)
urls.py
from django.urls import path
from .views import (
osaka_map_index,
osaka_map_process,
osaka_bar_65over,
osaka_bar_density,
osaka_bar_tax,
osaka_bar_crime,
osaka_bar_home,
)
app_name = "area_data"
urlpatterns = [
path("", osaka_map_index, name="map_index"),
path("map_process/", osaka_map_process, name="map_process"),
path("bar_home/", osaka_bar_home, name="bar_home"),
path("bar_65over/", osaka_bar_65over, name="over65"),
path("bar_density/", osaka_bar_density, name="density"),
path("bar_tax/", osaka_bar_tax, name="tax"),
path("bar_crime/", osaka_bar_crime, name="crime"),
]
地図とグラフを表示させるためのurlの設定
views.py
from django.shortcuts import render
import folium
import geopandas as gpd
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from .models import OsakaBase
from .forms import OsakaDataForm, OsakaProcessForm
from django.conf import settings
from branca.element import Figure
def osaka_map_index(request):
data = OsakaBase.objects.all().values()
df = pd.DataFrame(data)
choice = request.GET.get("cho")
if choice:
choice= choice
else:
choice="under_15"
# choice = "criminal_offense"
print(choice)
### GeoJsonの読み込みと整形 ###
geo_data = settings.BASE_DIR / "data" / "2022_midiam_osaka_boundary_non_seie.json"
geo_df = gpd.read_file(geo_data)
# null値のN03_002を削除
geo_df.drop(columns="N03_002", inplace=True)
# 政令指定都市の大阪市と堺市を一般市町村列(N03_004)に代入
geo_df.loc[0, "N03_004"] = "大阪市"
geo_df.loc[1, "N03_004"] = "堺市"
# 表記名の違いが無いか確認
# df_ = set(df["city_name"].unique().tolist())
# gdf_ = set(geo_df["N03_004"].unique().tolist())
# print(df_-gdf_)
# ポリゴンデータを集約
geo_2022_porigon = geo_df[["N03_004", "geometry"]]
### GeoJson編集 ###
# ポリゴンデータとdfデータを結合
gdf_2022_all = pd.concat([geo_2022_porigon, df], axis=1)
# print(gdf_2022_all)
# 目印のpref番号をふる
gdf_2022_all["pref"] = [x for x in range(1, 44)]
gdf_2022_all["pref"] = gdf_2022_all["pref"].astype("str")
### Map 処理 ###
gdf_2022_all.crs = "epsg:4326"
osaka_pop = folium.Map(
location=[34.68639,135.52],
tiles="cartodbpositron",
zoom_start=10
)
folium.Choropleth(
geo_data=gdf_2022_all,
data=gdf_2022_all,
columns=["pref", choice],
key_on="feature.properties.pref",
name="大阪府データ",
fill_color="RdPu",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="大阪府のデータ",
reset=True,
).add_to(osaka_pop)
style_function = lambda x: {
"fillColor": "#ffffff",
"color": "#000000",
"fillOpacity": 0.1,
"weight": 0.1
}
highlight_function = lambda x: {
"fillColor": "#000000",
"color": "#000000",
"fillOpacity": 0.50,
"weight": 0.1
}
NIL = folium.features.GeoJson(
gdf_2022_all,
style_function=style_function,
control=False,
highlight_function=highlight_function,
tooltip=folium.features.GeoJsonTooltip(
fields=["city_name", choice],
aliases=["名前 : ", "数量 : "],
style=("background-color: white; color: #333333; font-family: arial; font-size: 12px; padding: 10px")
)
).add_to(osaka_pop)
### ###
fig = Figure(height=700)
fig.add_child(osaka_pop)
context = {"map": osaka_pop._repr_html_(),
"form": OsakaDataForm(),
}
return render(request, "area_data/main.html", context)
def osaka_map_process(request):
data = OsakaBase.objects.all().values()
df = pd.DataFrame(data)
df_per = df[["city_name", "population", "resident_tax", "cars",
"traffic_accidents", "criminal_offense"]]
choice = request.GET.get("choice")
if choice:
choice= choice
else:
choice="crime_peoples"
# 前処理
df_per_c = df_per.copy()
df_per_c["per_person"] = df_per["resident_tax"] / df_per["population"]
df_per_c["car_person"] = df_per["cars"] / df_per["population"]
df_per_c["accident_peoples"] = df_per["traffic_accidents"] / df_per["population"] * 1000
df_per_c["crime_peoples"] = df_per["criminal_offense"] / df_per["population"] * 1000
### GeoJsonの読み込みと整形 ###
geo_data = settings.BASE_DIR / "data" / "2022_midiam_osaka_boundary_non_seie.json"
geo_df = gpd.read_file(geo_data)
# null値のN03_002を削除
geo_df.drop(columns="N03_002", inplace=True)
# 政令指定都市の大阪市と堺市を一般市町村列(N03_004)に代入
geo_df.loc[0, "N03_004"] = "大阪市"
geo_df.loc[1, "N03_004"] = "堺市"
# 表記名の違いが無いか確認
# df_ = set(df["city_name"].unique().tolist())
# gdf_ = set(geo_df["N03_004"].unique().tolist())
# print(df_-gdf_)
# ポリゴンデータを集約
geo_2022_porigon = geo_df[["N03_004", "geometry"]]
### GeoJson編集 ###
# ポリゴンデータとdfデータを結合
gdf_2022_all = pd.concat([geo_2022_porigon, df_per_c], axis=1)
# print(gdf_2022_all)
# 目印のpref番号をふる
gdf_2022_all["pref"] = [x for x in range(1, 44)]
gdf_2022_all["pref"] = gdf_2022_all["pref"].astype("str")
### Map 処理 ###
gdf_2022_all.crs = "epsg:4326"
osaka_pop = folium.Map(
location=[34.68639,135.52],
tiles="cartodbpositron",
zoom_start=10
)
folium.Choropleth(
geo_data=gdf_2022_all,
data=gdf_2022_all,
columns=["pref", choice],
key_on="feature.properties.pref",
name="大阪府の市町村別MAPデータ",
fill_color="RdPu",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="大阪府のデータ",
reset=True,
).add_to(osaka_pop)
style_function = lambda x: {
"fillColor": "#ffffff",
"color": "#000000",
"fillOpacity": 0.1,
"weight": 0.1
}
highlight_function = lambda x: {
"fillColor": "#000000",
"color": "#000000",
"fillOpacity": 0.50,
"weight": 0.1
}
NIL = folium.features.GeoJson(
gdf_2022_all,
style_function=style_function,
control=False,
highlight_function=highlight_function,
tooltip=folium.features.GeoJsonTooltip(
fields=["city_name", choice],
aliases=["名前 : ", "数量 : "],
style=("background-color: white; color: #333333; font-family: arial; font-size: 12px; padding: 10px")
)
).add_to(osaka_pop)
### ###
fig = Figure(height=700)
fig.add_child(osaka_pop)
context = {"map": osaka_pop._repr_html_(),
"form": OsakaProcessForm(),
}
return render(request, "area_data/per_map.html", context)
def osaka_bar_65over(request):
data = OsakaBase.objects.all().values()
df = pd.DataFrame(data)
df_per = df[["city_name", "population", "over_65", "pop_density", "resident_tax",
"criminal_offense"]]
# 前処理
df_per_c = df_per.copy()
df_per_c["per_person"] = df_per["resident_tax"] / df_per["population"]
df_per_c["crime_peoples"] = df_per["criminal_offense"] / df_per["population"] * 1000
df_per_c = df_per_c.sort_values("over_65")
# グラフ処理
marker_color = []
for c in df_per_c["city_name"]:
# print(c)
if c == "豊中市":
marker_color.append("#1D6A96")
else:
marker_color.append("#D1DDDB")
fig = go.Figure()
fig.add_trace(go.Bar(
y=df_per_c["city_name"],
x=df_per_c["over_65"],
textfont={"color": "#030305"},
name="65歳以上"
))
fig.update_traces(
width=0.9,
marker_color=marker_color,
texttemplate="%{x:0.1f}%",
textposition="outside",
orientation="h"
)
fig.update_layout(
title="<b>大阪府 各市町村の65歳以上の人口に占める割合",
xaxis={"range": (0, 55),
"showticklabels": False,
# "range": (0, 18)
},
# yaxis={"range": (-2, 44)},
# width=800,
height=1200,
plot_bgcolor="white"
)
html = fig.to_html(include_plotlyjs=False))
context = {"chart": html}
return render(request, "area_data/bar_65over.html", context)
def osaka_bar_density(request):
data = OsakaBase.objects.all().values()
df = ...
上のコードとほぼ同じ
... "area_data/bar_density.html", context)
def osaka_bar_tax(request):
data = OsakaBase.objects.all().values()
df = ...
上のコードとほぼ同じ
..."area_data/bar_tax.html", context)
def osaka_bar_crime(request):
data = OsakaBase.objects.all().values()
df = ...
上のコードとほぼ同じ
..."area_data/bar_crime.html", context)
def osaka_bar_home(request):
return render(request, "area_data/bar_home.html", {})
views.pyが肝になるところなので、長いコードになりました。
- geopandasで境界データを読み込みます。29行目
- 政令指定都市は区をまとめて一つの市町村とします。35行目
- 大阪府の中心をlocationに指定してマップを作成。59行目以降
- Getパラメータで受け取った値を、コロプレス図で指定して、項目に応じた表示に切り分けます。69行目
2023-9-6追記※修正
html = fig.to_html(include_plotlyjs=False)
この記述でjsの読み込みをFalseとします。268行目
- 217行目以降はplotlyを用いたグラフ表示用のコードです。
- 私の住む豊中市を目立つように色付けしています。234行目
templates/base.html
※雛形のイメージhtmlです 用途に合わせて手直してください
{% load static %}
<!doctype html>
<html lanh=ja>
<head>
<!-- Require meta tags -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0", shrink-to-fit=none>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<!-- custom css & js -->
<link rel="stylesheet" href="{% static 'style.css' %}">
<script src="{% static 'main.js' %}" defer></script>
<title>Spiner | {% block title %}{% endblock title %}</title>
</head>
<body>
<div class="container mt-3">
{% block content %}
{% endblock content %}
</div>
<!-- Optional Javascript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS-->
<script
src="https://code.jquery.com/jquery-3.6.3.min.js"
integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU="
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
</body>
</html>
templates/area_data/main.html
base.htmlを継承した表示用のhtmlを作成します。
{% extends 'base.html' %}
{% load widget_tweaks %}
{% block title %}地図で見る大阪府データ 基本項目{% endblock title %}
{% block contents %}
<div class="row">
{{ get_name_display }}
<div class="col">
<h3 class="mb-3">地図で見る大阪府データ 基本項目</h3>
<form method="GET" action="{% url 'area_data:map_index' %}" name="area_form">
{% comment %} {{ form.as_p }} {% endcomment %}
{% for field in form %}
<div class="form-group">
{{ field.label_tag }}
{% render_field field class="form-control" style="border:1px solid #ccc;width:300px;" %}
{% if field.help_text %}
<small class="form-text text-muted">
{{ field.help_text }}
</small>
{% endif %}
</div>
{% endfor %}
<button class="btn btn-dark rounded-capsule mb-3" onclick="clickBtn1()">表示</button>
</form>
<h5 class="text-center">大阪府内の各市町村「<span id="span_data"></span>」の分布</h5>
{{ map|safe }}
<p><small>参照:データおおさか2023(令和5年3月作成)<br>
https://www.pref.osaka.lg.jp/toukei/d-osaka/index.html</small></p>
<p><small>大阪府のポリゴンデータ<br>
「大阪府 市区町村(政令指定都市統合版) コロプレス地図(塗り分け地図) | 歴史的行政区域データセットβ版」中解像度<br>
https://geoshape.ex.nii.ac.jp/city/choropleth/27_city_dc.html</small></p>
</div>
</div>
<script>
// getパラメータからselectboxのテキストを抜き出す
// URLのクエリストリングを取得
const queryString = window.location.search;
// URLSearchParamsオブジェクトを作成
const urlParams = new URLSearchParams(queryString);
// selectboxパラメータの値を取得
const selectboxValue = urlParams.get('cho');
if (selectboxValue === null) {
document.getElementById("span_data").textContent = "15歳未満:%";
}
console.log(selectboxValue)
// selectboxのoption要素を取得
const selectbox = document.getElementById('id_cho');
// 選択肢と一致するものを選択
for (let i = 0; i < selectbox.options.length; i++) {
if (selectbox.options[i].value === selectboxValue) {
selectbox.options[i].selected = true;
const txt = selectbox.options[i].text;
console.log(txt)
document.getElementById("span_data").textContent = txt;
break;
}
}
</script>
{% endblock contents %}
- ChoiceFieldのフォームを表示
- Javascriptで、selectした項目が遷移後に選択状態となるようにするために記述
- {% load widget_tweaks %}はフォームのレンダリングを装飾するためのタグ
templates/area_data/bar_65over.html
棒グラフ表示用のhtmlを作成します。
{% extends 'base.html' %}
{% block title %}大阪府 各市町村の65歳以上の割合{% endblock title %}
{% block head_scripts %}
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
{% endblock head_scripts %}
{% block contents %}
<div class="row">
<div class="col">
<h3>グラフで見る大阪府のデータ</h3>
<div class="dropdown dropdown-on-hover d-inline-block">
<button class="btn btn-dark dropdown-toggle" id="dropdownMenuHoverButton" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">大阪府データのグラフを選択</button>
<div class="dropdown-menu dropdown-menu-right py-0" aria-labelledby="dropdownMenuHoverButton">
<a class="dropdown-item" href="{% url 'area_data:over65' %}">各市町村の65歳以上の人口に占める割合</a>
<a class="dropdown-item" href="{% url 'area_data:density' %}">各市町村の人口密度:人/k㎡</a>
<a class="dropdown-item" href="{% url 'area_data:tax' %}">各市町村の住民税/一人</a>
<a class="dropdown-item" href="{% url 'area_data:crime' %}">各市町村の刑法犯/千人</a>
</div>
</div>
{{ chart|safe }}
<p><small>参照:データおおさか2023(令和5年3月作成)<br>
https://www.pref.osaka.lg.jp/toukei/d-osaka/index.html</small></p>
</div>
</div>
{% endblock contents %}
ほぼ同じ内容のテンプレートを用意します。
- templates/area_data/bar_crime.html
- templates/area_data/bar_density.html
- templates/area_data/bar_tax.html
- templates/area_data/bar_home.html
2023-9-6追記※修正
冒頭部分でplotlyのjsをcdnで読み込みます。6行目
投稿内容 ランダム表示
豊中市MAPの基データのコーディング
最終更新:2023年07月14日
❝ユーチューブのダウンロード❞の使い方
最終更新:2023年07月14日
❝地図とグラフで見る大阪府データ❞のコーディング
最終更新:2023年09月06日
豊中市MAPの基データの説明
最終更新:2023年07月14日
python3.10 Django4 wsl bootstrap javascript
カテゴリ
私の願い
私は神社の宮司です。神社や地域を担う次世代の人々に対し、何かを残してお役に立ててもらいたいとの願いが、強く芽生えました。個業としての神社や、小規模な地域社会に、恩恵が届くのが遅くなりそうな「デジタル」の分野。門外漢として奮闘した実体験から得た経験則を、わずかずつでも残し未来につなぎたいと願うばかりです。
最近の投稿
- 簡易で安価なカメラで防犯・外出対策を
最終更新:2023年09月08日
- 神社のオリジナルTシャツを作ってみた
最終更新:2023年08月07日
- HTMLメールを活用してみた
最終更新:2023年07月14日
- 豊中市Graphの基データの説明
最終更新:2023年07月14日