追記
- 2016年の入場者数のデータに更新しました。
- Bokeh 0.12.6に対応しました。
Pythonでインタラクティブなグラフを描画できるライブラリ「Bokeh」を使って、Wikipediaに掲載されている世界テーマパーク入場者数ランキングを、可視化してみました。
今回は、Bokehのグラフを手軽に描画できるbokeh.charts bkchartsを使いました。
追記(Ver.0.12.6)
Bokeh 0.12.6から、bokeh.chartsは別モジュール(bkcharts)に分離されました。Ver.1.0までは、互換性維持の為に引き続きbokeh.chartsも使用することができますが、importする際に下記の警告が表示されます。
BokehDeprecationWarning: The bokeh.charts API has moved to a separate 'bkcharts' package. This compatibility shim will remain until Bokeh 1.0 is released. After that, if you want to use this API you will have to install the bkcharts package explicitly.
1. 作成したグラフ
Wikipediaの世界テーマパーク入場者数ランキングは、クリエイティブ・コモンズ 表示-継承ライセンスの下で公開されているので、このグラフのラインセンスも、それを継承してクリエイティブ・コモンズ 表示-継承ライセンスです。
ユニバーサル・スタジオ・ジャパンの入場者数が近年増加していることが分かります。2015年の時点で東京ディズニーシーの入園者数を超えていますが、2016年時点でまだ東京ディズニーランドの入園者数は超えられていません。
2. 前提バージョン
この記事で前提としているのは、下記のバージョンです。
- python : Ver.3.5.3
- pandas : Ver.0.20.1
- bokeh : Ver.0.12.6
3. 必要なモジュールのインポート
1 2 3 4 5 | import pandas as pd
# from bokeh.charts import Line # Ver.0.12.5以前
from bkcharts import Line # Ver.0.12.6以降
from bokeh.io import show
from bokeh.models import NumeralTickFormatter
|
4. WikipediaからDataFrameを抽出・取得
pandasのread_html関数を使います。
1 | dflist = pd.read_html('https://en.wikipedia.org/wiki/List_of_amusement_park_rankings', header=0, index_col=0)
|
2つ目のDataFrameが、世界のテーマパーク入場者数ランキングの表です。
2 3 | df = dflist[1]
df.info()
|
<class 'pandas.core.frame.DataFrame'> Float64Index: 45 entries, 1.0 to 45.0 Data columns (total 12 columns): Amusement park 45 non-null object Location 45 non-null object 2006[1] 35 non-null float64 2008[3] 34 non-null float64 2009[4] 38 non-null float64 2010[5] 40 non-null float64 2011[6] 39 non-null float64 2012[7] 40 non-null float64 2013[8] 40 non-null float64 2014[9] 41 non-null float64 2015[10] 43 non-null float64 2016[11] 45 non-null int64 dtypes: float64(9), int64(1), object(2) memory usage: 4.6+ KB
5. データの整形・クリーンナップ
5.1. カラム名の「[1]」等の注釈を取り除く
「[数字]」(正規表現で指定)を空文字列に置換します。
1 2 | df.columns = df.columns.str.replace('\[\d+\]', '')
df.columns
|
Index(['Amusement park', 'Location', '2006', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016'], dtype='object')
5.2. インデックスをテーマパーク名にする
indexを「Amusement park」カラムで置き換えます。
1 | df.index
|
Float64Index([ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, nan, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0, 44.0, 45.0], dtype='float64', name='Rank')
2 3 | df.index = df['Amusement park']
df.index
|
Index(['Magic Kingdom at Walt Disney World Resort', 'Disneyland Park at Disneyland Resort', 'Tokyo Disneyland at Tokyo Disney Resort', 'Universal Studios Japan', 'Tokyo DisneySea at Tokyo Disney Resort', 'Epcot at Walt Disney World Resort', 'Disney's Animal Kingdom at Walt Disney World Resort', 'Disney's Hollywood Studios at Walt Disney World Resort', 'Universal Studios Florida at Universal Orlando Resort', 'Universal's Islands of Adventure at Universal Orlando Resort', 'Disney California Adventure Park at Disneyland Resort', 'Chimelong Ocean Kingdom', 'Disneyland Park at Disneyland Paris', 'Lotte World', 'Universal Studios Hollywood', 'Everland at Everland Resort', 'Hong Kong Disneyland at Hong Kong Disneyland Resort', 'Ocean Park Hong Kong', 'Nagashima Spa Land', 'Europa-Park at Europa-Park Resort', 'Shanghai Disneyland Park at Shanghai Disney Resort', 'Walt Disney Studios Park at Disneyland Paris', 'Efteling', 'Tivoli Gardens', 'SeaWorld Orlando', 'Busch Gardens Tampa Bay', 'Universal Studios Singapore', 'Knott's Berry Farm', 'OCT East', 'Window of the World at OCT Resort', 'Happy Valley at OCT Resort', 'Chimelong Paradise', 'Happy Valley', 'Canada's Wonderland', 'PortAventura Park at PortAventura World', 'Cedar Point', 'SeaWorld San Diego', 'Fantawild Adventure', 'Fantawild Oriental Heritage', 'Kings Island', 'Six Flags Magic Mountain', 'Hersheypark', 'Six Flags Great Adventure', 'Liseberg', 'Six Flags Great America'], dtype='object', name='Amusement park')
5.3. テーマパーク名と場所のカラムを削除
drop関数を使って、カラムを削除します。
1 2 | df.drop(['Location', 'Amusement park'], axis=1, inplace=True)
df.info()
|
<class 'pandas.core.frame.DataFrame'> Index: 45 entries, Magic Kingdom at Walt Disney World Resort to Six Flags Great America Data columns (total 10 columns): 2006 35 non-null float64 2008 34 non-null float64 2009 38 non-null float64 2010 40 non-null float64 2011 39 non-null float64 2012 40 non-null float64 2013 40 non-null float64 2014 41 non-null float64 2015 43 non-null float64 2016 45 non-null int64 dtypes: float64(9), int64(1) memory usage: 3.9+ KB
5.4. カラムとインデックスを入れ替える(転置)
1 2 | dft = df.T
dft.info()
|
<class 'pandas.core.frame.DataFrame'> Index: 10 entries, 2006 to 2016 Data columns (total 45 columns): Magic Kingdom at Walt Disney World Resort 10 non-null float64 Disneyland Park at Disneyland Resort 10 non-null float64 Tokyo Disneyland at Tokyo Disney Resort 10 non-null float64 Universal Studios Japan 10 non-null float64 Tokyo DisneySea at Tokyo Disney Resort 10 non-null float64 Epcot at Walt Disney World Resort 10 non-null float64 Disney's Animal Kingdom at Walt Disney World Resort 10 non-null float64 Disney's Hollywood Studios at Walt Disney World Resort 10 non-null float64 Universal Studios Florida at Universal Orlando Resort 10 non-null float64 Universal's Islands of Adventure at Universal Orlando Resort 10 non-null float64 Disney California Adventure Park at Disneyland Resort 10 non-null float64 Chimelong Ocean Kingdom 3 non-null float64 Disneyland Park at Disneyland Paris 10 non-null float64 Lotte World 10 non-null float64 Universal Studios Hollywood 10 non-null float64 Everland at Everland Resort 10 non-null float64 Hong Kong Disneyland at Hong Kong Disneyland Resort 10 non-null float64 Ocean Park Hong Kong 10 non-null float64 Nagashima Spa Land 10 non-null float64 Europa-Park at Europa-Park Resort 10 non-null float64 Shanghai Disneyland Park at Shanghai Disney Resort 1 non-null float64 Walt Disney Studios Park at Disneyland Paris 10 non-null float64 Efteling 10 non-null float64 Tivoli Gardens 10 non-null float64 SeaWorld Orlando 10 non-null float64 Busch Gardens Tampa Bay 10 non-null float64 Universal Studios Singapore 7 non-null float64 Knott's Berry Farm 10 non-null float64 OCT East 7 non-null float64 Window of the World at OCT Resort 8 non-null float64 Happy Valley at OCT Resort 10 non-null float64 Chimelong Paradise 8 non-null float64 Happy Valley 8 non-null float64 Canada's Wonderland 10 non-null float64 PortAventura Park at PortAventura World 10 non-null float64 Cedar Point 10 non-null float64 SeaWorld San Diego 10 non-null float64 Fantawild Adventure 2 non-null float64 Fantawild Oriental Heritage 1 non-null float64 Kings Island 10 non-null float64 Six Flags Magic Mountain 9 non-null float64 Hersheypark 10 non-null float64 Six Flags Great Adventure 9 non-null float64 Liseberg 10 non-null float64 Six Flags Great America 2 non-null float64 dtypes: float64(45) memory usage: 3.9+ KB
3 | dft.head()
|
Amusement park | Magic Kingdom at Walt Disney World Resort | Disneyland Park at Disneyland Resort | Tokyo Disneyland at Tokyo Disney Resort | Universal Studios Japan | Tokyo DisneySea at Tokyo Disney Resort | Epcot at Walt Disney World Resort | Disney's Animal Kingdom at Walt Disney World Resort | Disney's Hollywood Studios at Walt Disney World Resort | Universal Studios Florida at Universal Orlando Resort | Universal's Islands of Adventure at Universal Orlando Resort | ... | Cedar Point | SeaWorld San Diego | Fantawild Adventure | Fantawild Oriental Heritage | Kings Island | Six Flags Magic Mountain | Hersheypark | Six Flags Great Adventure | Liseberg | Six Flags Great America |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2006 | 16640000.0 | 14730000.0 | 12900000.0 | 8500000.0 | 12100000.0 | 10460000.0 | 9100000.0 | 8910000.0 | 6000000.0 | 5300000.0 | ... | 3070000.0 | 4260000.0 | NaN | NaN | 3050000.0 | 2550000.0 | 2690000.0 | 2730000.0 | 2950000.0 | NaN |
2008 | 17063000.0 | 14721000.0 | 14293000.0 | 8300000.0 | 12498000.0 | 10935000.0 | 9540000.0 | 9608000.0 | 6231000.0 | 5297000.0 | ... | 3198000.0 | 4174000.0 | NaN | NaN | 3126000.0 | NaN | 2842000.0 | 2761000.0 | 3050000.0 | NaN |
2009 | 17233000.0 | 15900000.0 | 13646000.0 | 8000000.0 | 12004000.0 | 10990000.0 | 9590000.0 | 9700000.0 | 5530000.0 | 4627000.0 | ... | 2942000.0 | 4200000.0 | NaN | NaN | 3000000.0 | 2500000.0 | 2807000.0 | 2634000.0 | 3150000.0 | NaN |
2010 | 16972000.0 | 15980000.0 | 14452000.0 | 8160000.0 | 12663000.0 | 10825000.0 | 9686000.0 | 9603000.0 | 5925000.0 | 5949000.0 | ... | 3051000.0 | 3800000.0 | NaN | NaN | 3112000.0 | 2600000.0 | 2891000.0 | 2700000.0 | 2900000.0 | NaN |
2011 | 17142000.0 | 16140000.0 | 13996000.0 | 8500000.0 | 11930000.0 | 10825000.0 | 9783000.0 | 9699000.0 | 6044000.0 | 7674000.0 | ... | 3143000.0 | 4294000.0 | NaN | NaN | 3143000.0 | 2700000.0 | 2949000.0 | NaN | 2900000.0 | NaN |
5 rows × 45 columns
5.5. DataFrameを、上位6パークのみに絞り込む
今回は(Wikipediaの表がそのようなレイアウトになっているので)、左から6カラム目までが上位6パーク(2016年時点)です。
1 2 | dfplot = dft.iloc[:, 0:6]
dfplot
|
Amusement park | Magic Kingdom at Walt Disney World Resort | Disneyland Park at Disneyland Resort | Tokyo Disneyland at Tokyo Disney Resort | Universal Studios Japan | Tokyo DisneySea at Tokyo Disney Resort | Epcot at Walt Disney World Resort |
---|---|---|---|---|---|---|
2006 | 16640000.0 | 14730000.0 | 12900000.0 | 8500000.0 | 12100000.0 | 10460000.0 |
2008 | 17063000.0 | 14721000.0 | 14293000.0 | 8300000.0 | 12498000.0 | 10935000.0 |
2009 | 17233000.0 | 15900000.0 | 13646000.0 | 8000000.0 | 12004000.0 | 10990000.0 |
2010 | 16972000.0 | 15980000.0 | 14452000.0 | 8160000.0 | 12663000.0 | 10825000.0 |
2011 | 17142000.0 | 16140000.0 | 13996000.0 | 8500000.0 | 11930000.0 | 10825000.0 |
2012 | 17536000.0 | 15963000.0 | 14847000.0 | 9700000.0 | 12656000.0 | 11063000.0 |
2013 | 18588000.0 | 16202000.0 | 17214000.0 | 10100000.0 | 14084000.0 | 11229000.0 |
2014 | 19332000.0 | 16769000.0 | 17300000.0 | 11800000.0 | 14100000.0 | 11454000.0 |
2015 | 20492000.0 | 18278000.0 | 16600000.0 | 13900000.0 | 13600000.0 | 11798000.0 |
2016 | 20395000.0 | 17943000.0 | 16540000.0 | 14500000.0 | 13460000.0 | 11712000.0 |
6. グラフの描画
6.1. まずは描画してみる
bokeh.chartsのLineを使って、線グラフを描いてみます。
1 2 | p = Line(dfplot)
show(p)
|
6.2. 見映えを変更
オプションを指定して、グラフを見易く調整します。
- グラフのタイトルを設定
- X軸、Y軸にラベルを設定
- Y軸の数字表記を、カンマ付きの読み易い表記に変更
1 2 3 | p = Line(dft.iloc[:, 0:6], title='テーマパーク入場者数', xlabel='年', ylabel='入場者数(人)')
p.yaxis.formatter = NumeralTickFormatter(format='0,0')
show(p)
|
6.3. X軸の間隔を補正
2007年のデータがないので、X軸の間隔が一定ではなくなってしまっています。 indexをDateTimeIndexに変換して、改善します。
1 | dft.index
|
Index(['2006', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016'], dtype='object')
2 3 | dft.index = pd.to_datetime(dft.index)
dft.index
|
DatetimeIndex(['2006-01-01', '2008-01-01', '2009-01-01', '2010-01-01', '2011-01-01', '2012-01-01', '2013-01-01', '2014-01-01', '2015-01-01', '2016-01-01'], dtype='datetime64[ns]', freq=None)
6.4. 再び描画
1 2 3 4 | p = Line(dft.iloc[:, 0:6], title='テーマパーク入場者数', xlabel='年', ylabel='入場者数(人)')
# y軸の数字表記変更
p.yaxis.formatter = NumeralTickFormatter(format='0,0')
show(p)
|
これで完成です。