Why aren't there lines between data points in Contourf plot? - python

I plotted a contourf plot with 9x11 points. When I plot the contourf plot then I expect to see lines between data points (since there is no other data in between the data points). But for example in the 0.9 level there are some parts (especially between x=2 and x=4) which are not linear. What can be the reason for that?
plt.figure()
x=np.linspace(0,10,11)
y=np.linspace(0,10,11)
X,Y = np.meshgrid(x,y)
levels = np.arange(0,1.01,0.1)
norm = cm.colors.Normalize(vmax=1, vmin=0)
cmap = cm.PRGn
CS1 = plt.contourf(X, Y, data,levels=levels,cmap=cm.get_cmap(cmap,
len(levels) - 1),norm=norm)
plt.xticks(np.arange(11),np.arange(11))
plt.yticks(np.arange(11),np.arange(250,855,55))
plt.xlim([0,8])
plt.colorbar(CS1)
plt.grid()
plt.show()

It's supposed to be that way: contourf colours in the area between the lines and contour draws the lines. See the examples.

Maybe the following plot helps to understand a contour plot better.
Here we plot a contour of an array with 3x3 points. The value of the middle point (6) is much larger than the other values. We chose levels of 3 and 5 where to plot the contour lines. Those lines are calculated by the contour as to interpolate the data.
Using more points will then allow to use more lines and make them look more smooth.
import matplotlib.pyplot as plt
import numpy as np
X,Y = np.meshgrid(np.arange(3), np.arange(3))
Z = np.array([[1,1,1],[2,6,2],[1,1,1]])
fig, ax=plt.subplots()
cs = ax.contour(X,Y,Z, levels=[3,5])
cs2 = ax.contourf(X,Y,Z, levels=[1,3,5,6], alpha=0.3)
plt.clabel(cs, cs.levels, inline=False)
plt.colorbar(cs2)
ax.scatter(X,Y)
for x,y,z in zip(X.flatten(), Y.flatten(), Z.flatten()):
ax.text(x,y,z)
plt.show()

Related

Python plt.colorbar() what does it do and what does the numbers on colorbar signifies?

Can someone explain to me what and how colorbar is used? I dont get the significance of colorbar and the number is it shows? What does the number on colorbar means? Please explain to me...
Data is from datacamp: Two columns with percentage of students taking biology and business from year 1970 to 2010. Below code makes a 2dhist but I dont understand what colorbar labels signifies? is it percentage??
plt.hist2d(data['Biology'], data['Business'], bins=(5,5))
plt.colorbar()
plt.show()
You have not uploaded your data so I am going to post a toy example and explain some things.
from matplotlib.colors import LogNorm
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
# normal distribution center at x=0 and y=5
x = np.random.randn(100000)
y = np.random.randn(100000) + 5
plt.hist2d(x, y, bins=40, norm=LogNorm())
plt.xlabel('x')
plt.ylabel('y')
cbar = plt.colorbar()
cbar.ax.set_ylabel('Counts')
plt.show()
Here, I have created 2 variables. The x has mean=0 and the y has mean=5.
When you plot the 2D hist, you see a 2D histogram. Think about it like looking at a histogram from the "top".
print(x.mean())
print(y.mean())
#0.0015767005081253399
#5.005093241323296
Now, you can see that the colors at the center of this 2D histogram are yellowish and correspond to the highest values of the colorbar.
This is reasonable since the histogram of x should have a peak at 0 and the histogram of y should have a peak at 5.
You plot their positions on the x-y plane and as you can see they are so dense and overlap with each other. You want to view the distribution better by count of boxes in the plane, so you try a 2D diagram.
This is exactly what the colors and the colorbar's values mean. It's the height/frequency/counts of each bin if you had a 1D classical histogram.
EDIT 1: By using fewer bins it's like zooming in the initial plot.
from matplotlib.colors import LogNorm
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(0)
# normal distribution center at x=0 and y=5
x = np.random.randn(100000)
y = np.random.randn(100000) + 5
plt.hist2d(x, y, bins=(5,5), norm=LogNorm())
plt.xlabel('x')
plt.ylabel('y')
cbar = plt.colorbar()
cbar.ax.set_ylabel('Counts')
plt.show()

Add a label to y-axis to show the value of y for a horizontal line in matplotlib

How can I add a string label to the horizontal red line showed in the following plot? I want to add something like "k=305" to the y-axis label next to the line. The blue dots are just some other data and the values do not matter. For recreation of this problem, you can plot any kind of data. My question is about the red line.
plt.plot((0,502),(305,305),'r-')
plt.title("ALS+REG")
A horizontal line can be drawn using Axes.axhline(y).
Adding a label would be done by using Axes.text(). THe tricky bit is to decide upon the coordinates at which to place that text. Since the y coordinate should be the data coordinate at which the line is drawn, but the x coordinate of the label should be the independent of the data (e.g. allow for differen axis scales), we can use a blended transform, where the x transform is the transform of the axis ylabels, and the y transform is the data coordinate system.
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
import numpy as np; np.random.seed(42)
N = 120
x = np.random.rand(N)
y = np.abs(np.random.normal(size=N))*1000
mean= np.mean(y)
fig, ax=plt.subplots()
ax.plot(x,y, ls="", marker="o", markersize=2)
ax.axhline(y=mean, color="red")
trans = transforms.blended_transform_factory(
ax.get_yticklabels()[0].get_transform(), ax.transData)
ax.text(0,mean, "{:.0f}".format(mean), color="red", transform=trans,
ha="right", va="center")
plt.show()

Add image behind scatter subplot independent of scatter points axes

I am trying to add an image behind each subplot of my scatter plot figure. I want my image to take up all the subplot space. But I do not want to map my scatter points onto the image: That is, I want the axes of my scatter points to be independent to that of the image.
When I simply use imread() and implot() while making a subplot to insert the image, like so:
im = plt.imread("/Users/mac/Desktop/image.jpeg")
two = plt.subplot(222)
implot = plt.imshow(im)
plt.title('4-8 Hz')
plt.scatter(X,Y, s=100, marker ='o', c=AveragedHursts4to8, cmap = cm.plasma)
plt.colorbar()
two.axis('off')
I get the right-most image down below, where, clearly, the image axes and scatter points axes are shared.
I tried to use the twiny() function to make a new set of axes for the image, with the image set as the first axes and the second axes set to the scatter points, like so:
onetwin = plt.subplot(221)
plt.title('1-4 Hz')
implot = plt.imshow(im, zorder=1)
onetwin.axis('off')
one = onetwin.twiny()
plt.scatter(X,Y, s=100, marker ='o', c=AveragedHursts1to4, cmap = cm.plasma, zorder = 2)
plt.colorbar()
one.axis('off')
There I get the leftmost image, where the scatter points are squished on the y axis and the image, for some reason, has been shrunk.
And when I switch the ordering of the creation of the axes for twiny, the image takes up the whole subplot and the scatter points do not show at all.
Suggestions?
My suggestion would be to leave the points' positions untouched and scale the background image accordingly. One can use the extent keyword to imshow for that purpose.
In the example below I plot some random points on four different scales. Each time the image is scaled to the scatterplot's dimensions using the extent keyword.
import matplotlib.pyplot as plt
import numpy as np
x = np.random.rand(8*8).reshape((8,8))
image = plt.imread("https://upload.wikimedia.org/wikipedia/en/2/27/EU_flag_square.PNG")
fig, ax = plt.subplots(ncols=4, figsize=(11,3.8))
for i in range(len(ax)):
ax[i].scatter(x[2*i,:]*10**(i-1), x[2*i+1,:]*10**(i-1), c="#ffcc00", marker="*", s=280, edgecolors='none')
xlim = ax[i].get_xlim()
ylim = ax[i].get_ylim()
mini = min(xlim[0],ylim[0])
maxi = max(xlim[1],ylim[1])
ax[i].imshow(image, extent=[mini, maxi, mini, maxi])
plt.tight_layout()
plt.show()
The simplest, fastest solution I came up with is to solve for x and y in:
largest_x_coodinate_value(x) = x_dimension of image_in_pixels
largest_y_coordinate_value(y) = y_dimension_of_image_in_pixels
And then do vectorized multiplication over the numpy arrays containing the X and Y coordinates with those calculated x,y values, effectively scaling the coordinates to the size of the image.

plot many circles based on x,y,r being vectors in python

x,y are positions of the circles and r is the radius - all vectors.I want to plot them all at once. Something like:
import matplotlib.pyplot as plt
from matplotlib.patches Circle
#define x,y,r vectors
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
plt.Circle((x,y),r,color='r')
plt.show()
Thanks.
plt.scatter allows you to define a radius of the points plotted.
From the doc
matplotlib.pyplot.scatter(x, y, s=20, c='b', marker='o')
[...]
s:
size in points^2. It is a scalar or an array of the same length as x and y.
Playing with facecolor and edgecolor you should be able to get what you want
You can find an example in How to set_gid() for each bubble in matplot scatter chart?
I am not informed about the Circles patch, but here is how you can do it with the standard plot command:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([0.2,0.4])
y = np.array([0.2,1.2])
r = np.array([0.5,0.3])
phi = np.linspace(0.0,2*np.pi,100)
na=np.newaxis
# the first axis of these arrays varies the angle,
# the second varies the circles
x_line = x[na,:]+r[na,:]*np.sin(phi[:,na])
y_line = y[na,:]+r[na,:]*np.cos(phi[:,na])
plt.plot(x_line,y_line,'-')
plt.show()
The basic idea is to give the plt.plot(...) command two 2D arrays. In that case they are interpreted as a list of plots. Espacially for many plots (=many circles) this is much faster, than plotting circle by circle.

Draw axis lines or the origin for Matplotlib contour plot

I want to draw x=0 and y=0 axis in my contour plot, using a white color. If that is too cumbersome, I would like to have a white dot denoting where the origin is.
My contour plot looks as follows and the code to create it is given below.
xvec = linspace(-5.,5.,100)
X,Y = meshgrid(xvec, xvec)
fig = plt.figure(figsize=(6, 4))
contourf(X, Y, W,100)
plt.colorbar()
There are a number of options (E.g. centered spines), but in your case, it's probably simplest to just use axhline and axvline.
E.g.
import numpy as np
import matplotlib.pyplot as plt
xvec = np.linspace(-5.,5.,100)
x,y = np.meshgrid(xvec, xvec)
z = -np.hypot(x, y)
plt.contourf(x, y, z, 100)
plt.colorbar()
plt.axhline(0, color='white')
plt.axvline(0, color='white')
plt.show()
Can't you just overlay a straight line?
plt.plot([0,0],[-4,4],lw=3,'w')

Categories

Resources