こんな人にオススメ
今は世界的に裕福に、そして長寿になってきているけど、昔はどうだったの?
各国ごとに時系列でアニメーションで見てみたい。
ということで、今回は世界各国の収入と平均寿命の時代変化をplotly
のpx
のアニメーションで見る。
以下の記事である年のデータでバブルチャートを作成した。
-
-
【plotly&バブルチャート】plotlyで各国の収入と平均寿命をバブルチャートで描く
続きを見る
また、以下の記事で年ごとに作成したが、以下の記事ではスライダーを使用した。今回はアニメーションで作成。
-
-
【plotly&バブルチャート】plotlyで各国の収入と平均寿命の時代変化をバブルチャートで描く
続きを見る
plotly
のアニメーションにはpx
とgo
があるけど、今回はpx
を使用してグラフ化する。px
の方が簡単に作成できる分、カスタムに乏しい。
px
のアニメーションについては以下の記事で解説している。
-
-
【px&animation】plotly.expressでアニメーションのグラフを作成
続きを見る
python環境は以下。
- Python 3.9.7
- numpy 1.21.2
- pandas 1.3.3
- plotly 5.3.1
- plotly-orca 3.4.2
作成したコード全文
使用するデータ
今回使用するデータは以下の3種類。
- 世界各国の収入
- 世界各国の平均寿命
- 世界各国の人口
データは全て「Gapminder」からの引用で、基本的にこの組織からのデータだが一部のデータは使用していない。「Based on free material from GAPMINDER.ORG, CC-BY LICENSE」、すなわちフリーな素材ということだ。
このデータを知ったきっかけは、「FACTFULNESS」という本を読んだから。この本は執筆者が人生で一番読んで良かったと思っている本で、データや事実に基づきテレビなどでは知り得ない世界の本当の姿を知るという本だ。この本の著者がデータ引用元のギャップマインダー財団の共同創立者。
各データはGapminderの「Download the data」からダウンロードすることができる。収入、平均寿命、人口はそれぞれ以下の定義だ。
- 収入:一人当たりGDPでその単位は「2011年の固定価格のinternational dollars」
- 平均寿命:現在の死亡パターンが同じままである場合、新生児が生きる平均年数
- 人口:単純にその国の総人口
また、グラフの最終的な完成イメージは以下。
- 横軸:各国の収入
- 縦軸:各国の平均寿命
- バブルの大きさ:各国の人口
今回は人口が多いほど赤系統のバブルに、少ないほど青系統のバブルになるように作成した。細かいことはの後に解説する。
なお、ここにギャップマインダーのグラフがある。クオリティはめちゃくちゃ高い。めちゃくちゃ軽くてびっくりする。
下準備
import re import sys import numpy as np import pandas as pd import plotly.express as px import plotly.io as pio sys.path.append('../../') import plotly_layout_template as template
まずは下準備としてのimport
関連。plotly_layout_template
は自作のplotly
テンプレート。これを使用することで簡単にキレイなグラフを作成できる。
-
-
【随時更新 備忘録】plotlyのグラフ即席作成コード
続きを見る
px
のアニメーションはpandas
のデータフレームを使用するのがメジャーで簡単な方法なので、今回はpandas
をimport
。
データの形式と読み込み
まずは今回使用するデータの形式とデータそのものの読み込み方を解説。もちろん色んな方法があると思うけど、個人的にはこの方法が楽だった。
データの読み込み
# 使用するscvファイル名 income_name = './income_per_person_gdppercapita_ppp_inflation_adjusted.csv' life_expectancy_name = './life_expectancy_years.csv' population_name = './population_total.csv'
まずはデータの読み込みから。先程のダウンロードサイトからデータをダウンロードして、pyファイルと同じディレクトリに置いた。
ファイル名は変わるかもしれないけど、とりあえず収入・平均寿命・人口のデータを使用。
pandas
のcsv読み込み時にファイル名を指定してもいいけど、その場合は79文字ルールに反するので予め変数化。
-
-
【PEP8&flake8】pythonにおけるPEP8とflake8
続きを見る
これらを使用して、各データを実際に読み込む。区切り文字は明示的に','
と指定、0列目は国名でこれをインデックスとした。
# データの読み込み income = pd.read_csv(income_name, sep=',', index_col=0) life_expectancy = pd.read_csv(life_expectancy_name, sep=',', index_col=0) population = pd.read_csv(population_name, sep=',', index_col=0)
読み込んだ内容を出力すると以下。
print(income) # 1800 1801 1802 1803 ... 2047 2048 2049 2050 # country ... # Afghanistan 674 674 674 674 ... 3270 3340 3410 3480 # Angola 691 693 697 700 ... 9120 9320 9520 9720 # Albania 746 746 746 746 ... 27.8k 28.3k 28.9k 29.6k # Andorra 1340 1340 1340 1350 ... 123k 126k 128k 131k # United Arab Emirates 1120 1120 1120 1130 ... 84.5k 86.3k 88.1k 90k # ... ... ... ... ... ... ... ... ... ... # Samoa 1570 1570 1570 1570 ... 9340 9540 9740 9950 # Yemen 981 983 986 988 ... 4510 4610 4710 4810 # South Africa 1760 1740 1720 1700 ... 16.5k 16.8k 17.2k 17.6k # Zambia 741 743 746 747 ... 4010 4090 4180 4270 # Zimbabwe 972 973 974 975 ... 3960 4050 4130 4220 # [195 rows x 251 columns] print(life_expectancy) # 1800 1801 1802 1803 ... 2097 2098 2099 2100 # country ... # Afghanistan 28.2 28.2 28.2 28.2 ... 76.4 76.5 76.6 76.8 # Angola 27.0 27.0 27.0 27.0 ... 79.6 79.7 79.9 80.0 # Albania 35.4 35.4 35.4 35.4 ... 88.0 88.2 88.3 88.4 # Andorra NaN NaN NaN NaN ... NaN NaN NaN NaN # United Arab Emirates 30.7 30.7 30.7 30.7 ... 83.0 83.1 83.2 83.3 # ... ... ... ... ... ... ... ... ... ... # Samoa 25.4 25.4 25.4 25.4 ... 80.5 80.6 80.7 80.8 # Yemen 23.4 23.4 23.4 23.4 ... 77.6 77.8 77.9 78.0 # South Africa 33.5 33.5 33.5 33.5 ... 77.3 77.4 77.5 77.7 # Zambia 32.6 32.6 32.6 32.6 ... 76.7 76.8 77.0 77.1 # Zimbabwe 33.7 33.7 33.7 33.7 ... 74.0 74.2 74.3 74.4 # [195 rows x 301 columns] print(population) # 1800 1801 1802 1803 ... 2097 2098 2099 2100 # country ... # Afghanistan 3.28M 3.28M 3.28M 3.28M ... 75.6M 75.4M 75.2M 74.9M # Angola 1.57M 1.57M 1.57M 1.57M ... 182M 184M 186M 188M # Albania 400k 402k 404k 405k ... 1.17M 1.14M 1.11M 1.09M # Andorra 2650 2650 2650 2650 ... 62.6k 62.5k 62.5k 62.4k # United Arab Emirates 40.2k 40.2k 40.2k 40.2k ... 12.7M 12.8M 12.8M 12.9M # ... ... ... ... ... ... ... ... ... ... # Samoa 47.3k 47.3k 47.3k 47.3k ... 312k 312k 311k 310k # Yemen 2.59M 2.59M 2.59M 2.59M ... 53.7M 53.5M 53.4M 53.2M # South Africa 1.45M 1.45M 1.46M 1.46M ... 79.5M 79.4M 79.3M 79.2M # Zambia 747k 758k 770k 782k ... 79.2M 80M 80.8M 81.5M # Zimbabwe 1.09M 1.09M 1.09M 1.09M ... 31M 31M 31M 31M # [197 rows x 301 columns]
なるほど、NaN
とk(キロ)やM(メガ)などのSI接頭辞がついているデータがある。
NaN
に関してはほっといても大丈夫。グラフ化してくれないだけのはず。しかし、SI接頭辞は厄介だ。
一応、astropyを使用することでSI接頭辞を認識させることは可能だが、人口の部分でB(ビリオン=10億)が出てきてエラー。
SI接頭辞とB(ビリオン)を処理
# データ内にMとかBとかの接頭辞があるので数値に変換 def prefix_modify(val): val = f"{val}" number = re.findall(r'\\d+(?:\\.\\d+)?', val)[0] if 'k' in val: number = float(number) * 1e3 elif 'M' in val: number = float(number) * 1e6 elif 'B' in val: number = float(number) * 1e9 return number
ということで接頭辞をうまく処理する方法を探していたけど、どうしてもBが処理できなかったのでムリヤリ作成。
prefix_modify
関数の引数val
は接頭辞の処理をしたい値で、数値の場合はのちにエラーが出るのでstr
で文字列に変換。
number
は以下のような挙動。要するにデータから数値のみを抽出。小数にも対応させた。
- 3.28M: 3.28
- 400k: 400
- 2650: 2650(そのまま)
あとはif
でk, M, Bがあればこれらを処理する。何も接頭辞がない場合は処理せずそのままnumber
を使用する。
実際にデータフレームに適用するにはapply
もしくはapplymap
を使用するが、今回は列ごととかじゃなくて各データに対して適用なのでapplymap
。
もちろん平均寿命で1kとかはないので、平均寿命のlife_expectancy
には適用しない。
# データフレーム中のSI接頭辞を数値に変換 income = income.applymap(prefix_modify) population = population.applymap(prefix_modify)
これで接頭辞を値に変換できているので確認する。ちゃんと値が変換されている。
print(income) # 1800 1801 1802 ... 2048 2049 2050 # country ... # Afghanistan 674 674 674 ... 3340 3410 3480 # Angola 691 693 697 ... 9320 9520 9720 # Albania 746 746 746 ... 28300.0 28900.0 29600.0 # Andorra 1340 1340 1340 ... 126000.0 128000.0 131000.0 # United Arab Emirates 1120 1120 1120 ... 86300.0 88100.0 90000.0 # ... ... ... ... ... ... ... ... # Samoa 1570 1570 1570 ... 9540 9740 9950 # Yemen 981 983 986 ... 4610 4710 4810 # South Africa 1760 1740 1720 ... 16800.0 17200.0 17600.0 # Zambia 741 743 746 ... 4090 4180 4270 # Zimbabwe 972 973 974 ... 4050 4130 4220 # [195 rows x 251 columns] print(population) # 1800 1801 ... 2099 2100 # country ... # Afghanistan 3280000.0 3280000.0 ... 75200000.0 74900000.0 # Angola 1570000.0 1570000.0 ... 186000000.0 188000000.0 # Albania 400000.0 402000.0 ... 1110000.0 1090000.0 # Andorra 2650 2650 ... 62500.0 62400.0 # United Arab Emirates 40200.0 40200.0 ... 12800000.0 12900000.0 # ... ... ... ... ... ... # Samoa 47300.0 47300.0 ... 311000.0 310000.0 # Yemen 2590000.0 2590000.0 ... 53400000.0 53200000.0 # South Africa 1450000.0 1450000.0 ... 79300000.0 79200000.0 # Zambia 747000.0 758000.0 ... 80800000.0 81500000.0 # Zimbabwe 1090000.0 1090000.0 ... 31000000.0 31000000.0 # [197 rows x 301 columns]
3データ揃っている国を抽出
income_country = set(income.index.values) life_expectancy_country = set(life_expectancy.index.values) population_country = set(population.index.values)
続いては収入・平均寿命・人口の3データが揃っている国名だけを抽出する作業。
というのも、データによったらこの国のデータは存在していないとかになっていることがある。これだとグラフ化がダルいので予め揃っていないデータは弾く。
setを使用すると一意的なデータを取得することができる。実際に収入を見てみると以下の国が含まれていることがわかる。
print(income_country) # {'Algeria', 'Cape Verde', 'Lao', 'Somalia', 'Gabon', 'Slovak Republic', 'Lesotho', 'North Macedonia', 'Mauritius', 'Turkmenistan', 'Burkina Faso', 'Kyrgyz Republic', 'Eritrea', 'Syria', 'Netherlands', 'Jordan', 'Monaco', 'Canada', 'Equatorial Guinea', 'Sudan', 'Kuwait', 'Israel', 'North Korea', 'Uruguay', 'Sao Tome and Principe', 'Russia', 'Samoa', 'China', 'Kazakhstan', 'Iceland', 'South Korea', 'Singapore', 'Cuba', 'Oman', 'Papua New Guinea', 'Estonia', 'Morocco', 'Marshall Islands', 'Dominican Republic', 'Czech Republic', 'Luxembourg', 'Madagascar', 'Antigua and Barbuda', 'Sri Lanka', 'Romania', 'Paraguay', 'Finland', 'Nauru', 'Slovenia', 'Cameroon', 'El Salvador', 'Mauritania', 'Turkey', 'Peru', 'Botswana', 'Zimbabwe', 'Tunisia', 'Ireland', 'Namibia', 'Sierra Leone', 'Honduras', 'Kenya', 'India', 'Armenia', 'United Kingdom', 'Vanuatu', 'Spain', 'Tuvalu', 'Bahrain', 'Congo, Dem. Rep.', 'Seychelles', 'United Arab Emirates', 'Brazil', 'France', 'New Zealand', 'Bulgaria', 'Guinea-Bissau', 'Mongolia', 'Bhutan', 'Iraq', 'Yemen', 'Azerbaijan', 'Malaysia', 'Eswatini', 'Tanzania', 'United States', 'Saudi Arabia', 'Myanmar', 'Belarus', 'Lebanon', 'Bahamas', 'Guinea', 'San Marino', 'Rwanda', 'Tajikistan', 'Hungary', 'Denmark', 'Solomon Islands', 'Andorra', 'Fiji', 'Montenegro', 'Nigeria', 'Panama', 'Chile', 'South Africa', 'Micronesia, Fed. Sts.', 'Angola', 'Hong Kong, China', 'South Sudan', 'Bosnia and Herzegovina', 'Trinidad and Tobago', 'Togo', 'Germany', 'Benin', 'Serbia', 'Mali', 'Malta', 'Ecuador', 'Austria', 'Belize', 'Djibouti', 'Thailand', 'Malawi', 'Congo, Rep.', 'Lithuania', 'Afghanistan', 'Poland', 'Venezuela', 'Taiwan', 'Central African Republic', "Cote d'Ivoire", 'Ukraine', 'Gambia', 'Costa Rica', 'Mexico', 'Zambia', 'Chad', 'Sweden', 'Jamaica', 'Libya', 'Georgia', 'Nepal', 'Qatar', 'Mozambique', 'Bangladesh', 'Pakistan', 'Palau', 'Guatemala', 'Norway', 'Haiti', 'Cyprus', 'Senegal', 'Albania', 'Tonga', 'Niger', 'Kiribati', 'Comoros', 'Belgium', 'Brunei', 'Ethiopia', 'Italy', 'Iran', 'Egypt', 'Portugal', 'Philippines', 'Liberia', 'Croatia', 'Indonesia', 'Uzbekistan', 'Ghana', 'Switzerland', 'St. Vincent and the Grenadines', 'St. Kitts and Nevis', 'St. Lucia', 'Guyana', 'Argentina', 'Bolivia', 'Burundi', 'Cambodia', 'Vietnam', 'Maldives', 'Barbados', 'Dominica', 'Nicaragua', 'Colombia', 'Grenada', 'Greece', 'Timor-Leste', 'Australia', 'Latvia', 'Suriname', 'Moldova', 'Palestine', 'Uganda', 'Japan'}
これらを論理演算子の&
で結んでやると、共通する国だけを出力してくれる。要するに揃っていないと出力されない。
ただし、set
の場合は順番が適当になるので、元のアルファベット順になるようにsorted
でソートしている。
# 3データ揃っているデータのみを抽出 common_country = income_country & life_expectancy_country & population_country common_country = sorted(common_country) print(common_country) # ['Afghanistan', 'Albania', 'Algeria', 'Andorra', 'Angola', 'Antigua and Barbuda', 'Argentina', 'Armenia', 'Australia', 'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bhutan', 'Bolivia', 'Bosnia and Herzegovina', 'Botswana', 'Brazil', 'Brunei', 'Bulgaria', 'Burkina Faso', 'Burundi', 'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Central African Republic', 'Chad', 'Chile', 'China', 'Colombia', 'Comoros', 'Congo, Dem. Rep.', 'Congo, Rep.', 'Costa Rica', "Cote d'Ivoire", 'Croatia', 'Cuba', 'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic', 'Ecuador', 'Egypt', 'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia', 'Eswatini', 'Ethiopia', 'Fiji', 'Finland', 'France', 'Gabon', 'Gambia', 'Georgia', 'Germany', 'Ghana', 'Greece', 'Grenada', 'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras', 'Hong Kong, China', 'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran', 'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kiribati', 'Kuwait', 'Kyrgyz Republic', 'Lao', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libya', 'Lithuania', 'Luxembourg', 'Madagascar', 'Malawi', 'Malaysia', 'Maldives', 'Mali', 'Malta', 'Marshall Islands', 'Mauritania', 'Mauritius', 'Mexico', 'Micronesia, Fed. Sts.', 'Moldova', 'Monaco', 'Mongolia', 'Montenegro', 'Morocco', 'Mozambique', 'Myanmar', 'Namibia', 'Nauru', 'Nepal', 'Netherlands', 'New Zealand', 'Nicaragua', 'Niger', 'Nigeria', 'North Korea', 'North Macedonia', 'Norway', 'Oman', 'Pakistan', 'Palau', 'Palestine', 'Panama', 'Papua New Guinea', 'Paraguay', 'Peru', 'Philippines', 'Poland', 'Portugal', 'Qatar', 'Romania', 'Russia', 'Rwanda', 'Samoa', 'San Marino', 'Sao Tome and Principe', 'Saudi Arabia', 'Senegal', 'Serbia', 'Seychelles', 'Sierra Leone', 'Singapore', 'Slovak Republic', 'Slovenia', 'Solomon Islands', 'Somalia', 'South Africa', 'South Korea', 'South Sudan', 'Spain', 'Sri Lanka', 'St. Kitts and Nevis', 'St. Lucia', 'St. Vincent and the Grenadines', 'Sudan', 'Suriname', 'Sweden', 'Switzerland', 'Syria', 'Taiwan', 'Tajikistan', 'Tanzania', 'Thailand', 'Timor-Leste', 'Togo', 'Tonga', 'Trinidad and Tobago', 'Tunisia', 'Turkey', 'Turkmenistan', 'Tuvalu', 'Uganda', 'Ukraine', 'United Arab Emirates', 'United Kingdom', 'United States', 'Uruguay', 'Uzbekistan', 'Vanuatu', 'Venezuela', 'Vietnam', 'Yemen', 'Zambia', 'Zimbabwe']
3データ揃っている年を抽出
income_year = set(income.columns.values) life_expectancy_year = set(life_expectancy.columns.values) population_year = set(population.columns.values)
年についても同じ。3データでは何年までのデータかが異なっているので共通する年だけを抽出する。
やってることはさっきの国の時と同じ。set
で一意的な国を抽出して(今回は元から一意的)、&
で共通部分を抽出。
# 共通する年を抽出 common_year = income_year & life_expectancy_year & population_year common_year = sorted(common_year) print(common_year) # ['1800', '1801', '1802', '1803', '1804', '1805', '1806', '1807', '1808', '1809', '1810', '1811', '1812', '1813', '1814', '1815', '1816', '1817', '1818', '1819', '1820', '1821', '1822', '1823', '1824', '1825', '1826', '1827', '1828', '1829', '1830', '1831', '1832', '1833', '1834', '1835', '1836', '1837', '1838', '1839', '1840', '1841', '1842', '1843', '1844', '1845', '1846', '1847', '1848', '1849', '1850', '1851', '1852', '1853', '1854', '1855', '1856', '1857', '1858', '1859', '1860', '1861', '1862', '1863', '1864', '1865', '1866', '1867', '1868', '1869', '1870', '1871', '1872', '1873', '1874', '1875', '1876', '1877', '1878', '1879', '1880', '1881', '1882', '1883', '1884', '1885', '1886', '1887', '1888', '1889', '1890', '1891', '1892', '1893', '1894', '1895', '1896', '1897', '1898', '1899', '1900', '1901', '1902', '1903', '1904', '1905', '1906', '1907', '1908', '1909', '1910', '1911', '1912', '1913', '1914', '1915', '1916', '1917', '1918', '1919', '1920', '1921', '1922', '1923', '1924', '1925', '1926', '1927', '1928', '1929', '1930', '1931', '1932', '1933', '1934', '1935', '1936', '1937', '1938', '1939', '1940', '1941', '1942', '1943', '1944', '1945', '1946', '1947', '1948', '1949', '1950', '1951', '1952', '1953', '1954', '1955', '1956', '1957', '1958', '1959', '1960', '1961', '1962', '1963', '1964', '1965', '1966', '1967', '1968', '1969', '1970', '1971', '1972', '1973', '1974', '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992', '1993', '1994', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024', '2025', '2026', '2027', '2028', '2029', '2030', '2031', '2032', '2033', '2034', '2035', '2036', '2037', '2038', '2039', '2040', '2041', '2042', '2043', '2044', '2045', '2046', '2047', '2048', '2049', '2050']
3データをデータフレームにまとめる
# 辞書でデータを入れる dct = { 'country': [], 'year': [], 'income': [], 'life_expectancy': [], 'population': [] }
px
でアニメーションを作成するにはデータフレームを使用するのが楽。ということで、3データをまとめたデータフレームを作成。
作成にはdict
を使用するのが楽なのでまずは必要なデータの格納先をdict
で作成。key
がデータフレームの列名となる。
あとはこのdict
の各key
に対応したデータをvalue
のlist
に入れていけばいい。
for name in common_country: for year in common_year: dct['country'].append(name) dct['year'].append(int(year)) dct['income'].append(float(income[year][name])) dct['life_expectancy'].append(float(life_expectancy[year][name])) dct['population'].append(float(population[year][name]))
国名を固定しつつ、年を固定し、各国と各年に該当する国名・年・収入・平均寿命・人口をlist
に入れる。
データはstr
になっており、この場合だと後々エラーになるのでint
やfloat
で調節している。
最後にこのdict
をpandas
のデータフレームに入れたら完成。
df = pd.DataFrame(dct) print(df) # country year income life_expectancy population # 0 Afghanistan 1800 674.0 28.2 3280000.0 # 1 Afghanistan 1801 674.0 28.2 3280000.0 # 2 Afghanistan 1802 674.0 28.2 3280000.0 # 3 Afghanistan 1803 674.0 28.2 3280000.0 # 4 Afghanistan 1804 674.0 28.2 3280000.0 # ... ... ... ... ... ... # 48940 Zimbabwe 2046 3880.0 66.9 22800000.0 # 48941 Zimbabwe 2047 3960.0 67.1 23100000.0 # 48942 Zimbabwe 2048 4050.0 67.3 23400000.0 # 48943 Zimbabwe 2049 4130.0 67.4 23700000.0 # 48944 Zimbabwe 2050 4220.0 67.6 23900000.0 # [48945 rows x 5 columns]
データの並び方としては、行方向にある国の各年のデータが並んでいく。ある国データが終われば次の行からは次の国の初めの年が始まる。
グラフ化するための関数
ということで、グラフを描くための前段階の準備は終わった。ここではグラフを描くための関数を解説。
グラフ保存用の関数
# グラフ保存用の関数 def save(fig, config, save_name): pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html", config=config,) pio.write_image(fig, f"{save_name}.png")
グラフ保存用の関数を定義。保存形式はhtmlとpng。config
はグラフ上部のツールバーのことで、config
の設定で追加や削除が可能。
-
-
【plotly&config】グラフのツールバーを編集する
続きを見る
グラフ化するための関数
def graph(save_name, step=1, drtn=200, **kwargs): # データが重いとき用に何データずつスキップするかを指定 years = common_year[::step] # yearsの各年はstrなのでintに変換 years = np.array(years).astype(int) # yearsに当てはまるyear列を持つデータフレームを作成 data_frame = df[df['year'].isin(years)] # 最低限の引数を設定、追加設定はkwargsで fig = px.scatter( data_frame=data_frame, # 使用するデータフレーム x='income', y='life_expectancy', # 横・縦軸の列名 animation_frame='year', # アニメーション軸の列名 animation_group='country', # 各アニメーションで同データとみなす列名 range_x=[500, 200000], range_y=[0, 100], # 横・縦軸の表示範囲 hover_data=df, # ホバーに表示する内容=dfの内容 **kwargs # 追加設定 ) # アニメーションの進行速度を速める fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = drtn # テンプレートではxanchorがrightなのでleftにしておく fig.update_layout(legend=dict(xanchor='left')) # グラフの表示と保存 config = template.plotly_config() fig.show(config=config) save(fig=fig, config=config, save_name=save_name)
ということで、最後にグラフ化するための関数を定義しておく。引数は以下。
save_name
: グラフの保存名step
: データを何年おきに作成するかdrtn
: アニメーションの遅延の値(ms単位)kwargs
: グラフ化に際しての追加条件
今回のアニメーションはデータが重くなることもあるので、step
で何年おきにするかを指定できるようにした。
また、アニメーションの動きが遅くなるとイライラするので遅延も指定可能に。
さらに、kwargs
でpx.scatter
の引数の追加を可能とした。kwargs
については以下。
px.scatter
はデータフレームを基準にどの列をどの引数にするかを指定する。列名になかったらエラーとなるので注意。
この関数の注意点としては凡例に国名を反映させる場合、isin
の影響で順番がバラバラなので色分けがぐちゃぐちゃになるということ。
isin
もset
と同じ論理演算子なので順番は考えない。order
を指定できる引数があればいいがないので仕方ない。
実際にグラフ化
実際にグラフ化する。まずはkwargs
を指定せずに最低限のデータのみでプロット。この場合は全てのプロットが同じ色なのでわかりにくい。
さらにマーカーサイズも同じなので何が何だかわからん。ということで、以下でkwrags
で追加設定を行う。
# デフォルトのアニメーション graph(save_name='animation', step=5)