I have searched stackoverflow to find an answer to my issue, but to no avail. I wish to plot an earthquake data set with a yellow star to represent the center of my study area. However, I can only plot the earthquake data and cannot plot the star. I have tried two solutions: just plotting both data sets such as what I have in my code, or using a subplot.
In other words, what is the equivalent of MatLab's hold on command in Python/matplotlib?
#!/usr/bin/env python
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
# Read in latitudes and longitudes
eq_data = open('eq_data')
lats, lons = [], []
mag = []
for index, line in enumerate(eq_data.readlines()):
if index > 0:
lats.append(float(line.split(',')[0]))
lons.append(float(line.split(',')[1]))
mag.append(float(line.split(',')[2]))
#Build the basemap
antmap = Basemap(projection='spstere', boundinglat=10, lon_0=-60, resolution='f')
antmap.drawcoastlines(color='black', linewidth=0.15)
antmap.fillcontinents(color='0.95')
antmap.drawmapboundary(fill_color='aqua')
x,y = antmap(lons, lats)
x1,x2= (0,-90)
antmap.plot(x1,x2, 'r*', markersize=10)
antmap.plot(x,y,'ro', markersize=8)
plt.show()
Related
I am trying to display elevation/topography in 3D on a geographical map
I am currently displaying elevation with a colormap using the scatter function of matplolib over a geographical map created with the basemap package. I would like to visualize it in 3D with a shady effect or something similar.
Bellow is a simple example using data created randomly. The only constrain is to keep the 'ortho' look shown bellow. Any python package could be used.
Input data could either be a 1D arrays or 2D arrays.
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
size = 1000
# data to plot
data = np.arange(size)*0.5/size
# coordinates
lat = np.random.uniform(low=65, high=90, size=(size,))
lon = np.random.uniform(low=-180, high=180, size=(size,))
f1, ax = plt.subplots(1, 1,figsize=(9,8))
m = Basemap(projection='ortho',lat_0=70,lon_0=0,resolution='l',ax=ax)
m.drawcoastlines(linewidth=0.25, zorder=0)
m.drawparallels(np.arange(90,-90,-5), labels=[1,1,1,1],linewidth = 0.25, zorder=1)
m.drawmeridians(np.arange(-180.,180.,30.),labels=[1,1,1,1],latmax=85, linewidth = 0.25, zorder=1)
m.fillcontinents(color='dimgray',lake_color='grey', zorder=1)
x,y = m(lon,lat)
cmap='viridis'
m.scatter(x,y,c=data,s=10,cmap=cmap,vmin=0,vmax=0.5,zorder=3,alpha=1)
plt.show()
Thanks a lot,
I am trying to make a map in basemap using pcolormesh (and I'm open to other methods). I have a csv file with coordinates, and one with the corresponding density value. (Should they be in one file?) I am trying to load the values as a numpy array and then plot the map, but I am unsure as how to correspond the density to the point. My map is currently just displaying blue everywhere, so I think it is just counting each coordinate and displaying it. NOTE: In the example code below, I created a CSV that has the coordinates and the density, for ease of testing.
Ideally, I have a range of values in density and the lower will be blue and the higher will be red. I am just very confused by how to put the density in there.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
m = Basemap(projection='npstere',boundinglat=60,lon_0=270,resolution='l')
m.drawcoastlines()
m.drawcounties()
array = np.genfromtxt("fake.csv", delimiter=",", skip_header=1)
lats = array[0,:]
lons = array[1,:]
nx = 360
ny = 180
lon_bins = np.linspace(-180, 180, nx)
lat_bins = np.linspace(70, 90, ny)
density, lat_edges, lon_edges = np.histogram2d(lats, lons, [lat_bins, lon_bins])
lon_bins_2d, lat_bins_2d = np.meshgrid(lon_bins, lat_bins)
xs, ys = m(lon_bins_2d, lat_bins_2d)
density = np.hstack((density, np.zeros((density.shape[0], 1))))
density = np.vstack((density, np.zeros((density.shape[1]))))
plt.pcolormesh(xs, ys, density, cmap="jet", shading='gouraud')
plt.show()
Admittedly, some of this code is patched together from googling for help, and this currently produces my desired map but, instead of displaying density, it's just a big blue blob. How do I get the density value to correspond to each coordinate? Thanks!
I'm trying to plot data that contains lat, lon, and altitude as a 3d scatter plot in mpl. What I've found for documentation so far is either how to plot 2d geographic data using Basemap, OR how to plot 3d data using Axes3D, but not both. The specific coding issue I'm running into is how to set my lat/lon data to be interpreted as geographic lat and lon, but to keep my alt data as... well, altitude. I know Basemap contains the latlon setting:
"If latlon keyword is set to True, x,y are intrepreted as longitude
and latitude in degrees. Data and longitudes are automatically shifted
to match map projection region for cylindrical and pseudocylindrical
projections, and x,y are transformed to map projection coordinates."
However if I'm plotting in 3d, Axes3D doesn't support the latlon argument. The reason having geographic coordinates is so important is that I'm plotting the data over a basemap for visual reference.
My code:
import os
os.environ['PROJ_LIB'] = r'E:\Programs\Anaconda3\pkgs\proj4-5.2.0-ha925a31_1\Library\share'
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.basemap import Basemap
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.gca(projection='3d')
# Define lower left, uperright lontitude and lattitude respectively
extent = [-180, 180, -90, 90]
# Create a basemap instance that draws the Earth layer
#bm = Basemap(llcrnrlon=extent[0], llcrnrlat=extent[2],
# urcrnrlon=extent[1], urcrnrlat=extent[3],
# projection='cyl', resolution='l', fix_aspect=False, ax=ax)
bm = Basemap(llcrnrlon=-73,llcrnrlat=41,urcrnrlon=-69.5,urcrnrlat=43.5,projection='lcc', resolution='i', lat_0=42, lon_0=-71, ax=ax, fix_aspect=True)
# Add Basemap to the figure
ax.add_collection3d(bm.drawcoastlines(linewidth=0.35))
ax.add_collection3d(bm.drawstates(linewidth=0.25))
#ax.add_collection3d(bm.drawcounties(linewidth=0.15))
#ax.set_axis_off()
ax.view_init(azim=230, elev=50)
ax.set_xlabel('Longitude (°E)', labelpad=20)
ax.set_ylabel('Latitude (°N)', labelpad=20)
ax.set_zlabel('Altitude (ft)', labelpad=20)
# Add meridian and parallel gridlines
#lon_step = 5
#lat_step = 5
#meridians = np.arange(extent[0], extent[1] + lon_step, lon_step)
#parallels = np.arange(extent[2], extent[3] + lat_step, lat_step)
#ax.set_yticks(parallels)
#ax.set_yticklabels(parallels)
#ax.set_xticks(meridians)
#ax.set_xticklabels(meridians)
ax.set_zlim(0., 50000.)
#ax.set_xlim(-69., -73.)
#ax.set_ylim(40.,44.)
# empty array for place holder
lons = np.array([]) # longtitude
lats = np.array([]) # latitude
alt = np.array([]) # altitude
# Make sure your working directory is the directory contains this script and the data file.
#directory = os.fsencode('.')
# Import data to illustrate
lons, lats, alt = np.loadtxt('adsb-csv-2019-07-07_xzyonly_small.csv', delimiter=',', unpack=True, skiprows=1)
#alons, alats = map(lons, lats, latlon=True)
# scatter map based on lons, lats, alts
p = ax.scatter(lons, lats, alt, c=alt, cmap='jet')
# Add a colorbar to reference the intensity
#fig.colorbar(p, label='Aircraft Altitude')
plt.show()
This was adapted from code written by Phúc Lê.
Any help would be much appreciated!
I have a dataframe with locations given as longitude and latitude coordinates (in degrees). Those locations are around New York. Therefore I setup a Basemap in Python that nicely shows all those locations. Works fine!
But: the map is drawn inline and it's very tiny. How can I force that figure to be let's say 3 times larger (zoom=3).
Here's the code. The data is from the Kaggle Two Sigma Rental Listing challenge.
%matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
# New York Central Park
# Longitude: -73.968285
# Latitude: 40.785091
m = Basemap(projection='merc',llcrnrlat=40,urcrnrlat=42,\
llcrnrlon=-75, urcrnrlon=-72, resolution='i', area_thresh=50, lat_0=40.78, lon_0=-73.96)
m.drawmapboundary()
m.drawcoastlines(color='black', linewidth=0.4)
m.drawrivers(color='blue')
m.fillcontinents(color='lightgray')
lons = df['longitude'].values
lats = df['latitude'].values
x,y = m(lons, lats)
# r = red; o = circle marker (see: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot)
m.plot(x, y, 'ro', markersize=4)
plt.show()
normally it would be as simple as:
plt.figure(figsize=(20,10))
How do you change the size of figures drawn with matplotlib?
but there are some other options too, see:
How to maximize a plt.show() window using Python
also to get the current size (for the purpose of "zoom")
How to get matplotlib figure size
regarding the specific issue:
the figure is inline inside a Jupyter notebook
before creating or plotting the map/figure:
import matplotlib
matplotlib.rcParams['figure.figsize'] = (30,30)
I am trying to use streamplot function to plot wind field with basemap, projection "ortho". My test code is mainly based on this example:
Plotting wind vectors and wind barbs
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
import datetime
from mpl_toolkits.basemap import Basemap, shiftgrid
from Scientific.IO.NetCDF import NetCDFFile as Dataset
# specify date to plot.
yyyy=1993; mm=03; dd=14; hh=00
date = datetime.datetime(yyyy,mm,dd,hh)
# set OpenDAP server URL.
URLbase="http://nomads.ncdc.noaa.gov/thredds/dodsC/modeldata/cmd_pgbh/"
URL=URLbase+"%04i/%04i%02i/%04i%02i%02i/pgbh00.gdas.%04i%02i%02i%02i.grb2" %\
(yyyy,yyyy,mm,yyyy,mm,dd,yyyy,mm,dd,hh)
data = Dataset(URL)
#data = netcdf.netcdf_file(URL)
# read lats,lons
# reverse latitudes so they go from south to north.
latitudes = data.variables['lat'][:][::-1]
longitudes = data.variables['lon'][:].tolist()
# get wind data
uin = data.variables['U-component_of_wind_height_above_ground'][:].squeeze()
vin = data.variables['V-component_of_wind_height_above_ground'][:].squeeze()
# add cyclic points manually (could use addcyclic function)
u = np.zeros((uin.shape[0],uin.shape[1]+1),np.float64)
u[:,0:-1] = uin[::-1]; u[:,-1] = uin[::-1,0]
v = np.zeros((vin.shape[0],vin.shape[1]+1),np.float64)
v[:,0:-1] = vin[::-1]; v[:,-1] = vin[::-1,0]
longitudes.append(360.); longitudes = np.array(longitudes)
# make 2-d grid of lons, lats
lons, lats = np.meshgrid(longitudes,latitudes)
# make orthographic basemap.
m = Basemap(resolution='c',projection='ortho',lat_0=60.,lon_0=-60.)
# create figure, add axes
fig1 = plt.figure(figsize=(8,10))
ax = fig1.add_axes([0.1,0.1,0.8,0.8])
# define parallels and meridians to draw.
parallels = np.arange(-80.,90,20.)
meridians = np.arange(0.,360.,20.)
# first, shift grid so it goes from -180 to 180 (instead of 0 to 360
# in longitude). Otherwise, interpolation is messed up.
ugrid,newlons = shiftgrid(180.,u,longitudes,start=False)
vgrid,newlons = shiftgrid(180.,v,longitudes,start=False)
# now plot.
lonn, latt = np.meshgrid(newlons, latitudes)
x, y = m(lonn, latt)
st = plt.streamplot(x, y, ugrid, vgrid, color='r', latlon='True')
# draw coastlines, parallels, meridians.
m.drawcoastlines(linewidth=1.5)
m.drawparallels(parallels)
m.drawmeridians(meridians)
# set plot title
ax.set_title('SLP and Wind Vectors '+str(date))
plt.show()
After running the code, I got a blank map with a red smear in the lower left corner (please see the figure). After zoom this smear out, I can see the wind stream in a flat projection (not in "ortho" projection) So I guess this is the problem of data projection on the map. I did tried function transform_vector but it does not solve the problem Can anybody tell me, what did I do wrong, please! Thank you.
A new map after updating code:
You are plotting lat/lon coordinates on a map with an orthographic projection. Normally you can fix this by changing your plotting command to:
m.streamplot(mapx, mapy, ugrid, vgrid, color='r', latlon=True)
But your coordinate arrays don't have the same dimensions, that needs to be fixed as well.