Python {Article152}

ようこそ「Python」へ...

Python: Plotlyでデータサイエンティストのように日本の人口データから高齢化率・少子化率を分析して見る【Pythonデータ分析】

ここでは、Plotlyを使用してデータサイエンティストのように日本の人口データから高齢化率・少子化率を可視化して分析する方法を解説します。 本記事では、総務省統計局が公開している「年齢別人口データ(2021年度)」を使用しています。 このファイル(Excel)には、 4種類(15歳未満、15~64歳、65歳以上、75歳以上)の人口データが男女別に格納されています。 ここでは、これらの人口データを利用して都道府県別の高齢化率・少子化率等を可視化して分析します。

Pythonには、Matplotlib, Seaborn, Plotly Express, Plotly Graph Objectsなどのグラフを作成するライブラリがあります。

MatplotlibとSeabornは、 静的なグラフを作成するために設計されたPythonライブラリであるのに対して、 Plotlyはインタラクティブなグラフを作成するために設計されています。 したがって、Plotlyは、グラフを拡大・縮小したり、 マウスホーバーでデータ値を表示するなどのインタラクティブな操作が可能で、 より直感的なデータの解析ができるようになっています。 なので、ここではPlotlyのインタラクティブな機能を利用してデータを解析します。

なお、Plotlyは Dashを使用することによりWebブラウザ上で対話的なデータ可視化も可能になります。 Plotlyは、以下のようなさまざまなグラフを作成してデータを可視化することができます。
  • Scatter Plot(散布図):
    用途:2つの量的変数間の関係を可視化するために使用されます。
    特徴:点がプロットされ、X軸とY軸に数値が表示されます。 複数のグループを区別する場合、色や形状で表現できます。

  • Line Plot(折れ線グラフ):
    用途:量的変数の時間的変化を可視化するために使用されます。
    特徴:点を線で接続し、時間や数値の連続した変化を表現します。

  • Bar Chart(棒グラフ):
    用途:カテゴリ別の数量や割合の比較を可視化するために使用されます。
    特徴:カテゴリ(X軸)と数値(Y軸)が表示され、複数のグループを区別する場合、色やパターンで表現できます。

  • Pie Chart(円グラフ):
    用途:カテゴリ内の数量の比率を可視化するために使用されます。
    特徴:円形で表現され、各カテゴリの部分が円周上に表示されます。 一般的には、4つ以上のカテゴリに使用すると読みやすくなります。

  • Histogram(ヒストグラム):
    用途:数量データの分布を可視化するために使用されます。
    特徴:数値の範囲がビンに分割され、ビンごとにデータが表示されます。 ビンの幅は、分布の特性に応じて調整できます。

  • Sunburst(サンバーストチャート):
    用途:階層的なカテゴリ構造を可視化するために使用されます。
    特徴:中心から外側に向かってカテゴリが分割され、各セグメントの大きさは割合で表示されます。

  • Treemap(ツリーマップ):
    用途:階層的なカテゴリ構造を可視化するために使用されます。サンバーストチャートと同じく、会社の部門、チーム、プロジェクトなどの関係性を示すことができます。
    特徴:四角形の領域がカテゴリを表し、領域の大きさはカテゴリの値に比例します。 それぞれの四角形は、色やラベルなどの要素を持つことができます。ツリーマップは、視覚的に洞察力を得るために、大量のデータを表示するのに適しています。

  • Choropleth(コロプレス図):
    用途:地理的なデータを可視化するために使用されます。地域ごとの数量や比率を示すことができます。たとえば、国別の人口、都市別の収入などを表示できます。
    特徴:地図上の地域ごとに色を割り当てて表示します。 色は、数量や比率の大小に応じて異なり、カラーマップを選択することができます。 コロプレス図は、地域ごとのパターンを見つけるのに役立ちます。また、マウスオーバー時に詳細な情報を表示することもできます。

これらのグラフはすべて、Plotly Expressで簡単に作成することができます。 また、Plotly Expressは、多数のオプションやカスタマイズ機能を提供しているため、 データの視覚化において幅広い用途に利用できます。

説明文の左側に図の画像が表示されていますが縮小されています。 画像を拡大するにはマウスを画像上に移動してクリックします。 画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。 画像の任意の場所をクリックして閉じることもできます。
click image to zoom!
図A
click image to zoom!
図B
click image to zoom!
図C
click image to zoom!
図D
click image to zoom!
図E
click image to zoom!
図F
click image to zoom!
図G
click image to zoom!
図H
click image to zoom!
図I
click image to zoom!
図J
click image to zoom!
図K
click image to zoom!
図L
click image to zoom!
図M
click image to zoom!
図N
click image to zoom!
図O

Plotly Expressでデータサイエンティストのように日本の人口データから高齢化率・少子化率を分析して見る【Pythonデータ分析】

  1. まずは、Pythonの開発環境を準備する

    まずは、 「記事(Article137)」を参照して、 Pythonの開発環境を準備してください。 ここでは、Pythonのプロジェクトフォルダとして「Plotly」を使用しています。

    click image to zoom!
    図1
    図1は、Visual Studio Code(VS Code)の「Terminal」メニューから「New Terminal」を選択して、 「Terminal」ウィンドウを開いたときの画面です。 緑色の「(venv)」が表示されていれば、 Pythonの仮想環境が正常に作成されていることになります。
  2. Visual Studio Codeを起動してプログラムファイルを作成する

    Pythonの開発環境の準備が完了したら、 VS Codeを起動して新規のPythonファイル(*.py)を作成します。 ここで作成したPythonのファイルには「リスト8-1」のコードをコピペします。

    click image to zoom!
    図2
    図2は、VS Codeの画面です。
  3. 日本の人口データを分析(可視化)するためのデータを用意する

    ここでは、総務省統計局のWebサイトからダウンロードした人口データ(Excelファイル)を加工してPlotly Expressで分析するためのデータを用意します。

    ### 0: prepare data
    
    # 0-1: read a population data from a csv file
    csv_file = r'https://money-or-ikigai.com/Menu/Python/Article/data/map/japan_population_by_prefecture_age(2021).csv'
    # csv_file = 'datasets/csv/japan_population_by_prefecture_age(2021).csv'
    df = pd.read_csv(csv_file)
    # df.info()
    # df
    
    
    # %%
    
    ### 0-2: clean up data
    pd.options.mode.chained_assignment = None
    
    df['prefecture_jp'] = df['prefecture_jp'].apply(lambda x: x.replace(' ',''))
    df['prefecture_jp'] = df['prefecture_jp'].apply(lambda x: x.replace(' ',''))
    
    df['male_adult']   = df['male_adult'].apply(lambda x: int(x.replace(',','')))
    df['male_over65']  = df['male_over65'].apply(lambda x: int(x.replace(',','')))
    
    df['female_adult']   = df['female_adult'].apply(lambda x: int(x.replace(',','')))
    df['female_over65']  = df['female_over65'].apply(lambda x: int(x.replace(',','')))
    df['female_over75']  = df['female_over75'].apply(lambda x: int(x.replace(',','')))
    
    dfx = df[['prefecture_jp','male_under15','male_adult','male_over65','male_over75','female_under15','female_adult','female_over65','female_over75']]
    # dfx.info()
    # dfx.isnull().sum()
    
    
    # %%
    
    ### 0-3: add the columns
    dfx['male_under15'] = dfx['male_under15'].apply(lambda x: x * 1000)
    dfx['male_adult']   = dfx['male_adult'].apply(lambda x: x * 1000)
    dfx['male_over65']  = dfx['male_over65'].apply(lambda x: x * 1000)
    dfx['male_over75']  = dfx['male_over75'].apply(lambda x: x * 1000)
    
    dfx['female_under15'] = dfx['female_under15'].apply(lambda x: x * 1000)
    dfx['female_adult']   = dfx['female_adult'].apply(lambda x: x * 1000)
    dfx['female_over65']  = dfx['female_over65'].apply(lambda x: x * 1000)
    dfx['female_over75']  = dfx['female_over75'].apply(lambda x: x * 1000)
    
    dfx['pop_under15'] = dfx.apply(lambda row: row['male_under15'] + row['female_under15'], axis=1)
    dfx['pop_adult']   = dfx.apply(lambda row: row['male_adult'] + row['female_adult'], axis=1)
    dfx['pop_over65']  = dfx.apply(lambda row: row['male_over65'] + row['female_over65'], axis=1)
    dfx['pop_over75']  = dfx.apply(lambda row: row['male_over75'] + row['female_over75'], axis=1)
    
    dfx['pop_male']   = dfx.apply(lambda row: row['male_under15'] + row['male_adult'] + row['male_over65'], axis=1)
    dfx['pop_female'] = dfx.apply(lambda row: row['female_under15'] + row['female_adult'] + row['female_over65'], axis=1)
    dfx['pop']        = dfx.apply(lambda row: row['pop_male'] + row['pop_female'], axis=1)
    
    dfx['pop_under15_ratio'] = dfx.apply(lambda row: round((row['pop_under15'] / row['pop']) * 100, 2), axis=1)
    dfx['pop_adult_ratio']   = dfx.apply(lambda row: round((row['pop_adult']   / row['pop']) * 100, 2), axis=1)
    dfx['pop_over65_ratio']  = dfx.apply(lambda row: round((row['pop_over65']  / row['pop']) * 100, 2), axis=1)
    dfx['pop_over75_ratio']  = dfx.apply(lambda row: round((row['pop_over75']  / row['pop']) * 100, 2), axis=1)
    
    
    # %%
    
    ### 0-4: Read a GeoJson file
    
    url = r'https://money-or-ikigai.com/Menu/Python/Article/data/map/prefectures.json'
    response = urllib.request.urlopen(url)
    geo_data = response.read().decode('utf-8')
    japan_prefectures = json.loads(geo_data)
    # json_file = 'datasets/json/prefectures.json'
    # japan_prefectures = json.load(open(json_file, 'r'))
    # japan_prefectures
    
    
    # %%
    
    ### 0-5: Load a prefecture id map dictionary from the geojson data
    # Create an empty dictionary to store prefecture IDs
    prefecture_id_map = {}
    
    # Loop through the "features" list in the "japan_prefectures" dictionary
    for feature in japan_prefectures['features']:    
        feature['id'] = feature['properties']['pref']
        prefecture_id_map[feature['properties']['name']] = feature['id']
    # prefecture_id_map
    
    
    # %%
    
    ### 0-6: Load Japan geo data from a csv file
    
    geo_csv = r'https://money-or-ikigai.com/Menu/Python/Article/data/map/japan_geo.csv'
    # geo_csv = 'datasets/csv/japan_geo.csv'
    geo_df = pd.read_csv(geo_csv)
    # geo_df
    
    
    # %%
    
    ### 0-7: Filter columns from the pandas dataframe
    
    geo_df = geo_df[['region_en','region_jp','prefecture_en','prefecture_jp']]
    # geo_df
    
    
    # %%
    
    ### 0-8: Concatenate the Japan census and geojason data horizontally based on the 'prefecture_jp' column
    
    # Set the "prefecture_jp" column as the index for the "dfx" DataFrame
    dfx_jp = dfx.set_index('prefecture_jp')
    
    # Set the "prefecture_jp" column as the index for the "geo_df" DataFrame
    geojp_df =  geo_df.set_index('prefecture_jp')
    
    # Concatenate the "dfx" and "geo_df" DataFrames 
    # along the columns axis (axis=1) and store the result in "dfy"
    dfy = pd.concat([dfx_jp, geojp_df], axis=1)
    dfy.reset_index(inplace=True)
    # dfy
    
    
    # %%
    
    ### 0-9: Add a new column 'id' into the dataframe.
    
    # Create a new column named "id" in the "dfy" DataFrame 
    # by applying a lambda function to the "prefecture_en" column.
    # The lambda function maps each prefecture name in the "prefecture_en" column 
    # to its corresponding ID in the "prefecture_id_map" dictionary.
    # The resulting IDs are assigned to the "id" column
    dfy['id'] = dfy['prefecture_en'].apply(lambda x: prefecture_id_map[x])
    # pd.options.display.max_rows = 999
    
    raw_df = dfy.copy()
    # raw_df.head(1)
    # raw_df[['region_jp','region_en','prefecture_jp','prefecture_en','pop']].head(3)
    
    # %%    
    click image to zoom!
    図3-1
    図3-1では、総務省統計局のWebサイトからダウンロードしたExcelファイルをCSV形式で保存したCSVファイルを PandasのDataFrameに取り込んでいます。 CSVファイルの列名(カラム名)は、Pythonで処理しやすいように「英語」に変換しています。

    click image to zoom!
    図3-2
    図3-2では、前出(図3-1)のDataFrameの内容を表示しています。 DataFrameは「prefecture_id, prefecture_jp, total_under15, total_adult, total_over65, total_over75,..」 等の列から構成されています。 列「total_adult, total_over65, male_adult,...」等には、数値に「コンマ」が含まれているので後述するステップで除去します。

    click image to zoom!
    図3-3
    図3-3では、前出(図3-2)のDataFrameをクリーンアップして作成した新規のDataFrame(dfx)の構造を表示しています。 DataFrame(dfx)は、「prefecture_jp, male_under15, male_adult, male_over65, male_over75,...」等の列から構成されています。 クリーンアップ処理では、都道府県名から「空白」を除去したり、数値から「コンマ」を除去しています。

    click image to zoom!
    図3-4
    図3-4では、前出(図3-3)のDataFrame(dfx)の列の値を編集したり、新規の列を追加しています。 列「male_under15, male_adult, male_over65, male_over75,...」等の値(人口)は、1000人単位なので、 1000倍して本来の人数に変換しています。 さらに、「pop_under15, pop_adult, pop_over65, pop_over75,...」等の新規の列も追加しています。 これらの列には、人口(人数)が格納されています。 「pop_under15_ratio, pop_adult_ratio, pop_over65_ratio, pop_over75_ratio」等の列には、 それぞれの比率(%)が格納されています。 後述するステップでは、これらの比率を使用して「少子化率」「高齢化率」の各種グラフを作成します。

    click image to zoom!
    図3-5
    図3-5では、前出(図3-4)のDataFrame(dfx)の列の内容を表示しています。 列「male_under15, male_adult, male_over65, male_over75」には、年齢区分別に男性の人口が格納されているのが確認できます。 同様に列「female_under15, female_adult, female_over65, female_over75」には、 年齢区分別に女性の人口が格納されているのが確認できます。

    click image to zoom!
    図3-6
    図3-6では、前出(図3-4)のDataFrame(dfx)の列の内容を表示しています。 列「pop_under15, pop_adult, pop_over65, pop_over75」には、年齢区分別に男女合計の人口が格納されているのが確認できます。 また、列「pop_male, pop_female, pop」には、男性人口、女性人口、男女合計の人口が格納されているのが確認できます。

    click image to zoom!
    図3-7
    図3-7では、前出(図3-4)のDataFrame(dfx)の列の内容を表示しています。 列「pop_under15_ratio, pop_adult_ratio, pop_over65_ratio, pop_over75_ratio」には、 年齢区分別の比率が格納されているのが確認できます。 これらの列は、後述するステップで「少子化率」「高齢化率」の各種グラフを作成するときに使用します。

    click image to zoom!
    図3-8
    図3-8では、日本の地理データ(GeoJson)を読み込んで内容を表示しています。 このデータは、後述するステップでコロプレス図を作成するときに使用します。

    click image to zoom!
    図3-9
    図3-9では、前出(図3-8)のGeoJsonデータから、 都道府県名、都道府県IDを生成してDict型の変数「prefecture_id_map」に格納しています。

    click image to zoom!
    図3-10
    図3-10では、地理データが格納されているCSVファイルをPandasのDataFrame(geo_df)に取り込んでいます。 このDataFrame(geo_df)には、「地域名、都道府県名」が「英語」と「日本語」で格納されています。

    click image to zoom!
    図3-11
    図3-11では、前出(図3-10)のDataFrame(geo_df)から、 列「region_en, region_jp, prefecture_en, prefecture_jp」を抽出しています。

    click image to zoom!
    図3-12
    図3-12では、DataFrame(dfx_jp, geo_df)のインデックスに列「prefecture_jp」を設定しています。 これで、2つのDataFrame(dfx_jp, geojp_df)の連結が可能になります。

    click image to zoom!
    図3-13
    図3-13では、前出(図3-12)のDataFrame(dfx_jp, geojp_df)を連結しています。 これで2つのDataFrameが1個のDataFrame(dfy)にマージ(統合)されます。 統合されたDataFrame(dfy)には、2つのDataFrame(dfx_jp, geojp_df)の全ての列が含まれます。

    click image to zoom!
    図3-14
    図3-14では、前出(図3-13)のDataFrame(dfy)に新規の列「id」を追加しています。 列「id」には、図3-9で作成したGeoJsonの「都道府県ID」が格納されます。 これで、DataFrame(dfy)とGeoJsonがリンクされます。 最後に、最終版のDataFrame(dfy)を新規のDataFrame(raw_df)にコピーしています。 後述するステップでは、DataFrame(raw_df)を使用して各種グラフを作成します。

    click image to zoom!
    図3-15
    図3-15では、最終版のDataFrame(raw_df)の内容を表示しています。 ここでは、列「region_jp, region_en, prefecture_jp, prefecture_en, pop(人口)」の内容を表示しています。
  4. Plotly ExpressのChoropleth(コロプレス図)で人口データのマップを作成する

    ここでは、Plotly Expressのコロプレス図で人口データを可視化します。

    ### 1: Map population (2021)
    
    # set a defulat template
    pio.templates.default = 'plotly_dark'
    
    ### 1-1: population by prefecture
            
    df = raw_df.copy()
    
    fig = px.choropleth(
        df,
        locations='id',
        geojson=japan_prefectures,
        color='pop',
        hover_name='prefecture_jp',
        hover_data=['pop_male', 'pop_female'],
        height=600,
        labels=dict(
                    prefecture_jp='都道府県', 
                    pop='人口',
                    pop_male='男性',
                    pop_female='女性',
                    ),    
        title="px.choropleth(...): 都道府県別人口 (2021年度)",
    )
    
    fig.update_geos(fitbounds='locations', visible=False)
    
    fig.show()  
    
    
    # %%
    
    ### 1-2: population ratio ages over 65 by prefecture
            
    df = raw_df.copy()
    
    fig = px.choropleth(
        df,
        locations='id',
        geojson=japan_prefectures,
        color='pop_over65_ratio',
        hover_name='prefecture_jp',
        hover_data=['pop_male', 'pop_female'],
        height=600,    
        labels=dict(
                    pop_male='男性',
                    pop_female='女性',    
                    prefecture_jp='都道府県', 
                    pop_over65_ratio='高齢化率(%)',   
                    ),    
        title="px.choropleth(color='pop_over65_ratio'): 高齢化率(%) 65歳以上",
    )
    
    fig.update_geos(fitbounds='locations', visible=False)
    
    fig.show() 
    
    
    # %% 
    
    ### 1-3: population ratio ages over 75 by prefecture
            
    df = raw_df.copy()
    
    fig = px.choropleth(
        df,
        locations='id',
        geojson=japan_prefectures,
        color='pop_over75_ratio',
        hover_name='prefecture_jp',
        hover_data=['pop_male', 'pop_female'],
        height=600, 
        labels=dict(
                    pop_male='男性',
                    pop_female='女性',     
                    prefecture_jp='都道府県', 
                    pop_over75_ratio='高齢化率(%)',   
                    ),    
        title="px.choropleth(color='pop_over75_ratio'): 高齢化率(%) 75歳以上",
    )
    
    fig.update_geos(fitbounds='locations', visible=False)
    
    fig.show()
    
    
    # %%    
    click image to zoom!
    図4-1
    図4-1では、日本地図にカラーマップを適用させて都道府県別の人口分布を表示させています。 都道府県の色が「青色」から「黄色」になるほど人口が多くなっています。 マップ上にマウスをホバリングさせると、ホバーテキストが表示されます。

    click image to zoom!
    図4-2
    図4-2では、関東地方をズームインさせています。 ここでは、東京都にマウスをホバリングさせてホバーテキストを表示させています。 ホバーテキストには、東京都の「男性、女性、合計」の人口が表示されています。

    click image to zoom!
    図4-3
    図4-3では、日本地図にカラーマップを適用させて都道府県別の高齢化率(%)を表示させています。 都道府県の色が「青色」から「黄色」になるほど高齢化率(65歳以上の住民が対象)が高くなることを意味します。 秋田県が「黄色」になっているので高齢化率が高いことが分かります。

    click image to zoom!
    図4-4
    図4-4では、秋田県にマウスをホバリングさせてホバーテキストを表示させています。 ホバーテキストには、秋田県の「男性、女性」の人口と「高齢化率(%)」が表示されています。 秋田県の高齢化率は「37.99%」になっています。

    click image to zoom!
    図4-5
    図4-5では、75歳以上の住民を対象にして高齢化率のグラフを表示しています。
  5. Plotly ExpressのSunburst(サンバーストチャート)で人口データを可視化する

    ここでは、Plotly Expressのサンバーストチャートで人口データを可視化します。

    ### 2: sunburst chart 
    
    ### 2-1: population by region, prefecture
    df = raw_df.copy()
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop',           
            hover_name='prefecture_jp',
            color='pop',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_sum='総人口',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(path=['region_jp','prefecture_jp']): 都道府県別人口"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-2: population ages over 65 
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_over65',           
            hover_name='prefecture_jp',
            color='pop_over65',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_over65='高齢者',
                pop_sum='総人口',
                pop_over65_sum='高齢者',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_over65'): 高齢者人口 (65歳以上)"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-3: population ages over 75 
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_over75',           
            hover_name='prefecture_jp',
            color='pop_over75',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_over75='高齢者',
                pop_sum='総人口',
                pop_over75_sum='高齢者',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_over75'): 高齢者人口 (75歳以上)"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-4: population ratio ages over 65
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_over65_ratio',           
            hover_name='prefecture_jp',
            color='pop_over65_ratio',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_over65_ratio='高齢化率',
                pop_sum='総人口',
                pop_over65_ratio_sum='高齢化率',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_over65_ratio'): 高齢化率 (65歳以上)"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-5: population ratio ages over 75
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_over75_ratio',           
            hover_name='prefecture_jp',
            color='pop_over75_ratio',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_over75_ratio='高齢化率',
                pop_sum='総人口',
                pop_over75_ratio_sum='高齢化率',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_over75_ratio'): 高齢化率 (75歳以上)"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-6: population ratio ages under 15 
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_under15_ratio',           
            hover_name='prefecture_jp',
            color='pop_under15_ratio',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_under15_ratio='少子化率',
                pop_sum='総人口',
                pop_under15_ratio_sum='少子化率',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_under15_ratio'): 少子化率(15歳未満)"
    )
    
    fig.show()
    
    
    # %%
    
    ### 2-7: population ratio adult (15~64) 
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_adult_ratio',           
            hover_name='prefecture_jp',
            color='pop_adult_ratio',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_adult_ratio='就業人口率',
                pop_sum='総人口',
                pop_adult_ratio_sum='就業人口率',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_adult_ratio'): 就業人口率(15~64歳)"
    )
    
    fig.show()
    
    
    # %%    
    click image to zoom!
    図5-1
    図5-1では、地方、都道府県ごとの人口比率を円グラフで表示しています。 内側の円には、地方の人口比率が表示されています。 外側の円には、都道府県国ごとの人口比率が表示されています。 このグラフからは、地方と都道府県ごとの人口比率が同時に可視化できます。

    click image to zoom!
    図5-2
    図5-2では、前出(図5-1)の内側の円から「関東地方」をクリックして関東地方の都道府県の人口を表示させています。 ここでは、東京都にマウスをホバリングさせてホバーテキストを表示させています。

    click image to zoom!
    図5-3
    図5-3では、前出(図5-1)の内側の「中部地方」にマウスをホバリングさせてホバーテキストを表示させています。 ホバーテキストには、中部地方の「総人口(21,010,000)」が表示されます。

    click image to zoom!
    図5-4
    図5-4では、65歳以上の高齢者の人口をグラフに表示しています。

    click image to zoom!
    図5-5
    図5-5では、75歳以上の高齢者の人口をグラフに表示しています。

    click image to zoom!
    図5-6
    図5-6では、65歳以上の住民を対象にした高齢化率(%)をグラフに表示しています。 このグラフからは、秋田県がもっとも高齢化がすすんでいることが分かります。

    click image to zoom!
    図5-7
    図5-7では、前出(図5-6)の「秋田県」にマウスをホバリングさせてホバーテキストを表示させています。 秋田県の高齢化率は「37.99%」になっています。

    click image to zoom!
    図5-8
    図5-8では、75歳以上の住民を対象にした高齢化率(%)を表示しています。 ここでは、高齢化率が低い沖縄県にマウスをホバリングさせてホバーテキストを表示させています。 沖縄県の高齢化率は「10.62%」になっています。

    click image to zoom!
    図5-9
    図5-9では、15歳未満の住民を対象にした少子化率(%)をグラフに表示しています。 少子化率の場合、数値が高いほど少子化率がすすんでいないことを意味します。 ここでは、少子化がすすんでいない沖縄県にマウスをホバリングさせてホバーテキストを表示させています。 沖縄県の少子化率は「16.54%」になっています。

    click image to zoom!
    図5-10
    図5-10では、少子化がすすんでいる秋田県にマウスをホバリングさせてホバーテキストを表示させています。 秋田県の少子化率は「9.52%」になっています。

    click image to zoom!
    図5-11
    図5-11では、15歳~64歳までの住民(就業人口)を対象にしたグラフを表示しています。 ここでは、東京都にマウスをホバリングさせてホバーテキストを表示させています。 東京都の就業人口率は「66.06%」になっています。
  6. Plotly ExpressのPie Chart(円グラフ)で人口データを可視化する

    ここでは、Plotly Expressの円グラフで人口データを可視化します。 なお、65歳以上の人口の内訳についてはサンバーストチャートを使用します。

    ### 3: pie chart
    
    ### 3-0: japan
    
    df = raw_df.copy()
    df['region'] = 'Japan'
    # Group the "df" DataFrame by "region", 
    # summing the 'pop_under15', 'pop_adult', 'pop_over65' columns, and reset the index
    grp_df = df.groupby('region')[['pop_under15', 'pop_adult', 'pop_over65']].sum().reset_index()
    
    melted_df = pd.melt(grp_df, 
                        id_vars=['region'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',    
            height=600,    
            labels=dict(
                category='分類',
                value='人口'
            ),
            title="px.pie(names='category', values='value'): 全国 (人口構成)"                   
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-0-1: add a holl and annotations
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',        
            hole=0.4,
            height=600,         
            labels=dict(
                category='分類',
                value='人口'    
            ),
            title='px.pie(hole=0.4): 全国 (人口構成)'                    
    )
    
    fig.update_layout(
        annotations=[dict(text='全国', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-0-2: add a pull 
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',
            hole=0.4,
            height=600,        
            labels=dict(
                category='分類',
                value='人口'       
            ),
            title='px.pie() + update_traces(pull=[0, 0, 0.2]): 全国 (人口構成)'                    
    )
    
    fig.update_traces(
        pull=[0, 0, 0.2]
    )
    
    fig.update_layout(
        annotations=[dict(text='全国', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-0-3: sunburst()
    
    df = raw_df.copy()
    
    df['region'] = 'Japan'
    
    # Group the "df" DataFrame by "region", 
    # summing the 'pop_under15', 'pop_adult', 'pop_over65', 'pop_over75' columns, and reset the index
    grp_df = df.groupby('region')[['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75']].sum().reset_index()
    
    melted_df = pd.melt(grp_df, 
                        id_vars=['region'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over75','75歳以上'))
    
    melted2_df = melted_df.copy()
    melted2_df['sub_category'] = melted2_df['category']
    melted2_df['region'] = '全国'
    category = melted2_df.columns.get_loc('category')
    sub_category = melted2_df.columns.get_loc('sub_category')
    melted2_df.iloc[0, sub_category] = None
    melted2_df.iloc[1, sub_category] = None
    melted2_df.iloc[2, sub_category] = '65歳~74歳'
    melted2_df.iloc[3, category] = '65歳以上'
    
    fig = px.sunburst(melted2_df, 
            path=['region', 'category', 'sub_category'], 
            values='value',
            color='category',
            height=600,
            labels=dict(
            labels='ラベル',    
            value='人口',
            parent='65歳以上',
            category='分類'
            ),       
            title="px.sunburst(path=['region', 'category', 'sub_category']): 全国 (人口構成)"                  
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-1: Tokyo
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Tokyo'")
      
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    
    
    ### 3-1-1: add a holl + pull + annotations
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',
            hole=0.4,
            height=600,        
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'    
            ),
            title="px.pie(names='category', values='value'): 東京都 (人口構成)"                    
    )
    
    fig.update_traces(
        pull=[0, 0, 0.2]
    )
    
    fig.update_layout(
        annotations=[dict(text='東京都', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-1-2: sunburst()
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Tokyo'")
    
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over75','75歳以上'))
    
    melted2_df = melted_df.copy()
    melted2_df['sub_category'] = melted2_df['category']
    category = melted2_df.columns.get_loc('category')
    sub_category = melted2_df.columns.get_loc('sub_category')
    melted2_df.iloc[0, sub_category] = None
    melted2_df.iloc[1, sub_category] = None
    melted2_df.iloc[2, sub_category] = '65歳~74歳'
    melted2_df.iloc[3, category] = '65歳以上'
    
    fig = px.sunburst(melted2_df, 
            path=['prefecture_jp', 'category', 'sub_category'], 
            values='value',
            color='category',
            height=600,
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'
            ),                  
            title="px.sunburst(path=['prefecture_jp', 'category', 'sub_category']): 東京都 (人口構成)"                  
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-2: Akita
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Akita'")
    
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    
    ### 3-2-1: add a holl + pull + annotations
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',
            hole=0.4,
            height=600,        
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'    
            ),
            title="px.pie(names='category', values='value'): 秋田県 (人口構成)"                    
    )
    
    fig.update_traces(
        pull=[0, 0, 0.2]
    )
    
    fig.update_layout(
        annotations=[dict(text='秋田県', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-2-2: sunburst()
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Akita'")
    
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over75','75歳以上'))
    
    melted2_df = melted_df.copy()
    melted2_df['sub_category'] = melted2_df['category']
    category = melted2_df.columns.get_loc('category')
    sub_category = melted2_df.columns.get_loc('sub_category')
    melted2_df.iloc[0, sub_category] = None
    melted2_df.iloc[1, sub_category] = None
    melted2_df.iloc[2, sub_category] = '65歳~74歳'
    melted2_df.iloc[3, category] = '65歳以上'
    
    fig = px.sunburst(melted2_df, 
            path=['prefecture_jp', 'category', 'sub_category'], 
            values='value',
            color='category',
            height=600,
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'
            ),                  
            title="px.sunburst(path=['prefecture_jp', 'category', 'sub_category']): 秋田県 (人口構成)"                  
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-3: okinawa
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Okinawa'")
    
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    
    ### 3-3-1: add a hole + pull + annotations
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',
            hole=0.4,
            height=600,        
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'
            ),
            title="px.pie(names='category', values='value'): 沖縄県 (人口構成)"                    
    )
    
    fig.update_traces(
        pull=[0, 0, 0.2]
    )
    
    fig.update_layout(
        annotations=[dict(text='沖縄県', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-3-2: sunburst()
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Okinawa'")
    
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over75','75歳以上'))
    
    melted2_df = melted_df.copy()
    melted2_df['sub_category'] = melted2_df['category']
    category = melted2_df.columns.get_loc('category')
    sub_category = melted2_df.columns.get_loc('sub_category')
    melted2_df.iloc[0, sub_category] = None
    melted2_df.iloc[1, sub_category] = None
    melted2_df.iloc[2, sub_category] = '65歳~74歳'
    melted2_df.iloc[3, category] = '65歳以上'
    
    fig = px.sunburst(melted2_df, 
            path=['prefecture_jp', 'category', 'sub_category'], 
            values='value',
            color='category',
            height=600,
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'
            ),                  
            title="px.sunburst(path=['prefecture_jp', 'category', 'sub_category']): 沖縄県 (人口構成)"                  
    )
    
    fig.show()
    
    
    # %%    
    click image to zoom!
    図6-1
    図6-1では、日本(全国)の人口を3つの年齢区分(15歳未満、15歳~64歳、65歳以上)でグラフ化しています。 15歳~64歳の人口がもっとも多く「59.4%」になっています。 65歳以上の人口は「28.9%」、15歳未満の人口は「11.8%」となっています。 このグラフからは、日本の少子化がかなりすすんでいることが分かります。

    click image to zoom!
    図6-2
    図6-2では、Plotly Expressの「pie()」メソッドの引数に 「hole=0.4」を追加してドーナツ型の円グラフを作成しています。 内側の円には、figureクラスの「update_layout()」メソッドで注釈「全国」を表示させています。

    click image to zoom!
    図6-3
    図6-3では、figureクラス「update_traces()」メソッドで 「65歳」以上の円弧を引き出して強調させています。

    click image to zoom!
    図6-4
    図6-4では、Plotly Expressの「sunburst()」メソッドで 「65歳以上」の人口を更に「65歳~74歳」と「75歳以上」に分けています。 ここでは、「65歳~74歳」にマウスをホバリングさせてホバーテキストを表示させています。

    click image to zoom!
    図6-5
    図6-5では、東京都の円グラフを表示しています。 ここでは、「65歳以上」にマウスをホバリングさせてホバーテキストを表示させています。 ホバーテキストには、65歳以上の人口が表示されています。

    click image to zoom!
    図6-6
    図6-6では、Plotly Expressの「sunburst()」メソッドで東京都の 「65歳以上」の人口を更に「65歳~74歳」と「75歳以上」に分けています。 ここでは、「65歳~74歳」にマウスをホバリングさせてホバーテキストを表示させています。

    click image to zoom!
    図6-7
    図6-7では、秋田県の円グラフを表示しています。 ここでは、「65歳以上」にマウスをホバリングさせてホバーテキストを表示させています。 ホバーテキストには、65歳以上の人口が表示されています。

    click image to zoom!
    図6-8
    図6-8では、Plotly Expressの「sunburst()」メソッドで秋田県の 「65歳以上」の人口を更に「65歳~74歳」と「75歳以上」に分けています。 ここでは、「65歳~74歳」にマウスをホバリングさせてホバーテキストを表示させています。

    click image to zoom!
    図6-9
    図6-9では、沖縄県の円グラフを表示しています。 ここでは、「65歳以上」にマウスをホバリングさせてホバーテキストを表示させています。 ホバーテキストには、65歳以上の人口が表示されています。

    click image to zoom!
    図6-10
    図6-10では、Plotly Expressの「sunburst()」メソッドで沖縄県の 「65歳以上」の人口を更に「65歳~74歳」と「75歳以上」に分けています。 ここでは、「65歳~74歳」にマウスをホバリングさせてホバーテキストを表示させています。
  7. Plotly ExpressのBar Chart(棒グラフ)で人口データを可視化する

    ここでは、棒グラフで人口データを可視化します。 棒グラフは水平形で表示します。

    ### 4: bar chart
    
    ### 4-1: declining birth rate top 10 (under 15)
    
    df = raw_df.copy()
    df = df.nsmallest(10, 'pop_under15_ratio')
    df.reset_index(inplace=True)
    df['rank'] = df.index+1
    
    df[['prefecture_jp','pop_under15_ratio','pop_under15','pop']]
    
    fig = px.bar(df, 
            x='pop_under15_ratio', y='prefecture_jp',
            color='prefecture_jp',
            text='pop_under15_ratio',
            orientation='h',   
            height=600,
            labels=dict(
                pop_under15_ratio='少子化率(15歳未満)', 
                prefecture_jp='都道府県'
            ),
            title="px.bar(x='pop_under15_ratio', y='prefecture_jp'): 少子化率(%) 上位10"   
    )
    
    fig.show()
    
    
    # %% 
     
    ### 4-2: aging rate top 10 (over 65)
    
    df = raw_df.copy()
    df = df.nlargest(10, 'pop_over65_ratio')
    df.reset_index(inplace=True)
    df['rank'] = df.index+1
    
    df[['prefecture_jp','pop_over65_ratio','pop_over65','pop']]
    
    fig = px.bar(df, 
            x='pop_over65_ratio', y='prefecture_jp',
            color='prefecture_jp',
            text='pop_over65_ratio',
            orientation='h',   
            height=600,        
            labels=dict(
                pop_over65_ratio='高齢化率(65歳以上)', 
                prefecture_jp='都道府県'
            ),
            title="px.bar(x='pop_over65_ratio', y='prefecture_jp'): 高齢化率(%) 上位10"   
    )
    
    fig.show()
    
    
    # %%
    
    ### 4-3: aging rate top 10 (over 75)
    
    df = raw_df.copy()
    df = df.nlargest(10, 'pop_over75_ratio')
    df.reset_index(inplace=True)
    df['rank'] = df.index+1
    
    df[['prefecture_jp','pop_over75_ratio','pop_over75','pop']]
    
    fig = px.bar(df, 
            x='pop_over75_ratio', y='prefecture_jp',
            color='prefecture_jp',
            text='pop_over75_ratio',
            orientation='h',  
            height=600,          
            labels=dict(
                pop_over75_ratio='高齢化率(75歳以上)', 
                prefecture_jp='都道府県'
            ),
            title="px.bar(x='pop_over75_ratio', y='prefecture_jp'): 高齢化率(%) 上位10"   
    )
    
    fig.show()
    
    # %%    
    click image to zoom!
    図7-1
    図7-1では、少子化率の上位10の都道府県をグラフに表示しています。 棒の右端には少子化率(%)が表示されています。 少子化率の場合、数値が小さいほど少子化がすすんでいることになります。 少子化の順位は、秋田県、青森県、北海道、・・・の順になっています。

    click image to zoom!
    図7-2
    図7-2では、65歳以上の住民を対象にした高齢化率の上位10の都道府県をグラフに表示しています。 棒の右端には高齢化率(%)が表示されています。 高齢化率の場合、数値が大きいほど高齢化がすすんでいることになります。 高齢化の順位は、秋田県、高知県、山口県、・・・の順になっています。

    click image to zoom!
    図7-3
    図7-3では、75歳以上の住民を対象にした高齢化率の上位10の都道府県をグラフに表示しています。 棒の右端には高齢化率(%)が表示されています。 高齢化率の場合、数値が大きいほど高齢化がすすんでいることになります。 高齢化の順位は、秋田県、高知県、山口県、・・・の順になっています。
  8. 全てのコードを掲載

    ここでは、本記事で解説している全てのコードを掲載しています。

    リスト8-1: Article152.py
    # Analysis of population by prefecture and age in 2021 v30.py
    '''
    references
    https://www.stat.go.jp/data/jinsui/2021np/index.html
    https://plotly.com/python/sunburst-charts/
    
    '''
    
    # %%
    
    import json
    import urllib.request
    import numpy as np
    import math
    import pandas as pd
    import plotly.io as pio
    import plotly.express as px
    import plotly.graph_objects as go
    
    
    # %%
    
    ### 0: prepare data
    
    # 0-1: read a population data from a csv file
    csv_file = r'https://money-or-ikigai.com/Menu/Python/Article/data/map/japan_population_by_prefecture_age(2021).csv'
    # csv_file = 'datasets/csv/japan_population_by_prefecture_age(2021).csv'
    df = pd.read_csv(csv_file)
    # df.info()
    # df
    
    
    # %%
    
    ### 0-2: clean up data
    pd.options.mode.chained_assignment = None
    
    df['prefecture_jp'] = df['prefecture_jp'].apply(lambda x: x.replace(' ',''))
    df['prefecture_jp'] = df['prefecture_jp'].apply(lambda x: x.replace(' ',''))
    
    # df['male_under15'] = df['male_under15'].apply(lambda x: int(x))
    df['male_adult']   = df['male_adult'].apply(lambda x: int(x.replace(',','')))
    df['male_over65']  = df['male_over65'].apply(lambda x: int(x.replace(',','')))
    # df['male_over75']  = df['male_over75'].apply(lambda x: int(x))
    
    # df['female_under15'] = df['female_under15'].apply(lambda x: int(x))
    df['female_adult']   = df['female_adult'].apply(lambda x: int(x.replace(',','')))
    df['female_over65']  = df['female_over65'].apply(lambda x: int(x.replace(',','')))
    df['female_over75']  = df['female_over75'].apply(lambda x: int(x.replace(',','')))
    
    dfx = df[['prefecture_jp','male_under15','male_adult','male_over65','male_over75','female_under15','female_adult','female_over65','female_over75']]
    # dfx.info()
    # dfx.isnull().sum()
    
    
    # %%
    
    ### 0-3: add the columns
    dfx['male_under15'] = dfx['male_under15'].apply(lambda x: x * 1000)
    dfx['male_adult'] = dfx['male_adult'].apply(lambda x: x * 1000)
    dfx['male_over65'] = dfx['male_over65'].apply(lambda x: x * 1000)
    dfx['male_over75'] = dfx['male_over75'].apply(lambda x: x * 1000)
    
    dfx['female_under15'] = dfx['female_under15'].apply(lambda x: x * 1000)
    dfx['female_adult'] = dfx['female_adult'].apply(lambda x: x * 1000)
    dfx['female_over65'] = dfx['female_over65'].apply(lambda x: x * 1000)
    dfx['female_over75'] = dfx['female_over75'].apply(lambda x: x * 1000)
    
    dfx['pop_under15'] = dfx.apply(lambda row: row['male_under15'] + row['female_under15'], axis=1)
    dfx['pop_adult'] = dfx.apply(lambda row: row['male_adult'] + row['female_adult'], axis=1)
    dfx['pop_over65'] = dfx.apply(lambda row: row['male_over65'] + row['female_over65'], axis=1)
    dfx['pop_over75'] = dfx.apply(lambda row: row['male_over75'] + row['female_over75'], axis=1)
    
    dfx['pop_male'] = dfx.apply(lambda row: row['male_under15'] + row['male_adult'] + row['male_over65'], axis=1)
    dfx['pop_female'] = dfx.apply(lambda row: row['female_under15'] + row['female_adult'] + row['female_over65'], axis=1)
    dfx['pop'] = dfx.apply(lambda row: row['pop_male'] + row['pop_female'], axis=1)
    
    dfx['pop_under15_ratio'] = dfx.apply(lambda row: round((row['pop_under15'] / row['pop']) * 100, 2), axis=1)
    dfx['pop_adult_ratio']   = dfx.apply(lambda row: round((row['pop_adult']   / row['pop']) * 100, 2), axis=1)
    dfx['pop_over65_ratio']  = dfx.apply(lambda row: round((row['pop_over65']  / row['pop']) * 100, 2), axis=1)
    dfx['pop_over75_ratio']  = dfx.apply(lambda row: round((row['pop_over75']  / row['pop']) * 100, 2), axis=1)
    
    # dfx.info()
    # dfx[['prefecture_jp','male_under15','male_adult','male_over65','male_over75']].head(3)
    # dfx[['prefecture_jp','female_under15','female_adult','female_over65','female_over75']].head(3)
    # dfx[['prefecture_jp','pop_under15','pop_adult','pop_over65','pop_over75']].head(3)
    # dfx[['prefecture_jp','pop_male','pop_female','pop',]].head(3)
    # dfx[['prefecture_jp','pop_under15_ratio','pop_adult_ratio','pop_over65_ratio','pop_over75_ratio']].head(3)
    # dfx.isnull().sum()
    
    
    # %%
    
    ### 0-4: Read a GeoJson file
    
    url = r'https://money-or-ikigai.com/Menu/Python/Article/data/map/prefectures.json'
    response = urllib.request.urlopen(url)
    geo_data = response.read().decode('utf-8')
    japan_prefectures = json.loads(geo_data)
    # json_file = 'datasets/json/prefectures.json'
    # japan_prefectures = json.load(open(json_file, 'r'))
    # japan_prefectures
    
    
    # %%
    
    ### 0-5: Load a prefecture id map dictionary from the geojson data
    # Create an empty dictionary to store prefecture IDs
    prefecture_id_map = {}
    
    # Loop through the "features" list in the "japan_prefectures" dictionary
    for feature in japan_prefectures['features']:    
        feature['id'] = feature['properties']['pref']
        prefecture_id_map[feature['properties']['name']] = feature['id']
    # prefecture_id_map
    
    
    # %%
    
    ### 0-6: Load Japan geo data from a csv file
    
    geo_csv = r'https://money-or-ikigai.com/Menu/Python/Article/data/map/japan_geo.csv'
    # geo_csv = 'datasets/csv/japan_geo.csv'
    geo_df = pd.read_csv(geo_csv)
    # geo_df
    
    
    # %%
    
    ### 0-7: Filter columns from the pandas dataframe.
    
    geo_df = geo_df[['region_en','region_jp','prefecture_en','prefecture_jp']]
    # geo_df
    
    
    # %%
    
    ### 0-8: Concatenate the Japan census and geojason data horizontally based on the 'prefecture_jp' column
    
    # Set the "prefecture_jp" column as the index for the "dfx" DataFrame
    dfx_jp = dfx.set_index('prefecture_jp')
    
    # Set the "prefecture_jp" column as the index for the "geo_df" DataFrame
    geojp_df =  geo_df.set_index('prefecture_jp')
    
    # # Concatenate the "dfx" and "geo_df" DataFrames 
    # along the columns axis (axis=1) and store the result in "dfy"
    dfy = pd.concat([dfx_jp, geojp_df], axis=1)
    dfy.reset_index(inplace=True)
    # dfy
    
    
    # %%
    
    ### 0-9: Add a new column 'id' into the dataframe.
    
    # Create a new column named "id" in the "dfy" DataFrame 
    # by applying a lambda function to the "prefecture_en" column.
    # The lambda function maps each prefecture name in the "prefecture_en" column 
    # to its corresponding ID in the "prefecture_id_map" dictionary.
    # The resulting IDs are assigned to the "id" column
    dfy['id'] = dfy['prefecture_en'].apply(lambda x: prefecture_id_map[x])
    # pd.options.display.max_rows = 999
    
    raw_df = dfy.copy()
    # raw_df.head(1)
    # raw_df[['region_jp','region_en','prefecture_jp','prefecture_en','pop']].head(3)
    
    
    # %%
    
    ### 1: Map population (2021)
    
    # set a defulat template
    pio.templates.default = 'plotly_dark'
    
    ### 1-1: population by prefecture
            
    df = raw_df.copy()
    
    fig = px.choropleth(
        df,
        locations='id',
        geojson=japan_prefectures,
        color='pop',
        hover_name='prefecture_jp',
        hover_data=['pop_male', 'pop_female'],
        height=600,
        labels=dict(
                    prefecture_jp='都道府県', 
                    pop='人口',
                    pop_male='男性',
                    pop_female='女性',
                    ),    
        title="px.choropleth(...): 都道府県別人口 (2021年度)",
    )
    
    fig.update_geos(fitbounds='locations', visible=False)
    
    fig.show()  
    
    
    # %%
    
    ### 1-2: population ratio ages over 65 by prefecture
            
    df = raw_df.copy()
    
    fig = px.choropleth(
        df,
        locations='id',
        geojson=japan_prefectures,
        color='pop_over65_ratio',
        hover_name='prefecture_jp',
        hover_data=['pop_male', 'pop_female'],
        height=600,    
        labels=dict(
                    pop_male='男性',
                    pop_female='女性',    
                    prefecture_jp='都道府県', 
                    pop_over65_ratio='高齢化率(%)',   
                    ),    
        title="px.choropleth(color='pop_over65_ratio'): 高齢化率(%) 65歳以上",
    )
    
    fig.update_geos(fitbounds='locations', visible=False)
    
    fig.show() 
    
    
    # %% 
    
    ### 1-3: population ratio ages over 75 by prefecture
            
    df = raw_df.copy()
    
    fig = px.choropleth(
        df,
        locations='id',
        geojson=japan_prefectures,
        color='pop_over75_ratio',
        hover_name='prefecture_jp',
        hover_data=['pop_male', 'pop_female'],
        height=600, 
        labels=dict(
                    pop_male='男性',
                    pop_female='女性',     
                    prefecture_jp='都道府県', 
                    pop_over75_ratio='高齢化率(%)',   
                    ),    
        title="px.choropleth(color='pop_over75_ratio'): 高齢化率(%) 75歳以上",
    )
    
    fig.update_geos(fitbounds='locations', visible=False)
    
    fig.show()
    
    
    # %%
    
    ### 2: sunburst chart 
    
    ### 2-1: population by region, prefecture
    df = raw_df.copy()
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop',           
            hover_name='prefecture_jp',
            color='pop',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_sum='総人口',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(path=['region_jp','prefecture_jp']): 都道府県別人口"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-2: population ages over 65 
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_over65',           
            hover_name='prefecture_jp',
            color='pop_over65',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_over65='高齢者',
                pop_sum='総人口',
                pop_over65_sum='高齢者',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_over65'): 高齢者人口 (65歳以上)"
    )
    
    fig.show() 
    
    
    
    # %%
    
    ### 2-3: population ages over 75 
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_over75',           
            hover_name='prefecture_jp',
            color='pop_over75',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_over75='高齢者',
                pop_sum='総人口',
                pop_over75_sum='高齢者',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_over75'): 高齢者人口 (75歳以上)"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-4: population ratio ages over 65
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_over65_ratio',           
            hover_name='prefecture_jp',
            color='pop_over65_ratio',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_over65_ratio='高齢化率',
                pop_sum='総人口',
                pop_over65_ratio_sum='高齢化率',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_over65_ratio'): 高齢化率 (65歳以上)"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-5: population ratio ages over 75
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_over75_ratio',           
            hover_name='prefecture_jp',
            color='pop_over75_ratio',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_over75_ratio='高齢化率',
                pop_sum='総人口',
                pop_over75_ratio_sum='高齢化率',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_over75_ratio'): 高齢化率 (75歳以上)"
    )
    
    fig.show() 
    
    
    # %%
    
    ### 2-6: population ratio ages under 15 
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_under15_ratio',           
            hover_name='prefecture_jp',
            color='pop_under15_ratio',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_under15_ratio='少子化率',
                pop_sum='総人口',
                pop_under15_ratio_sum='少子化率',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_under15_ratio'): 少子化率(15歳未満)"
    )
    
    fig.show()
    
    
    # %%
    
    ### 2-7: population ratio adult (15~64) 
    
    fig = px.sunburst(df, 
            path=['region_jp','prefecture_jp'],
            values='pop_adult_ratio',           
            hover_name='prefecture_jp',
            color='pop_adult_ratio',
            height=600,
            labels=dict(
                labels='都道府県',
                parent='地方',
                pop='人口', 
                pop_adult_ratio='就業人口率',
                pop_sum='総人口',
                pop_adult_ratio_sum='就業人口率',
                prefecture_jp='都道府県',
                region_en='地域'
            ),            
            title="px.sunburst(values='pop_adult_ratio'): 就業人口率(15~64歳)"
    )
    
    fig.show()
    
    
    # %%
    
    ### 3: pie chart
    
    ### 3-0: japan
    
    df = raw_df.copy()
    df['region'] = 'Japan'
    # Group the "df" DataFrame by "region", 
    # summing the 'pop_under15', 'pop_adult', 'pop_over65' columns, and reset the index
    grp_df = df.groupby('region')[['pop_under15', 'pop_adult', 'pop_over65']].sum().reset_index()
    
    melted_df = pd.melt(grp_df, 
                        id_vars=['region'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    # melted_df
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',    
            height=600,    
            labels=dict(
                category='分類',
                value='人口'
            ),
            title="px.pie(names='category', values='value'): 全国 (人口構成)"                   
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-0-1: add a holl and annotations
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',        
            hole=0.4,
            height=600,         
            labels=dict(
                category='分類',
                value='人口'    
            ),
            title='px.pie(hole=0.4): 全国 (人口構成)'                    
    )
    
    fig.update_layout(
        annotations=[dict(text='全国', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-0-2: add a pull 
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',
            hole=0.4,
            height=600,        
            labels=dict(
                category='分類',
                value='人口'       
            ),
            title='px.pie() + update_traces(pull=[0, 0, 0.2]): 全国 (人口構成)'                    
    )
    
    fig.update_traces(
        pull=[0, 0, 0.2]
    )
    
    fig.update_layout(
        annotations=[dict(text='全国', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-0-3: sunburst()
    
    df = raw_df.copy()
    
    df['region'] = 'Japan'
    
    # Group the "df" DataFrame by "region", 
    # summing the 'pop_under15', 'pop_adult', 'pop_over65', 'pop_over75' columns, and reset the index
    grp_df = df.groupby('region')[['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75']].sum().reset_index()
    
    melted_df = pd.melt(grp_df, 
                        id_vars=['region'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over75','75歳以上'))
    # melted_df
    
    melted2_df = melted_df.copy()
    melted2_df['sub_category'] = melted2_df['category']
    melted2_df['region'] = '全国'
    category = melted2_df.columns.get_loc('category')
    sub_category = melted2_df.columns.get_loc('sub_category')
    melted2_df.iloc[0, sub_category] = None
    melted2_df.iloc[1, sub_category] = None
    melted2_df.iloc[2, sub_category] = '65歳~74歳'
    melted2_df.iloc[3, category] = '65歳以上'
    # melted2_df
    
    fig = px.sunburst(melted2_df, 
            path=['region', 'category', 'sub_category'], 
            values='value',
            color='category',
            height=600,
            labels=dict(
            labels='ラベル',    
            value='人口',
            parent='65歳以上',
            category='分類'
            ),       
            title="px.sunburst(path=['region', 'category', 'sub_category']): 全国 (人口構成)"                  
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-1: Tokyo
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Tokyo'")
    # df
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    # melted_df
    
    ### 3-1-1: add a holl + pull + annotations
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',
            hole=0.4,
            height=600,        
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'    
            ),
            title="px.pie(names='category', values='value'): 東京都 (人口構成)"                    
    )
    
    fig.update_traces(
        pull=[0, 0, 0.2]
    )
    
    fig.update_layout(
        annotations=[dict(text='東京都', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-1-2: sunburst()
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Tokyo'")
    # df
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over75','75歳以上'))
    melted_df
    
    melted2_df = melted_df.copy()
    melted2_df['sub_category'] = melted2_df['category']
    category = melted2_df.columns.get_loc('category')
    sub_category = melted2_df.columns.get_loc('sub_category')
    melted2_df.iloc[0, sub_category] = None
    melted2_df.iloc[1, sub_category] = None
    melted2_df.iloc[2, sub_category] = '65歳~74歳'
    melted2_df.iloc[3, category] = '65歳以上'
    melted2_df
    
    fig = px.sunburst(melted2_df, 
            path=['prefecture_jp', 'category', 'sub_category'], 
            values='value',
            color='category',
            height=600,
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'
            ),                  
            title="px.sunburst(path=['prefecture_jp', 'category', 'sub_category']): 東京都 (人口構成)"                  
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-2: Akita
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Akita'")
    # df
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    
    ### 3-2-1: add a holl + pull + annotations
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',
            hole=0.4,
            height=600,        
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'    
            ),
            title="px.pie(names='category', values='value'): 秋田県 (人口構成)"                    
    )
    
    fig.update_traces(
        pull=[0, 0, 0.2]
    )
    
    fig.update_layout(
        annotations=[dict(text='秋田県', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-2-2: sunburst()
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Akita'")
    # df
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over75','75歳以上'))
    melted_df
    
    melted2_df = melted_df.copy()
    melted2_df['sub_category'] = melted2_df['category']
    category = melted2_df.columns.get_loc('category')
    sub_category = melted2_df.columns.get_loc('sub_category')
    melted2_df.iloc[0, sub_category] = None
    melted2_df.iloc[1, sub_category] = None
    melted2_df.iloc[2, sub_category] = '65歳~74歳'
    melted2_df.iloc[3, category] = '65歳以上'
    melted2_df
    
    fig = px.sunburst(melted2_df, 
            path=['prefecture_jp', 'category', 'sub_category'], 
            values='value',
            color='category',
            height=600,
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'
            ),                  
            title="px.sunburst(path=['prefecture_jp', 'category', 'sub_category']): 秋田県 (人口構成)"                  
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-3: okinawa
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Okinawa'")
    # df
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    
    ### 3-3-1: add a hole + pull + annotations
    
    fig = px.pie(melted_df, 
            names='category', 
            values='value',
            color='category',
            hole=0.4,
            height=600,        
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'
            ),
            title="px.pie(names='category', values='value'): 沖縄県 (人口構成)"                    
    )
    
    fig.update_traces(
        pull=[0, 0, 0.2]
    )
    
    fig.update_layout(
        annotations=[dict(text='沖縄県', x=0.50, y=0.5, font_size=20, showarrow=False)]          
    )
    
    fig.show()
    
    
    # %%
    
    ### 3-3-2: sunburst()
    
    df = raw_df.copy()
    df = df.query("prefecture_en == 'Okinawa'")
    df
    
    melted_df = pd.melt(df, 
                        id_vars=['prefecture_jp'], 
                        value_vars=['pop_under15', 'pop_adult', 'pop_over65', 'pop_over75'], 
                        var_name='category', 
                        value_name='value')
    
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_under15','15歳未満'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_adult','15歳~64歳'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over65','65歳以上'))
    melted_df['category'] = melted_df['category'].apply(lambda x: x.replace('pop_over75','75歳以上'))
    melted_df
    
    melted2_df = melted_df.copy()
    melted2_df['sub_category'] = melted2_df['category']
    category = melted2_df.columns.get_loc('category')
    sub_category = melted2_df.columns.get_loc('sub_category')
    melted2_df.iloc[0, sub_category] = None
    melted2_df.iloc[1, sub_category] = None
    melted2_df.iloc[2, sub_category] = '65歳~74歳'
    melted2_df.iloc[3, category] = '65歳以上'
    melted2_df
    
    fig = px.sunburst(melted2_df, 
            path=['prefecture_jp', 'category', 'sub_category'], 
            values='value',
            color='category',
            height=600,
            labels=dict(
                labels='ラベル',    
                value='人口',
                parent='65歳以上',
                category='分類'
            ),                  
            title="px.sunburst(path=['prefecture_jp', 'category', 'sub_category']): 沖縄県 (人口構成)"                  
    )
    
    fig.show()
    
    
    # %%
    
    ### 4: bar chart
    
    ### 4-1: declining birth rate top 10 (under 15)
    
    df = raw_df.copy()
    df = df.nsmallest(10, 'pop_under15_ratio')
    df.reset_index(inplace=True)
    df['rank'] = df.index+1
    
    df[['prefecture_jp','pop_under15_ratio','pop_under15','pop']]
    
    fig = px.bar(df, 
            x='pop_under15_ratio', y='prefecture_jp',
            color='prefecture_jp',
            text='pop_under15_ratio',
            orientation='h',   
            height=600,
            labels=dict(
                pop_under15_ratio='少子化率(15歳未満)', 
                prefecture_jp='都道府県'
            ),
            title="px.bar(x='pop_under15_ratio', y='prefecture_jp'): 少子化率(%) 上位10"   
    )
    
    fig.show()
    
    
    # %% 
     
    ### 4-2: aging rate top 10 (over 65)
    
    df = raw_df.copy()
    df = df.nlargest(10, 'pop_over65_ratio')
    df.reset_index(inplace=True)
    df['rank'] = df.index+1
    
    df[['prefecture_jp','pop_over65_ratio','pop_over65','pop']]
    
    fig = px.bar(df, 
            x='pop_over65_ratio', y='prefecture_jp',
            color='prefecture_jp',
            text='pop_over65_ratio',
            orientation='h',   
            height=600,        
            labels=dict(
                pop_over65_ratio='高齢化率(65歳以上)', 
                prefecture_jp='都道府県'
            ),
            title="px.bar(x='pop_over65_ratio', y='prefecture_jp'): 高齢化率(%) 上位10"   
    )
    
    fig.show()
    
    
    # %%
    
    ### 4-3: aging rate top 10 (over 75)
    
    df = raw_df.copy()
    df = df.nlargest(10, 'pop_over75_ratio')
    df.reset_index(inplace=True)
    df['rank'] = df.index+1
    
    df[['prefecture_jp','pop_over75_ratio','pop_over75','pop']]
    
    fig = px.bar(df, 
            x='pop_over75_ratio', y='prefecture_jp',
            color='prefecture_jp',
            text='pop_over75_ratio',
            orientation='h',  
            height=600,          
            labels=dict(
                pop_over75_ratio='高齢化率(75歳以上)', 
                prefecture_jp='都道府県'
            ),
            title="px.bar(x='pop_over75_ratio', y='prefecture_jp'): 高齢化率(%) 上位10"   
    )
    
    fig.show()
    
    # %%