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
Related
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])
I recently came across a powerpoint slide containing a nice plot which I suspect is made rather with Julia or Python. The person giving the talk didn't give details on how to plot this (maybe he thought I was trying to get his data rather than the actual plot style).
Does anyone know how to produce this type of side colour bar? As you can see from the image attached the colour bar works both as colour bar and legend for the different curves plotted.
Here is some code to create a similar colorbar:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import LinearSegmentedColormap
def burr_pdf(x, c, k):
return c * k * (x ** (c - 1)) / (1 + x ** c) ** (k + 1)
xs = np.linspace(0.0001, 3, 300)
c_k_params = [(1, 1), (1, 2), (1, 3), (2, 1), (3, 1), (0.5, 2)]
curve_labels = [f'c={c}; k={k}' for c, k in c_k_params]
curve_colors = np.linspace(0.98, 0.02, len(c_k_params))
cmap = cm.get_cmap('jet')
special_map_list = [tuple((c+2)/3 for c in cmap(i/256)) for i in range(256)] # "whiten" the colors
for c in curve_colors:
special_map_list[int(c*256)] = cmap(c)
special_map_list[int(c*256)-1] = cmap(c)
special_map = LinearSegmentedColormap.from_list('', special_map_list)
fig, ax = plt.subplots(figsize=(7, 7))
for (c, k), col in zip(c_k_params, curve_colors):
ax.plot(xs, burr_pdf(xs, c, k), color=cmap(col))
ax.set_title('Burr – probability density function')
ax.set_ylim((0, 2))
ax.set_xlim((0, 3))
cbar = plt.colorbar(cm.ScalarMappable(norm=None, cmap=special_map), ax=ax, ticks=curve_colors)
cbar.ax.set_yticklabels(curve_labels)
plt.show()
The curves are from Wikipedia's Burr distribution.
The plot:
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))
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:
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.