0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

matplotlib: ETOPOのプロット、地図に等距離円を描く、画像に画像を張り込む (2026.05.08)

0
Last updated at Posted at 2026-05-08

はじめに

必要があり、題記のプログラムを作ったので、紹介する。作ったと言うより、Google検索で、AIが示したコードを修正して使ってみたと言う感じ。

作例

fig_comb.jpg

ETOPOの描画と等距離円の描画

ETOPOのデータを別途ダウンロードしておく。
pip install cartopypip 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()

以 上

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?