Pythonで地球儀をまわして「それ、、、ココ！」ってやりたい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/9735893b-5924-b81a-a9f1-276221211302.png)

※補足
タイトルを見て「は？何言ってるの？」という方は「宇宙海賊 マダガスカル レボリューション」で検索していただければと思います。

## まずはマダガスカルを見つけてみましょう

💡必要なことは以下の通り

:::note info
1. マダガスカルの緯度経度を取得する
1. 地球儀を用意してクルクルまわす
1. マダガスカルで止める
:::

## Plotlyを使って実装
完成はこんな感じです。

![無題の動画.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/9e370a9b-f5c3-b377-0d59-dec8ad6a8285.gif)

https://youtu.be/l0i-WW1jg6g

地球儀を回してマダガスカルの場所でストップさせています。

### ⚓マダガスカルの緯度経度
Wikipediaで調べました。
より良い方法として、**geojson**などのデータセット使う方法もありますので、末尾に載せておきます。地図データを扱うならこちらの方がベターです。

```python
# 緯度
lat = -18.7669
# 経度
lon = 46.8691
```

### 🌎地球儀を出す
Plotlyの`Scattergeo`で地図を表示することができます。
日本を例に表示させてみます。

```python
import plotly.graph_objs as go
import numpy as np

# 日本の緯度経度
lat = 35.3929
lon = 139.4428

# 日本の場所に赤点を打つ
fig= go.Figure(go.Scattergeo(
    lat=[lat],
    lon=[lon],
    mode='markers',
    marker_color='red',
    marker_size=10,
))
# 座標を調整
fig.update_layout(
    width=1000, height=1000,
    title_text='日本',
    title_x=0.5,
    geo=dict(
        # 選んだ国の座標が中心に表示されるようにする
        center_lon=lon,
        center_lat=lat,
        projection_rotation_lon=lon,
        projection_rotation_lat=lat,
        showland=True,
        showcountries=True,
        # 塗りつぶしと枠線の色
        landcolor='#99BBFF',
        countrycolor='#000000'
    )
)
fig.show()
```

![newplot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/74a0b12e-9246-689c-92f7-6e246c14b596.png)

このままでは平面図なので、丸い図形にします。図の装飾は`layut.geo`の`projection_type`に好みの図法を指定すればOK！

詳しいドキュメントはこちら

https://plotly.com/python/reference/layout/geo/

**球体は、`projection_type = 'orthographic'`です。**

![newplot (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/a36c9ad3-a61a-7ee2-79a8-2dc4caf4400b.png)

これで丸い地球儀が描けました！

<details><summary>コードはこちら</summary>

```python
# 日本の緯度経度
lat = 35.3929
lon = 139.4428

# 日本の場所に赤点を打つ
fig= go.Figure(go.Scattergeo(
    lat=[lat],
    lon=[lon],
    mode='markers',
    marker_color='red',
    marker_size=10,
))
# 座標を調整
fig.update_layout(
    width=1000, height=1000,
    title_text='日本',
    title_x=0.5,
    geo=dict(
        projection_type='orthographic',# ←加えた部分
        center_lon=lon,
        center_lat=lat,
        projection_rotation_lon=lon,
        projection_rotation_lat=lat,
        showland=True,
        showcountries=True,
        landcolor='#99BBFF',
        countrycolor='#000000'
    )
)
fig.show()
```

</details>

### 🧭アニメーションをつける
**`graph_objs.Frame`でアニメーションを追加します。**
経度の方向に270度分 (90度から360度) 回転させます。

```python
lon_range = np.arange(90+lon, 360+lon, 2)
frames = [go.Frame(layout=dict(geo_center_lon=lon,
                               geo_projection_rotation_lon=lon
                              )
                  ) for lon in lon_range]

fig.update(frames=frames)
```

さらに、layoutの中でボタンのコンポーネントを用意し、ボタンを押したときのアニメーションが動くようにします。

```python
updatemenus=[
   dict(type='buttons', 
        showactive=False,
        y=1,
        x=1.2,
        xanchor='right',
        yanchor='top',
        pad=dict(t=0, r=10),
        buttons=[
           dict(label='それ、、ココ！',
                method='animate',
                args=[
                    None,
                    dict(frame=dict(duration=20, 
                                    redraw=True),
                         transition=dict(duration=0),
                         fromcurrent=True,
                         mode='immediate')
                ]
            )
        ]
    )
]
```

<details><summary>コードの全体はこちら</summary>

```python
import plotly.graph_objs as go
import numpy as np

lat = -18.7669
lon = 46.8691

fig= go.Figure(go.Scattergeo(
    lat=[lat],
    lon=[lon],
    mode='markers',
    marker_color='red',
    marker_size=10,
))

fig.update_layout(
    width=500, height=500,
    title_text='マダガスカル',
    title_x=0.5,
    geo=dict(
        projection_type='orthographic',
        center_lon=100+lon,
        center_lat=0,
        projection_rotation_lon=100+lon,
        showland=True,
        showcountries=True,
        landcolor='#99BBFF',
        countrycolor='#000000'
    ),
    updatemenus=[
       dict(type='buttons', 
            showactive=False,
            y=1,
            x=1.2,
            xanchor='right',
            yanchor='top',
            pad=dict(t=0, r=10),
            buttons=[
               dict(label='それ、、ココ！',
                    method='animate',
                    args=[
                        None,
                        dict(frame=dict(duration=20, 
                                        redraw=True),
                             transition=dict(duration=0),
                             fromcurrent=True,
                             mode='immediate')
                    ]
                )
            ]
        )
    ]
)

lon_range = np.arange(100+lon, 360+lon, 2)
frames = [go.Frame(layout=dict(geo_center_lon=lon,
                               geo_projection_rotation_lon=lon
                              )
                  ) for lon in lon_range]

fig.update(frames=frames)
fig.show()
```

</details>

これを実行すると冒頭に示したような地球儀を回してマダガスカルでストップするようなアニメーションがつくれます。

もっとグルグル勢いよく回したい場合は、`lon_range`の範囲を360→720度などに変えて、`duration`を短くすればOKです。



## おまけ
今回は座標を調べて入力するような方法でしたが**geojson**を使えば、国名から国の輪郭に沿って塗りつぶすことも簡単です。
詳しくはこちらにGitHubリンクを載せておきます。

https://github.com/yutowac/DataScience/blob/main/preprocessing-draw-world-map-by-folium.ipynb


また、地球儀のような球体の図法以外にも`projection_type`ではこれだけの選択肢があります。モルワイデ図法とか懐かしいですね！

:::note warn
( "airy" | "aitoff" | "albers" | "albers usa" | "august" | "azimuthal equal area" | "azimuthal equidistant" | "baker" | "bertin1953" | "boggs" | "bonne" | "bottomley" | "bromley" | "collignon" | "conic conformal" | "conic equal area" | "conic equidistant" | "craig" | "craster" | "cylindrical equal area" | "cylindrical stereographic" | "eckert1" | "eckert2" | "eckert3" | "eckert4" | "eckert5" | "eckert6" | "eisenlohr" | "equal earth" | "equirectangular" | "fahey" | "foucaut" | "foucaut sinusoidal" | "ginzburg4" | "ginzburg5" | "ginzburg6" | "ginzburg8" | "ginzburg9" | "gnomonic" | "gringorten" | "gringorten quincuncial" | "guyou" | "hammer" | "hill" | "homolosine" | "hufnagel" | "hyperelliptical" | "kavrayskiy7" | "lagrange" | "larrivee" | "laskowski" | "loximuthal" | "mercator" | "miller" | "mollweide" | "mt flat polar parabolic" | "mt flat polar quartic" | "mt flat polar sinusoidal" | "natural earth" | "natural earth1" | "natural earth2" | "nell hammer" | "nicolosi" | "orthographic" | "patterson" | "peirce quincuncial" | "polyconic" | "rectangular polyconic" | "robinson" | "satellite" | "sinu mollweide" | "sinusoidal" | "stereographic" | "times" | "transverse mercator" | "van der grinten" | "van der grinten2" | "van der grinten3" | "van der grinten4" | "wagner4" | "wagner6" | "wiechel" | "winkel tripel" | "winkel3" )
::: 

試しに、こちらは`projection_type = albers` にした場合です。面白い動きをしました！

https://youtu.be/ryCBYLn8omk