I am attempting to plot multiple great circles using a for loop in conjunction with a set of lat/lon points. I am using the animation function with matplotlib to make the plots update when the data source is updated. This is all working well.
I noticed that plotting greatcircles where the shortest distance is wrapping the image, the plot will use that and appear on the other side of the map. Is there an argument that prevents this?
Also, depending on where the plot is I notice the "middle" of the plot arc is missing. What could be causing this? Map and code below:
The CSV uses the following points:(Moscow and Tokyo)
sourcelon sourcelat destlon destlat
55.44 37.51 -80.84 35.22
139 35.6 -80.84 35.22
Minimal code:
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import matplotlib.animation
# setup mercator map projection.
fig = plt.figure(figsize=(27, 20))
m = Basemap(projection='mill', lon_0=0)
m.drawcoastlines(color='r', linewidth=1.0)
def animate(i):
df = pd.read_csv('c:/python/scripts/test2.csv', sep='\s*,\s*',header=0, encoding='ascii', engine='python'); df
for x,y,z,w in zip(df['sourcelon'], df['sourcelat'], df['destlon'], df['destlat']):
line, = m.drawgreatcircle(x,y,z,w,color='r')
ani = matplotlib.animation.FuncAnimation(fig, animate, interval=1000)
plt.tight_layout()
plt.show()
As wikipedia tells us
The great-circle distance or orthodromic distance is the shortest distance between two points on the surface of a sphere, measured along the surface of the sphere.
So the path shown goes the shortest distance, which might wrap from one side of the image to the other.
The missing points in the line are a bit of a mystery, but it might be that there is some problem with the projection in use. Using a different projection, this works fine, e.g. projection='robin':
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,6))
m = Basemap(projection='robin',lon_0=0,resolution='c')
m.drawcoastlines(color='grey', linewidth=1.0)
a = [[55.44, 37.51, -80.84, 35.22],[139, 35.6, -80.84, 35.22]]
x,y,z,w = a[0]
line, = m.drawgreatcircle(x,y,z,w,color='r')
plt.show()
The problem can be circumvented if the distance between points in enlarged, e.g.
line, = m.drawgreatcircle(x,y,z,w,del_s=1000,color='r')
would give
Another workaround would be to get the data from the line and plot it manually,
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,6))
m = Basemap(projection='mill', lon_0=0)
m.drawcoastlines(color='grey', linewidth=1.0)
a = [[55.44, 37.51, -80.84, 35.22],[139, 35.6, -80.84, 35.22]]
x,y,z,w = a[0]
line, = m.drawgreatcircle(x,y,z,w,color='r')
line.remove()
mx,my = line.get_data()
m.plot(mx,my, color="limegreen")
plt.show()
Related
So, what I am having trouble with is how I am supposed to plot the data I have on top of a global map. I have an array of data, and two arrays of coordinates in latitude and longitude, where each datapoint was taken, but I am not sure of how to plot it on top of a global map. Creating the map itself is not too difficult, I just use:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
fig = plt.figure(figsize=(10, 8))
m = Basemap(projection='cyl', resolution='c',
llcrnrlat=-90, urcrnrlat=90,
llcrnrlon=-180, urcrnrlon=180, )
m.shadedrelief(scale=0.5)
m.drawcoastlines(color='black')
But the next step is where I am having problems. I have tried doing both a colormesh plot and scatter plot, but they haven't worked so far. How should I go about it so that the data is plotted in the correct coordinate locations for the global map?
Thanks a lot for any help!
Maybe a bit late, but I have this piece of code I used to plot multiple linear plot over a map in Basemap that worked for me.
map = Basemap(projection='cyl', resolution='c',
llcrnrlat=mins[1], urcrnrlat=maxs[1],
llcrnrlon=mins[0], urcrnrlon=50, )
plt.figure(figsize=(15, 15))
for i in range(1259):
filepath = filename[i]
data = pd.read_csv(filepath, index_col=0)
map.plot(data.x,data.y,'k-', alpha=0.1) ### Calling the plot in a loop!!
map.drawcoastlines(linewidth=1)
map.drawcountries(linewidth=0.5, linestyle='solid', color='k' )
plt.show()
The loop calls data from different folders, and I just use the map.plot command to plot. By doing it like that, you can plot all data in the same map.
I've created a map and I am reading in a CSV of latitude and longitude coordinates into a Pandas DataFrame. I've been successful in plotting multiple great arcs using a 'for' loop after reading in the DataFrame.
I am now trying to animate the multiple great arcs. The reason for the animation is to live update the plot when the CSV is updated. I eventually will use a SQL table for the DataFrame rather than a CSV, but I wanted to get the animation portion working first.
I read and watched multiple tutorials on matplotlib and animation. I've read the source documentation and attempted to apply multiple examples. I've been able to successfully animate a single great arc but can't seem to expand the code to multiple arcs.
Edit1: I want all great circle arcs from the file to be drawn on the map (I've got this part working). When a new set of latitude and longitude is added to the file I want it to update automatically within the same figure. I am trying to use this as a realtime display.
**Edit2: I've paired down the code as much as possible. It is minimal with a basic map, a few long/lat coordinates in a data frame and my attempt to animate the lines. I had to keep a CSV input as it is the only way to verify that the map updates once the CSV is updated.
The CSV contains the following:
sourcelon sourcelat destlon destlat
50.44 30.51 -80.84 35.22
52.52 13.4 -80.84 35.22
43.18 -22.97 -80.84 35.22
35.18 -22.97 -80.84 35.22
The arcs are being drawn, but are not being updated when the CSV is updated.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import matplotlib.animation
# create new figure, axes instances.
fig=plt.figure()
# setup mercator map projection.
plt.figure(figsize=(27, 20))
m = Basemap(projection='mill', lon_0=0)
m.drawcoastlines(color='r', linewidth=1.0)
def animate(i):
df = pd.read_csv('c:/python/scripts/test2.csv', sep='\s*,\s*',header=0, encoding='ascii', engine='python'); df
for x,y,z,w in zip(df['sourcelon'], df['sourcelat'], df['destlon'], df['destlat']):
line, = m.drawgreatcircle(x,y,z,w,color='r')
line, = plt.plot([],[])
ani = matplotlib.animation.FuncAnimation(fig, animate, interval=1000)
plt.tight_layout()
plt.show()
I answered my own question. I am able to get the map to update when I add coordinates to the CSV. However, I cant remove them. I'll work on that as well.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import matplotlib.animation
# setup mercator map projection.
fig = plt.figure(figsize=(27, 20))
m = Basemap(projection='mill', lon_0=0)
m.drawcoastlines(color='r', linewidth=1.0)
def animate(i):
df = pd.read_csv('c:/python/scripts/test2.csv', sep='\s*,\s*',header=0, encoding='ascii', engine='python'); df
for x,y,z,w in zip(df['sourcelon'], df['sourcelat'], df['destlon'], df['destlat']):
line, = m.drawgreatcircle(x,y,z,w,color='r')
ani = matplotlib.animation.FuncAnimation(fig, animate, interval=100)
plt.tight_layout()
plt.show()
I would like to make beautiful scatter plots with histograms above and right of the scatter plot, as it is possible in seaborn with jointplot:
I am looking for suggestions on how to achieve this. In fact I am having some troubles in installing pandas, and also I do not need the entire seaborn module
I encountered the same problem today. Additionally I wanted a CDF for the marginals.
Code:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
x = np.random.beta(2,5,size=int(1e4))
y = np.random.randn(int(1e4))
fig = plt.figure(figsize=(8,8))
gs = gridspec.GridSpec(3, 3)
ax_main = plt.subplot(gs[1:3, :2])
ax_xDist = plt.subplot(gs[0, :2],sharex=ax_main)
ax_yDist = plt.subplot(gs[1:3, 2],sharey=ax_main)
ax_main.scatter(x,y,marker='.')
ax_main.set(xlabel="x data", ylabel="y data")
ax_xDist.hist(x,bins=100,align='mid')
ax_xDist.set(ylabel='count')
ax_xCumDist = ax_xDist.twinx()
ax_xCumDist.hist(x,bins=100,cumulative=True,histtype='step',density=True,color='r',align='mid')
ax_xCumDist.tick_params('y', colors='r')
ax_xCumDist.set_ylabel('cumulative',color='r')
ax_yDist.hist(y,bins=100,orientation='horizontal',align='mid')
ax_yDist.set(xlabel='count')
ax_yCumDist = ax_yDist.twiny()
ax_yCumDist.hist(y,bins=100,cumulative=True,histtype='step',density=True,color='r',align='mid',orientation='horizontal')
ax_yCumDist.tick_params('x', colors='r')
ax_yCumDist.set_xlabel('cumulative',color='r')
plt.show()
Hope it helps the next person searching for scatter-plot with marginal distribution.
Here's an example of how to do it, using gridspec.GridSpec:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as np
x = np.random.rand(50)
y = np.random.rand(50)
fig = plt.figure()
gs = GridSpec(4,4)
ax_joint = fig.add_subplot(gs[1:4,0:3])
ax_marg_x = fig.add_subplot(gs[0,0:3])
ax_marg_y = fig.add_subplot(gs[1:4,3])
ax_joint.scatter(x,y)
ax_marg_x.hist(x)
ax_marg_y.hist(y,orientation="horizontal")
# Turn off tick labels on marginals
plt.setp(ax_marg_x.get_xticklabels(), visible=False)
plt.setp(ax_marg_y.get_yticklabels(), visible=False)
# Set labels on joint
ax_joint.set_xlabel('Joint x label')
ax_joint.set_ylabel('Joint y label')
# Set labels on marginals
ax_marg_y.set_xlabel('Marginal x label')
ax_marg_x.set_ylabel('Marginal y label')
plt.show()
I strongly recommend to flip the right histogram by adding these 3 lines of code to the current best answer before plt.show() :
ax_yDist.invert_xaxis()
ax_yDist.yaxis.tick_right()
ax_yCumDist.invert_xaxis()
The advantage is that any person who is visualizing it can compare easily the two histograms just by moving and rotating clockwise the right histogram on their mind.
On contrast, in the plot of the question and in all other answers, if you want to compare the two histograms, your first reaction is to rotate the right histogram counterclockwise, which leads to wrong conclusions because the y axis gets inverted. Indeed, the right CDF of the current best answer looks decreasing at first sight:
I am at a loss to get the following code to work. For whatever reason, the GeoPandas *.plot() doesn't work, but I want to use both Pandas and GeoPandas for some simple plots.
I have been trying to take the Shapely objects from GeoPandas and plot them on a Basemap. The problem is that the polygons won't plot. I iterate through them from the GeoPandas.geometry, add them to the axes collection, and then use plot() - to no avail. Basemap seems to work fine, the code doesn't give any errors, but the polygons - counties - don't appear...
Thank you for the help!
import geopandas as gpd
from descartes import PolygonPatch
import matplotlib as mpl
import mpl_toolkits.basemap as base
import matplotlib.pyplot as plt
counties_file = r'C:\Users\...\UScounties\UScounties.shp'
counties = gpd.read_file(counties_file)
#new plot
fig = plt.figure(figsize=(5,5),dpi=300)
#ax = fig.add_subplot(111)
ax = ax = plt.gca()
minx, miny, maxx, maxy = counties.total_bounds
#map
m = base.Basemap(llcrnrlon=minx, llcrnrlat=miny,
urcrnrlon=maxx, urcrnrlat=maxy,
resolution='h', area_thresh=100000,
projection='merc')
patches = []
#add polygons
for poly in counties.geometry:
#deal with single polygons and multipolygons
if poly.geom_type == 'Polygon':
p = PolygonPatch(poly, facecolor='blue', alpha=1)
#plt.gca().add_patch(p)
#ax.add_patch(p)
patches.append(p)
elif poly.geom_type == 'MultiPolygon':
for single in poly:
q = PolygonPatch(single,facecolor='red', alpha=1)
#ax.add_patch(p)
patches.append(q)
m.drawcoastlines(linewidth=.1)
m.fillcontinents()
m.drawcountries(linewidth=.25,linestyle='solid')
m.drawstates(linewidth=.25,linestyle='dotted')
m.drawmapboundary(fill_color='white')
ax.add_collection(mpl.collections.PatchCollection(patches, match_original=True))
ax.plot()
plt.show()
Check if your shapefile is in the right projection system. Basemap is currently set to Mercator Projection. After that it worked for me.
I want to plot a graph on a map where the nodes would be defined by coordinates (lat, long) and have some value associated.
I have been able to plot points as a scatterplot on a basemap but can't seem to find how to plot a graph on the map.
Thanks.
EDIT: I have added code on how I plotted the points on a basemap. Most of it has been adapted from code in this article.
from mpl_toolkits.basemap import Basemap
from shapely.geometry import Point, MultiPoint
import pandas as pd
import matplotlib.pyplot as plt
m = Basemap(
projection='merc',
ellps = 'WGS84',
llcrnrlon=-130,
llcrnrlat=25,
urcrnrlon=-60,
urcrnrlat=50,
lat_ts=0,
resolution='i',
suppress_ticks=True)
# Create Point objects in map coordinates from dataframe lon
# and lat values
# I have a dataframe of coordinates
map_points = pd.Series(
[Point(m(mapped_x, mapped_y))
for mapped_x, mapped_y in zip(df['lon'],
df['lat'])])
amre_points = MultiPoint(list(map_points.values))
plt.clf()
fig = plt.figure()
ax = fig.add_subplot(111, axisbg='w', frame_on=False)
fig.set_size_inches(18.5, 10.5)
# Create a scatterplot on the map
dev = m.scatter(
[geom.x for geom in map_points],
[geom.y for geom in map_points],
20, marker='o', lw=.25,
facecolor='#33ccff', edgecolor='w',
alpha=0.9,antialiased=True,
zorder=3)
m.fillcontinents(color='#555555')
I get this image:
Here is one way to do it:
import networkx as nx
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap as Basemap
m = Basemap(
projection='merc',
llcrnrlon=-130,
llcrnrlat=25,
urcrnrlon=-60,
urcrnrlat=50,
lat_ts=0,
resolution='i',
suppress_ticks=True)
# position in decimal lat/lon
lats=[37.96,42.82]
lons=[-121.29,-73.95]
# convert lat and lon to map projection
mx,my=m(lons,lats)
# The NetworkX part
# put map projection coordinates in pos dictionary
G=nx.Graph()
G.add_edge('a','b')
pos={}
pos['a']=(mx[0],my[0])
pos['b']=(mx[1],my[1])
# draw
nx.draw_networkx(G,pos,node_size=200,node_color='blue')
# Now draw the map
m.drawcountries()
m.drawstates()
m.bluemarble()
plt.title('How to get from point a to point b')
plt.show()
As of today there is a nice alternative to basemap. Mplleaflet is a library inspired by mpld3. It plots faster than basemap, is more easy to use and allows to visualizing geographic data on beautiful interactive openstreetmap. The input can be longitude and latitude the library automatically projects the data properly.
Input dictionary pos, where the node (country) is the key and long lat are saved as value.
pos = {u'Afghanistan': [66.00473365578554, 33.83523072784668],
u'Aland': [19.944009818523348, 60.23133494165451],
u'Albania': [20.04983396108883, 41.14244989474517],
u'Algeria': [2.617323009197829, 28.158938494487625],
.....
Plotting is as easy as:
import mplleaflet
fig, ax = plt.subplots()
nx.draw_networkx_nodes(GG,pos=pos,node_size=10,node_color='red',edge_color='k',alpha=.5, with_labels=True)
nx.draw_networkx_edges(GG,pos=pos,edge_color='gray', alpha=.1)
nx.draw_networkx_labels(GG,pos, label_pos =10.3)
mplleaflet.display(fig=ax.figure)