LoginSignup
19
22

More than 3 years have passed since last update.

Pythonで世界地図(Basemap)

Last updated at Posted at 2018-04-26

2019/05/07現在、Python3ではエラーでBasemapのimportすら出来なくなりました。

http://ty21ky.web.fc2.com/python/
で、cartopy版の世界地図を始めました。

数日前に今迄インストールしたライブラリに新しいバージョンが沢山ありましたので、全てのライブラリを最新のバージョンにバージョンアップしました。
バージョンアップする前は、普通に動作していましたが、アップ後は動作しなくなりました。
現在のところ、原因はバージョンアップしたライブラリが悪いのかどうか不明です。
BaseMap関係のPython3のライブラリはバージョンアップしない方がよいようです。また、これからインストールする人は最新の物をインストールすると動作しません。

ひょっとして、もうBasemapはインストール出来ないかもしれない。

海外のサイトで、Basemapは廃止予定なのでcartopyを勉強してくださいと書いてました。

Python2では、使用できるようです。(ライブラリのバージョンアップしていません)

BaseMap_Python3_Error.png

matplotlib(3.0.3)をアンインストールし、元の(2.2.2)をインストールし実行すると、次は
「AttributeError: module 'pyproj' has no attribute 'pyproj_datadir'」
何か沢山元に戻す必要があるようです。

実行した環境

Ubuntu Stdio 17.10 ー> 18.04LTSにアップグレード
Python 2.7.14 ー> 2.7.15rc1
Python 3.6.3 ー> 3.6.5

18.04LTSにアップグレードしPython2で動作していたものが、'ascii'codec can't・・・で動作しないものもあります。
また、Python3で動作するようになりました。

いくつか実行しましたが、ほとんどのプログラムは動作して、エラーはほんの一部だけでした。

Python2の方で'ascii'codec can'tエラーがでるものは、importの前に

try:
    #Python2の場合
    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')
except NameError:
    pass  #Python3

を入れることで解決しました。
俺的備忘録 〜なんかいろいろ〜 さん ありがとうございます。
https://orebibou.com/2017/08/python%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%A7%E3%80%8Eunicodedecodeerror-ascii-codec-cant-decode-byte-0xc3%E3%80%8F%E3%81%A8%E3%81%84%E3%81%86%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C/

'ascii'codec can'tエラーが出るものと、出ないものがある。????

インストール(Python 2.7.14)

sudo apt install python-matplotlib
sudo apt install python-mpltoolkits.basemap

Python 3.6.3 ー> 3.6.5
sudo apt install python3-matplotlib
sudo apt install python3-mpltoolkits.basemap
でインストール出来るのですが、エラーがでて動作しません。(コメント欄に書きましたが動作する場合もあるようです。)
アップグレード後、Python3で動作するようになりました。

nihon.py
#!/usr/bin/python3
# coding: UTF-8

from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
#import numpy as np

map = Basemap(projection='ortho', lat_0=35, lon_0=135,
              resolution='l', area_thresh=1000.0)

map.drawcoastlines() #海岸線

center = 6378100 # (m) 地球中心座標
spece = 10000  #単位(m) #projection = 'ortho'の場合、地球の輪郭線の上下左右が線幅の1/2が表示範囲からはみ出て消えているため、表示範囲を広げる。
plt.axis([-spece, spece+center*2, -spece, spece+center*2])  #グラフの範囲(表示範囲)を広げる

# plt.savefig('xxx.png')  #pngで保存 
plt.show() #ウインドウで表示
#plt.close()  #plt.savefigで連続して行う場合は必ず必要。クローズしてメモリを開放する。

projection = 'cea' 正積円筒図法
projection = 'mbtfpq' McBryde-Thomas Flat-Polar Quartic 図法
projection='aeqd' 正距方位図法
projection = 'sinu 正弦曲線図法
projection = 'moll' モルワイデ図法
projection = 'gall' ゴール図法
projection = 'mill' ミラー図法
projection = 'merc' メルカトル図法(高緯度に向かうにつれ距離や面積が拡大される)
projection = 'cyl' Cylindrical Equidistant(極地域の縮尺と面積の歪みは、メルカトル図法よりも小さくなります。グラフの座標は東経・北緯の表示になります。)
projection = 'hammer' Hammer
projection = 'geos' Geostationary
projection = 'nsper' Near-Sided Perspective
projection = 'eck4' エケルト図法
projection = 'kav7' Kavrayskiy VII
projection = 'ortho' 正射投影(地球表面を平面に対して正射影して描かれる地図)
projection = 'vandg' ヴァン・デル・グリンテン図法
projection = 'robin' ロビンソン図法(楕円?形の地球)

lat_0 = 0.0 北緯(南緯の場合はマイナス)
lon_0 = 135.0 東経(西経でも良い。この場合はマイナス)

resolution = 'c' 荒い (早い)
resolution = 'l' low
resolution = 'i' 中間
resolution = 'h' high
resolution = 'f' full (非常に時間がかかる)

area_thresh = 0.0 〜 10000.0(これ以上になると大きな島が消えていく)
数値が小さいほうが、小さな島も表示されるが、時間もかかる。

map.bluemarble() 色を指定しないでこれを指定すると衛星写真
map.shadedrelief() 標高図(地球儀のようになる)
map.etopo() 陸地、海洋地形図
map.drawcountries() 国境線
map.drawrivers() 河川の描画
map.drawmapboundary(fill_color='aqua') #これだけを指定すると陸も海も'aqua'(水色)になる。
map.fillcontinents(color='coral',lake_color='aqua') #陸地と湖の色の指定。
map.drawmapboundary() 地図投影領域の周囲に境界線を描画し、必要に応じて領域の内側を塗りつぶします。

map.drawmeridians(np.arange(0, 360, 10)) #緯線 表示 例.10度毎
,labels=[True,False,False,True] を指定すると東経のラベル表示(地図の種類により表示されないものがある)
map.drawparallels(np.arange(-90, 90, 10)) #経線 表示 例.10度毎
,labels=[False,True,True,False] を指定すると北緯のラベル表示

map.drawparallels(np.arange(0, 1, 1),color='red',linestyle='solid') #赤道

image.png

サンプルプログラム

上記のサイトにたくさんあります。

https://qiita.com/sakaia/items/36c92d14942c3458bb56
ここでは、世界銀行のデータを世界地図上に表示出来る。

MotoGPのサーキットの位置を地図上にプロットする

circuit.pyのあるフォルダにdatasetsフォルダを作成し、circuit_data.csvを保存する。

circuit_data.csv
latitude,longitude,name
34.845602,136.539017,suzuka circuit
36.531433,140.224618,Twin Ring Motegi
25.486119,51.452865,Lusail Race Track
-27.512414,-64.917640,Autódromo internacional Termas De Rio Hondo
30.134451,-97.635765,Circuit of the Americas
36.709213,-6.033803,Circuito de Jerez
47.953644,0.213421,Circuit Bugatti
43.997518,11.372029,Mugello Circuit
41.568231,2.257314,Circuit de Barcelona-Catalunya
52.958256,6.522449,TT Circuit Assen
50.791774,12.688464,sachsenring-circuit
49.203901,16.44578,Brno Circuit
47.220266,14.764772,Red Bull Ring
-37.621419,145.02113,Silverstone Circuit
43.961893,12.684494,Misano World Circuit Marco Simoncelli
41.078284,-0.204513,MotorLand Aragón
14.957992,103.085011,Chang International Circuit
-38.496949,145.229462,Phillip Island Grand Prix Circuit
2.759404,101.731896,Sepang International Circuit
39.48688,-0.629795,Ricardo Tormo Circuit
circuit.py
#!/usr/bin/python

import csv

filename = 'datasets/circuit_data.csv'

# Create empty lists for the latitudes and longitudes.
lats, lons = [], []

# Read through the entire file, skip the first line,
#  and pull out just the lats and lons.
with open(filename) as f:
    # Create a csv reader object.
    reader = csv.reader(f)

    # Ignore the header row.
    next(reader)

    # Store the latitudes and longitudes in the appropriate lists.
    for row in reader:
        lats.append(float(row[0]))  #latitude
        lons.append(float(row[1]))  #longitude

# Build Map

from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np

# make sure the value of resolution is a lowercase L,
#  for 'low', not a numeral 1
map = Basemap(projection='robin', lat_0=0, lon_0=150,
              resolution='l', area_thresh=1000.0)

map.drawcoastlines()
map.drawcountries()
map.fillcontinents(color='gray')
map.drawmapboundary()
plt.title('2018 MotoGP circult + suzuka circuit')

map.drawmeridians(np.arange(0, 360, 10))
map.drawparallels(np.arange(-90, 90, 10))

x,y = map(lons, lats)
map.plot(x, y, 'ro', markersize=3)

plt.show()

image.png

サーキット名を表示

ズームしないと文字が重なります。
変更点

lats, lons, name1 = [], [], [] #変更

    for row in reader:
        lats.append(float(row[0]))  #latitude
        lons.append(float(row[1]))  #longitude
        name1.append(row[2])   #circuit name  #追加

x,y = map(lons, lats)
map.plot(x, y, 'ro', markersize=3)

for i in range(len(name1)):  #追加
    plt.text(x[i], y[i], "  " + name1[i], fontsize=12, color='red')  #追加

plt.show()

text()は、どうもリストが使えないようなのでfor文で繰り返す。
サーキット名の1文字目がドットに隠れるので、前にスペースを入れる。
y座標に値を追加すると、ズームで拡大すると文字がドットからズームするたびに離れていきます。
ズームはルーペ ボタンを何回も押さないとズーム出来ない??

image.png

19
22
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
22