[Python] Draw elevation data on a sphere with Plotly and draw a globe that can be rotated round and round

Introduction

Using Plotly, which supports various languages including Python and allows you to draw interactive diagrams relatively easily, you can use elevation data to rotate around like Google Earth. Let's create a globe.

The result looks like this. https://rkiuchir.github.io/3DSphericalTopo

EarthGlove.gif

3 points

  1. Acquisition and reading of elevation data
  2. Convert latitude / longitude information expressed in Cartesian coordinate system to spherical coordinate system ([Plotly Chart Studio: Heatmap plot on a spherical map](https://chart-studio.plotly.com/~empet/14813/heatmap] -see plot-on-a-spherical-map / # /))
  3. Draw with Plotly

Execution environment

0. Install Plotly

It can be installed with pip install plotly.

1-1. Acquisition of altitude data

1-2. Reading elevation data

First, read the three data of latitude / longitude and altitude from the data file in netCDF format.

Regarding the resolution, the data is skipped according to the specified resolution value.

import numpy as np
from netCDF4 import Dataset

def Etopo(lon_area, lat_area, resolution):
    ### Input
    # resolution: resolution of topography for both of longitude and latitude [deg]
    # (Original resolution is 0.0167 deg)
    # lon_area and lat_area: the region of the map which you want like [100, 130], [20, 25]
    ###
    

    ### Output
    # Mesh type longitude, latitude, and topography data
    ### 

    # Read NetCDF data
    data = Dataset("ETOPO1_Ice_g_gdal.grd", "r")
    
    # Get data
    lon_range = data.variables['x_range'][:]
    lat_range = data.variables['y_range'][:]
    topo_range = data.variables['z_range'][:]
    spacing = data.variables['spacing'][:]
    dimension = data.variables['dimension'][:]
    z = data.variables['z'][:]

    lon_num = dimension[0]
    lat_num = dimension[1]
    
    # Prepare array
    lon_input = np.zeros(lon_num); lat_input = np.zeros(lat_num)
    for i in range(lon_num):
        lon_input[i] = lon_range[0] + i * spacing[0]

    for i in range(lat_num):
        lat_input[i] = lat_range[0] + i * spacing[1]

    # Create 2D array
    lon, lat = np.meshgrid(lon_input, lat_input)

    # Convert 2D array from 1D array for z value
    topo = np.reshape(z, (lat_num, lon_num))

    # Skip the data for resolution
    if ((resolution < spacing[0]) | (resolution < spacing[1])):
        print('Set the highest resolution')
    else:
        skip = int(resolution/spacing[0])
        lon = lon[::skip,::skip]
        lat = lat[::skip,::skip]
        topo = topo[::skip,::skip]

    topo = topo[::-1]

    # Select the range of map
    range1 = np.where((lon>=lon_area[0]) & (lon<=lon_area[1]))
    lon = lon[range1]; lat = lat[range1]; topo = topo[range1]
    range2 = np.where((lat>=lat_area[0]) & (lat<=lat_area[1]))
    lon = lon[range2]; lat = lat[range2]; topo = topo[range2]
    
    # Convert 2D again
    lon_num = len(np.unique(lon))
    lat_num = len(np.unique(lat))
    lon = np.reshape(lon, (lat_num, lon_num))
    lat = np.reshape(lat, (lat_num, lon_num))
    topo = np.reshape(topo, (lat_num, lon_num))
   
    return lon, lat, topo

2. Convert latitude / longitude information to spherical coordinates

(See Plotly Chart Studio: Heatmap plot on a spherical map)

Here, the latitude / longitude information expressed in the orthogonal system coordinates prepared above is converted to the spherical coordinate system.

def degree2radians(degree):
    # convert degrees to radians
    return degree*np.pi/180

def mapping_map_to_sphere(lon, lat, radius=1):
    #this function maps the points of coords (lon, lat) to points onto the  
    sphere of radius radius
    
    lon=np.array(lon, dtype=np.float64)
    lat=np.array(lat, dtype=np.float64)
    lon=degree2radians(lon)
    lat=degree2radians(lat)
    xs=radius*np.cos(lon)*np.cos(lat)
    ys=radius*np.sin(lon)*np.cos(lat)
    zs=radius*np.sin(lat)
    return xs, ys, zs

3. Draw with Plotly

Now, let's actually draw the 3D data of latitude, longitude, and altitude represented by the spherical coordinate system in Plotly.

First, call the function prepared in 1-2. To read the global elevation data. If you read at too high a resolution, the amount of data will increase on the order of the cube, so this time the resolution is set to 0.8 °.

# Import topography data
# Select the area you want
resolution = 0.8
lon_area = [-180., 180.]
lat_area = [-90., 90.]

# Get mesh-shape topography data
lon_topo, lat_topo, topo = ReadGeo.Etopo(lon_area, lat_area, resolution)

Next, convert it to the spherical coordinate system with the function prepared in 2.

xs, ys, zs = mapping_map_to_sphere(lon_topo, lat_topo)

And from here, we will actually move on to drawing.

First, define the color scale used to draw the elevation data.

# Import color scale
import Plotly_code as Pcode
name = "topo"
Ctopo = Pcode.Colorscale_Plotly(name)
cmin = -8000
cmax = 8000

Then, draw using Plotly. Here you enter the input data and color scale.

topo_sphere=dict(type='surface',
            x=xs, 
            y=ys, 
            z=zs,
            colorscale=Ctopo,
            surfacecolor=topo,
            cmin=cmin, 
            cmax=cmax)
            )

Erase the shaft etc. so that it looks good.

noaxis=dict(showbackground=False,
            showgrid=False,
            showline=False,
            showticklabels=False,
            ticks='',
            title='',
            zeroline=False)

Finally, use layout to specify the title and background color. This time, the background color is black, with a little awareness of Google Earth.


import plotly.graph_objs as go

titlecolor = 'white'
bgcolor = 'black'

layout = go.Layout(
      autosize=False, width=1200, height=800,
      title = '3D spherical topography map',
      titlefont = dict(family='Courier New', color=titlecolor),
      showlegend = False,
      scene = dict(
        xaxis = noaxis,
        yaxis = noaxis,
        zaxis = noaxis,
        aspectmode='manual',
        aspectratio=go.layout.scene.Aspectratio(
            x=1, y=1, z=1)),
        paper_bgcolor = bgcolor,
        plot_bgcolor = bgcolor)

Then, draw using the prepared one (html output here).

from plotly.offline import plot

plot_data=[topo_sphere]

fig = go.Figure(data=plot_data, layout=layout)
plot(fig, validate = False, filename='3DSphericalTopography.html', 
     auto_open=True)

in conclusion

With this, I think that I could draw a plot of a globe that can be turned like the beginning. I use this by overlaying the distribution of earthquakes on top of this.

This example can be easily applied when plotting on a sphere, and I think it has a wide range of uses. In addition, it is useful not only for elevation data but also for creating a two-dimensional map, and it is also possible to draw three-dimensional images that express the height with elevation data.

Recommended Posts

[Python] Draw elevation data on a sphere with Plotly and draw a globe that can be rotated round and round
[Python] Make a graph that can be moved around with Plotly
Draw a graph that can be moved around with HoloViews and Bokeh
Get data from MySQL on a VPS with Python 3 and SQLAlchemy
I made a shuffle that can be reset (reverted) with Python
Make a currency chart that can be moved around with Plotly (2)
Make a currency chart that can be moved around with Plotly (1)
Understand the probabilities and statistics that can be used for progress management with a python program
A memo with Python2.7 and Python3 on CentOS
Create a web app that can be easily visualized with Plotly Dash
"Manim" that can draw animation of mathematical formulas and graphs with Python
Folium: Visualize data on a map with Python
Format DataFrame data with Pytorch into a form that can be trained with NN
I made a familiar function that can be used in statistics with Python
Article that can be a human resource who understands and masters the mechanism of API (with Python code)
Python knowledge notes that can be used with AtCoder
A server that echoes data POSTed with flask / python
Install Mecab and CaboCha on ubuntu16.04LTS so that it can be used from python3 series
[Python] A program to find the number of apples and oranges that can be harvested
A memo that reads data from dashDB with Python & Spark
Let's make a diagram that can be clicked with IPython
I bought and analyzed the year-end jumbo lottery with Python that can be executed in Colaboratory
I tried using "Asciichart Py" which can draw a beautiful graph on the console with Python.
[Python] A program that finds the maximum number of toys that can be purchased with your money
I made a package that can compare morphological analyzers with Python
Build a 64-bit Python 2.7 environment with TDM-GCC and MinGW-w64 on Windows 7
Make multiple numerical elevation data into a single picture with Python
Build a Python environment on your Mac with Anaconda and PyCharm
Make a Spinbox that can be displayed in Binary with Tkinter
Draw a watercolor illusion with edge detection in Python3 and openCV3
Make a Spinbox that can be displayed in HEX with Tkinter
Python standard module that can be used on the command line
A python script that deletes ._DS_Store and ._ * files created on Mac
A story and its implementation that arbitrary a1 * a2 data can be represented by a 3-layer ReLU neural network with a1 and a2 intermediate neurons with an error of 0.
I wrote a tri-tree that can be used for high-speed dictionary implementation in D language and Python.
Can I be a data scientist?
[Python] Code that can be written with brain death at the beginning when scraping as a beginner
Get a list of camera parameters that can be set with cv2.VideoCapture and make it a dictionary type
EXCEL data bar and color scale can also be done with pandas
I created a template for a Python project that can be used universally
[Python] A program that finds a pair that can be divided by a specified value
Deploy a Python app on Google App Engine and integrate it with GitHub
Mathematical optimization that can be used for free work with Python + PuLP
How to draw a vertical line on a heatmap drawn with Python seaborn
Send and receive binary data via serial communication with python3 (on mac)
Create a Python3 environment with pyenv on Mac and display a NetworkX graph
Make a decision tree from 0 with Python and understand it (4. Data structure)
I made a module PyNanaco that can charge nanaco credit with python
I wanted to quickly create a mail server that can be used freely with postfix + dovecot on EC2
[Python] Creating a tool that can list, select, and execute python files with tkinter & about the part that got caught
[Python] A program that creates stairs with #
Add a Python data source with Redash
Map rent information on a map with python
A typed world that begins with Python
A memo for making a figure that can be posted to a journal with matplotlib
A class for PYTHON that can be operated without being aware of LDAP
I want to create a priority queue that can be updated in Python (2.7)
I registered PyQCheck, a library that can perform QuickCheck with Python, in PyPI.
Moved Raspberry Pi remotely so that it can be LED attached with Python
Build a Python + bottle + MySQL environment with Docker on RaspberryPi3! [Trial and error]
Since python is read as "Pichon", it can be executed with "Pichon" (it is a story)