はじめに
必要があり、題記のプログラムを作ったので、紹介する。作ったと言うより、Google検索で、AIが示したコードを修正して使ってみたと言う感じ。
作例
ETOPOの描画と等距離円の描画
ETOPOのデータを別途ダウンロードしておく。
pip install cartopyとpip install netCDF4が必要。Windowsでcartopyをインストールするのは面倒である。ネットで検索するといくつかの方法があるようだが、私の場合は、cartopyをインストールするだけの目的で、Microsoft C++ Build Toolsをインストールした。
等距離円を描くのは、ax.tissot(rad_km=dis,lons=lon1,lats=lat1,color='#0000ff',alpha=0.2)とかでもいける。
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import netCDF4 as nc
import numpy as np
import cartopy.geodesic as cgeo
def circ(ax,lon,lat,dist):
cp=cgeo.Geodesic().circle(
lon=lon, lat=lat, radius=dist*1000, # (m)
n_samples=100,
endpoint=True
)
geom=plt.Polygon(
cp,
#edgecolor='#0000ff',
#facecolor='None',
color='#0000ff',
alpha=0.2,
transform=ccrs.Geodetic()
)
ax.add_patch(geom)
ax.plot(lon, lat, 'ko', markersize=5, transform=ccrs.Geodetic())
def main():
# Read netCDF4
fn = 'ETOPO1_Bed_c_gmt4.grd'
ds = nc.Dataset(fn)
# x: latitude, y: longitude, z: elevation
lon = ds.variables['x'][:]
lat = ds.variables['y'][:]
topo = ds.variables['z'][:]
# Ploting area
lon_min, lon_max = 136, 142
lat_min, lat_max = 33,40
# get the data in plotting area
lon_idx = (lon >= lon_min) & (lon <= lon_max)
lat_idx = (lat >= lat_min) & (lat <= lat_max)
topo_subset = topo[lat_idx][:, lon_idx]
lon_subset = lon[lon_idx]
lat_subset = lat[lat_idx]
# Plot by cartopy
proj=ccrs.PlateCarree()
iw=12
ih=iw/(lon_max-lon_min)*(lat_max-lat_min)
fig = plt.figure(figsize=(iw, ih))
ax = plt.axes(projection=proj)
# map
ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=proj)
# add coastline and border
ax.add_feature(cfeature.COASTLINE, linewidth=1)
ax.add_feature(cfeature.BORDERS, linestyle=':', linewidth=2)
# Plotting ETOPO data
cf = ax.contourf(lon_subset, lat_subset, topo_subset,
levels=np.linspace(0, 3000, 31),
cmap='magma_r', transform=ccrs.PlateCarree(),alpha=0.7)
# color bar
cbar = plt.colorbar(cf, ax=ax, orientation='vertical', shrink=0.7)
cbar.set_label('Elevation (m)')
# Tokyo
lat1=35.6894
lon1=139.6917
# Niigata
lat2=37.912028
lon2=139.061889
# Sendai
lat3=38.2606
lon3=140.8812
# raadius 100km
dis=100
#ax.tissot(rad_km=dis,lons=lon1,lats=lat1,color='#0000ff',alpha=0.2)
circ(ax,lon1,lat1,dis)
circ(ax,lon2,lat2,dis)
circ(ax,lon3,lat3,dis)
# add grid
gl = ax.gridlines(draw_labels=True, linestyle='--')
gl.top_labels = False
gl.right_labels = False
plt.title('ETOPO1 Topography - Tokyo Region')
fnameF='fig_map1.jpg'
plt.savefig(fnameF, dpi=200, bbox_inches="tight", pad_inches=0.1)
# ---------------
# Execute
# ---------------
if __name__ == '__main__': main()
小さな表を作成
これは自前のプログラム。
表を作成し、貼り付けようにトリムしておく。
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageChops
def fig_trim(fig):
def trim(im, border):
bg = Image.new(im.mode, im.size, border)
diff = ImageChops.difference(im, bg)
bbox = diff.getbbox()
return im.crop(bbox)
img_org=Image.open(fig,'r')
img_new=trim(img_org,'#ffffff')
img_new.save(fig, 'JPEG', quality=100, optimize=True)
def inp_data():
_data=np.array([
['Transportation route','','',''],
['Route' ,'Unit','Value','Remarks'],
['From Tokyo' ,'km' ,100.0,'existing'],
['From Niigata' ,'km' ,100.0,'existing'],
['From Sendai' ,'km' ,100.0,'existing'],
['to Intake dam' ,'km' , 20.0,'new'],
['to Head tank' ,'km' , 15.0,'new'],
['to Power Station','km' , 10.0,'new']
],dtype=object)
n,m=_data.shape
data=np.empty((n,m),dtype=object)
for i in range(n):
for j in range(m):
s=_data[i,j]
try:
s=float(s)
data[i,j]=f'{s:6.1f}'
except ValueError:
data[i,j]=s
return data
def mp_tbl(data,dpara,fsz):
xmin,xmax=dpara[0],dpara[1]
ymin,ymax=dpara[2],dpara[3]
tw,th=dpara[4],dpara[5]
colw=dpara[6]
tbl=plt.table(
cellText=data,
colWidths=colw,
cellLoc='left',
edges='open',
bbox=[xmin,ymin,tw,th]
)
tbl.auto_set_font_size(False)
tbl.set_fontsize(fsz)
n,m=data.shape
for i in range(n):
for j in range(m):
if i==0:
tbl[i,j].set_text_props(ha='left',fontweight='bold')
else:
tbl[i,j].visible_edges='closed'
tbl[i,j].set_edgecolor('#000000')
tbl[i,j].set_facecolor('#ffffff')
tbl[i,j].set_linewidth(0.5)
def fig(fnameF):
data=inp_data()
n,m=data.shape
c1,c2,c3,c4=0,0,0,0
for i in range(1,n):
for j in range(0,m):
w1=len(data[i,0])
w2=len(data[i,1])
w3=len(data[i,2])
w4=len(data[i,3])
if c1<w1: c1=w1
if c2<w2: c2=w2
if c3<w3: c3=w3
if c4<w4: c4=w4
tw,th=1.0,0.5 # table width, table height
col=np.array([c1,c2,c3,c4])
colw=col/np.sum(col)*tw
fsz=10
xmin,xmax= 0, 1
ymin,ymax= 0, 1
iw,ih=fsz/72*np.sum(col)*1.0, fsz/72*m*6 # default (inch)
plt.figure(figsize=(iw,ih),facecolor='w')
plt.rcParams['font.size']=fsz
plt.rcParams['font.family']='monospace'
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.axis('off')
dpara=[xmin,xmax,ymin,ymax,tw,th,colw]
mp_tbl(data,dpara,fsz)
plt.savefig(fnameF, dpi=200, bbox_inches="tight", pad_inches=0.1)
def main():
fnameF='fig_table.jpg'
fig(fnameF)
fig_trim(fnameF)
#---------------
# Execute
#---------------
if __name__ == '__main__': main()
作成した小さな表を地図に貼り付ける
from PIL import Image, ImageDraw, ImageFilter
def main():
fname1='fig_map1.jpg'
fname2='fig_table.jpg'
fname3='fig_comb.jpg'
im1 = Image.open(fname1)
im2 = Image.open(fname2)
w1,h1=im1.size
w2,h2=im2.size
dw=int(w1*0.07)
dh=int(h1*0.05)
back_im = im1.copy()
back_im.paste(im2,(dw,dh))
back_im.save(fname3, quality=100)
#---------------
# Execute
#---------------
if __name__ == '__main__': main()
以 上
