Quiver plot arrows using Matplotlib - python

I am trying to make a quiver plot using the list I4. In I4[0], (0,0) and (1,0) represent the starting position and the direction of the arrow respectively. However, the current output doesn't match the expected one. I attach both here.
import matplotlib.pyplot as plt
I4 = [[(0, 0), (1, 0)], [(0, 0), (0, -1)], [(1, 0), (1, -1)], [(0, -1), (1, -1)]]
fig, ax = plt.subplots(figsize = (10,10))
for i in range(0,len(I4)):
ax.quiver(I4[i][0], I4[i][1])
plt.show()
The current output is
The expected output is

Alternatively, you could use plt.arrow (doc here):
import matplotlib.pyplot as plt
I4 = [(0, 0),(1, 1),(0, 1), (0, 1)]
dI4=[(1,0),(0,-1),(1,0),(0,-1)]
texts=['(0,-1)','(1,-1)','(1,0)','(0,0)']
textxy=[(0,0),(1,0),(1,1),(0,1)]
fig, ax = plt.subplots(figsize = (10,10))
for i in range(len(I4)):
ax.arrow(I4[i][0], I4[i][1],dI4[i][0],dI4[i][1],length_includes_head=True,head_width=0.05,color='k',lw=3)
if i<2:
dy=-0.1
else:
dy=0.1
plt.text(textxy[i][0], textxy[i][1]+dy,texts[i],fontsize=20)
ax.set_aspect('equal')
ax.set_xlim([-0.5,1.5])
ax.set_ylim([-0.5,1.5])
plt.axis('off')
plt.show()
And the output gives:

Please, take a look at the documentation with help(ax.quiver): you'll see that you need to specify ax.quiver(x, y, u, v) where x, y are the starting coordinates, u, v represents the directions.
In practice, you need to unpack your lists, like this:
ax.quiver(*I4[i][0], *I4[i][1])

Related

Wrong result trying to plot a spider-web graph in matplotlib

I am practicing how to use the matplotlib and pyplot library, and for that very reason I'm trying to make a function that plots points so that any two points have a line that
connects them.
I think I'm close to solving the problem, but the result still seems a bit off.
My code is:
import numpy as np
import matplotlib.pyplot as plt
alpha = (np.sqrt(2)/2)
square_points = ((0, 0),(1, 0),(0, 1),(1, 1))
shape_points = ((1, 0),(alpha, alpha),(0, 1),(-alpha, alpha),(-1, 0),(-alpha, -alpha),(0, -1),(alpha, -alpha))
def complete_graph(points):
for i in range(len(points)):
for j in range(i):
x = (points[i])
y = (points[j])
plt.plot(x, y)
plt.show()
complete_graph(square_points) #square shape
complete_graph(shape_points) #spider web ish shape
The result is supposed to look like this:
Square shape
Spider web shape
My result however is:
For what is supposed to be a square shape:
For what is supposed to be a spiderweb-ish shape
You need to have the x and y coordinates separately. The simplest would be x=[points[i][0], points[j][0]] and y=[points[i][1], points[j][1]].
Using numpy, the code could be written creating all x. The vertices can be drawn using plt.scatter(). Setting the z-order to 3 shows them in front of the edges.
import numpy as np
import matplotlib.pyplot as plt
alpha = np.sqrt(2) / 2
square_points = ((0, 0), (1, 0), (0, 1), (1, 1))
shape_points = ((1, 0), (alpha, alpha), (0, 1), (-alpha, alpha), (-1, 0), (-alpha, -alpha), (0, -1), (alpha, -alpha))
def complete_graph(points):
# calculate and plot the edges
edges = np.array([(points[i], points[j]) for i in range(len(points)) for j in range(i)]).reshape(-1, 2)
plt.plot(edges[:, 0], edges[:, 1], color='dodgerblue')
points = np.array(points)
# plot the vertices
plt.scatter(points[:, 0], points[:, 1], color='mediumvioletred', s=100, zorder=3)
plt.axis('equal') # show squares as squares (x and y with the same distances)
plt.axis('off') # hide the surrounding rectangle and ticks
plt.show()
complete_graph(square_points) # square shape
complete_graph(shape_points) # spider web ish shape

I want to plot perpendicular vectors in Python

I would like to simply plot perpendicular vectors in 2D. I've implemented 2 ways to plot them in the code below but the vectors don't "look" perpendicular to me when the plots are drawn. If it makes any difference I'm using Spyder.
import numpy as np
import matplotlib.pyplot as plt
x1=[0,0,4,3]
x2=[0,0,-3,4]
x3=[0,0,3,-4]
soa =np.array([x1,x2,x3])
X,Y,U,V = zip(*soa)
plt.figure()
ax = plt.gca()
ax.quiver(X,Y,U,V,angles='xy',scale_units='xy',scale=1)
ax.set_xlim([-10,10])
ax.set_ylim([-10,10])
plt.draw()
plt.show()
import pylab as pl
from matplotlib import collections as mc
lines = [[(0, 1), (4, 3)], [(-3, 4), (3, -4)]]
c = np.array([(1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)])
lc = mc.LineCollection(lines, colors=c, linewidths=2)
fig, ax = pl.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.1)
Your problem is that the size of the unit differs on the x and y axes. You need to force them to be equal.
In matplotlib.pyplot, add the line
plt.axes().set_aspect('equal')
just before you show the graph with
plt.show()
I get this result in the IPython console in Spyder:
In pylab, add the line
ax.set_aspect('equal')
at the end. However, these line segments still do not look perpendicular, and that is because they really are not perpendicular. The slope of your first, red line segment is 2/3, so your second, green line segment should have slope -3/2 but it actually has slope -4/3. Perhaps change your line to
lines = [[(0, 1), (4, 3)], [(-3, 4), (3, -5)]]
(I changed the ending -4 to -5) to get the correct second slope. You get a change from this first figure to the second:
and that last does look perpendicular.
The problem is the aspect ratio of the figure canvas.
Use:
plt.figure(figsize=(6,6))

Plotting Shapefiles which color decided by the scatter point data within

My question
Plotting heatmap with shapefile
1.intro
a bunch of shapefile represent the administration boundaries
a pandas.Dataframe containing some point with (longitude,latitude,value)
Code here:
map = Basemap(llcrnrlon=xc1,llcrnrlat=yc1,urcrnrlon=xc2,urcrnrlat=yc2)
##Assuming "shape.shp" is my shapefile
map.readshapefile('./shape','shape',zorder =1,)
patches=[]
cs=plt.cm.Greens(np.arange(18)/18.)
for info, shape in zip(map.shape_info, map.shape):
x,y=zip(*shape)
patches.append( Polygon(np.array(shape), True) ) # facecolor= '#6582B3'
ax.add_collection(PatchCollection(patches, facecolor= cs,edgecolor='none',
linewidths=1.5, zorder=2))
## scatter the point, assuming "pt" is the Dataframe
pt_lat = pt.lat.as_matrix()
pt_lon = power.lon.as_matrix()
plt.scatter(pt_lon,pt_lat,marker='o',s=50,lw= 0,zorder = 3, alpha = 0.75)
Picture here:
http://i11.tietuku.com/9785abb6097b7c0e.png
2. My target
In the picture upward, the color of each shapefile is based on the colormap predefined.
Plotting Each area (In my case, 18 shapefile) with the color corresponding to the sum of pt.values within.
In other words, the inner point data decide the shapefile's color
Add --2015-01-11
Thanks for #MaxNoe's answer.
I have learned from your code, but still has some problem.
Here is my code & picture:
fig = plt.figure(figsize =(8,6))
ax = plt.subplot()
map = Basemap(llcrnrlon=xc1,llcrnrlat=yc1,urcrnrlon=xc2,urcrnrlat=yc2)
map.readshapefile('./shape','shape')
patches=[]
for info, shape in zip(map.shape_info, map.shape):
x,y=zip(*shape)
patches.append(Polygon(np.array(shape), True) )
xx = pt.lon.iloc[:].as_matrix()
yy = pt.lat.iloc[:].as_matrix()
value = pt.value.iloc[:].as_matrix()
sh = (len(xx),2)
position = np.zeros(len(xx)*2).reshape(*sh)
for i in range(0,len(xx),1):
position[i] = np.array([xx[i],yy[i]])
poly_values = []
for patch in patches:
mask = np.array([patch.contains_point(xy) for xy in position])
poly_values.append(value[mask].sum())
coll = PatchCollection(patches, cmap = 'Greens')
coll.set_array(np.array(poly_values))
ax.add_collection(coll)
plt.colorbar(coll,label = "polygon")
point_plot = plt.scatter(xx,yy,marker='o',s=80,lw= 0,zorder = 3, c = "r",alpha = 0.75)
ax.set_frame_on(False)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="4%", pad=0.1)
cbar = plt.colorbar(coll,label = "polygon",cax= cax)
http://i4.tietuku.com/9a7b0cbc16f2e0b0.png
It seems like the color for polygon[i] isn't according to the poly_value[i]
I think the problem is coll.set_array doesn't work.
Otherwise, I have checked each polygon and the scatter point value within, the poly_value[i] and the actual condition is not match(bigger than reality). I think the I may use value.mask wrong.
You can use Polygon.contains_point to check if a point is inside it.
I use this function to create a boolean mask to address the points which are inside that poly and use .sum() to get the value for this polygon.
Then I use PatchCollection.set_array to set the values.
Here is the code (without basemap as I do not have the shape file):
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
# some random numbers for demonstration
data = np.random.normal(0, 1, (100, 2))
value = np.random.normal(0, 1, 100)
polygons = [
Polygon([(0, 0), (0, 3), (-3, 3), (-3, 0)], closed=True),
Polygon([(0, 0), (0, -3), (-3, -3), (-3, 0)], closed=True),
Polygon([(0, 0), (0, 3), (3, 3), (3, 0)], closed=True),
Polygon([(0, 0), (0, -3), (3, -3), (3, 0)], closed=True),
]
poly_values = []
for poly in polygons:
mask = np.array([poly.contains_point(xy) for xy in data])
poly_values.append(value[mask].sum())
coll = PatchCollection(polygons, cmap='magma')
coll.set_array(np.array(poly_values))
fig, ax = plt.subplots()
ax.add_collection(coll)
points = ax.scatter(data[:, 0], data[:, 1], c=value, cmap='viridis', linewidth=0)
fig.colorbar(coll, label='polygons')
fig.colorbar(points, label='points')
plt.show()
Result:

Python annotation arrows with same headlength

I'm using matplotlib to create annotations with arrows.
from matplotlib import pyplot as plt
plt.figure()
plt.annotate('Text1', xy=(1, 0), xytext=(1, 1), arrowprops=dict(alpha=0.5, fc='r', ec='r', headwidth=10))
plt.annotate('Text2', xy=(3, 0), xytext=(3, 3), arrowprops=dict(alpha=0.5, fc='r', ec='r', headwidth=10))
plt.annotate('Text3', xy=(6, 0), xytext=(6, 6), arrowprops=dict(alpha=0.5, fc='r', ec='r', headwidth=10))
plt.annotate('Text4', xy=(9, 0), xytext=(9, 9), arrowprops=dict(alpha=0.5, fc='r', ec='r', headwidth=10))
plt.xlim((0, 10))
plt.ylim(0, 10)
plt.show()
As can be seen, the length of the arrow heads is affected by the line-length and varies between the arrows.
I'm looking for a way to create arrows with different line-lengths but equal arrow-headlengths.
Although many options are listed on the annotations manual page, i was not able to produce the desired result.
As an alternative approach i tried to plot the arrows seperatedely using plt.arrow. In that case the arrow heads looked as desired, but when using transparency, additional lines became visible.
Best regards, zinjaai
In the arrowprops you can't specify the length of the head, but the frac arguement specifies the length of the head as a fraction the arrow length. Since you know xy and xytext you can compute the necessary fraction for a desired headlength.
I've don't it quickly for the example you provided (with an head length of 0.5).
from matplotlib import pyplot as plt
plt.figure()
plt.annotate('Text1', xy=(1, 0), xytext=(1, 1),
arrowprops=dict(alpha=0.5, fc='r', ec='r', headwidth=10, frac=0.5/1))
plt.annotate('Text2', xy=(3, 0), xytext=(3, 3),
arrowprops=dict(alpha=0.5, fc='r', ec='r', headwidth=10, frac=0.5/3))
plt.annotate('Text3', xy=(6, 0), xytext=(6, 6),
arrowprops=dict(alpha=0.5, fc='r', ec='r', headwidth=10, frac=0.5/6))
plt.annotate('Text4', xy=(9, 0), xytext=(9, 9),
arrowprops=dict(alpha=0.5, fc='r', ec='r', headwidth=10, frac=0.5/9))
plt.xlim((0, 10))
plt.ylim(0, 10)
plt.show()
Result:
You could wrap this in a function, which computes the length of the arrow (given xy and xytext) and then passes that on to plt.annotate.

Plot counter of data points in matlpotlib

I have a matplotlib scatter plot like following.
import matplotlib.pyplot as plt
from pylab import plot,axis,show,pcolor,colorbar,bone
axiss = [(0, 0), (0, 1), (0, 0), (2, 2), (0, 2), (2, 2), (2, 0), (0, 2), (1, 2), (2, 0)]
x,y = zip(*axiss)
labels = ['u1', 'u2', 'u3', 'u4',
'u5', 'u6', 'u7', 'u8',
'u9', 'u10']
fig, ax = plt.subplots()
ax.scatter(x, y)
for i, txt in enumerate(labels):
ax.annotate(txt, (x[i],y[i]))
show()
Instead of labels I want to show how many data points are scattered on one point. For example in the data point I have marked in red, It should show '2'. And in the mouse hover event I need to see the labels. So in the example it should be 'u7' and 'u10'. Is it possible with matplotlib?
It got a little long, but I would first collect the unique element in axiss using set and count the number of each unique element. Then include that data into scatter's third argument, the size of the points. I would also annotate each points according the the number of datasets in that point.
Now the interactive annotation is a tricky part. I could not find mouse-hover event catcher, but you can do pretty much the same thing for mouse-clicking event. Save the first script on this page http://wiki.scipy.org/Cookbook/Matplotlib/Interactive_Plotting as interactive_annotations.py and import it in the script.
import matplotlib.pyplot as plt
from pylab import plot,axis,show,pcolor,colorbar,bone
import numpy as np
axiss = [(0, 0), (0, 1), (0, 0), (2, 2), (0, 2), (2, 2), (2, 0), (0, 2), (1, 2), (2, 0)]
# get unique elements
axiss_unique = list(set(axiss))
# get number of data at each datapoint
axiss_count = [axiss.count(x) for x in axiss_unique]
sc = 100 # scale up the datapoints for scatter
labels = [] # label each point according to number of data there
annotates = [] # intereactively label each point according to the datapoint name
for i in range(len(axiss_count)):
labels.append('%i'%axiss_count[i])
annotates.append( ' '.join(['u'+str(k) for k, j in enumerate(axiss) if j == axiss_unique[i]]))
axiss_count[i] *= sc
x,y = zip(*axiss_unique)
fig, ax = plt.subplots()
# get offsets of the labels to each point
x_os, y_os = max(x)/20., max(y)/20.
ax.scatter(x, y, axiss_count)
for i, txt in enumerate(labels):
ax.annotate(txt, (x[i]+x_os,y[i]+y_os), fontsize=15)
# interactive annotation
import interactive_annotations
af = interactive_annotations.AnnoteFinder(x,y, annotates)
connect('button_press_event', af)
show()
Result is something like this.
You can edit interactive_annotations.py to change the offset of the annotations, fonts, etc.

Categories

Resources