Add polar axes to cartesian plot in Matplotlib - python

I have drawn a polar contour plot in Matplotlib as described in this question. This basically works by converting the polar co-ordinates to cartesian co-ordinates and then plotting in the cartesian co-ordinate system.
However, I want to be able to have a set of polar co-ordinate system axes overlain on the plot - that is, radial axes (sticking out from the centre) at 0, 90, 180 and 270 degrees, with ticks on them showing the radius at various points.
I have absolutely no idea how to go about doing this, and can't seem to find anything in documentation. Any suggestions?

fig = plt.figure(0)
rect = [0.1,0.1,0.8,0.8]
theta = np.linspace(0,2*np.pi,12)
line = np.random.rand(5)
r = np.linspace(1,1,12)
ax_carthesian = fig.add_axes(rect, ylim=(6.5,10.5), xlim=(-2,2), aspect='equal')
ax_carthesian.set_xlabel('X [kpc]')
ax_carthesian.set_ylabel('Y [kpc]')
# the polar axis:
ax_polar = fig.add_axes(rect, polar=True, frameon=False, xticks=([]), yticks=([]))
ax_polar.set_xticklabels(['','l=135','','l=225','','l=315','','l=45'])
ax_polar.set_yticklabels([]) #no radial ticks
# plotting on the carthesian axis
im = ax_carthesian.scatter(x_stuff, y_stuff, cmap='magma')
ax_polar.grid(True)
bothaxes = [ax_carthesian, ax_polar]
cbar = plt.colorbar(im, ax = bothaxes)
cbar.ax.set_ylabel('Log I_CO [K]')

Related

How to draw a curved line/arc in a polar plot with matplotlib?

I'm trying to figure out how to create an arc between 2 points in a polar plot but the line that I'm drawing is a straight line connecting them even though the plot is polar.
Is there a different plotting function I need to use instead of ax.plot?
I noticed there are patches in matplotlib which might be what I'm supposed to use but I'm not sure how to add them in this way.
How can I draw a curved line from point A and point B on the polar plot?
# Create polar plot object
with plt.style.context("seaborn-white"):
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(111, projection="polar")
# Draw 3 lines
for degree in [90, 210, 330]:
rad = np.deg2rad(degree)
ax.plot([rad,rad], [0,1], color="black", linewidth=2)
# Connect two points with a curve
for curve in [[[90, 210], [0.5, 0.8]]]:
curve[0] = np.deg2rad(curve[0])
ax.plot(curve[0], curve[1])
The polar projections means that you don't use the x,y coordinate system anymore, but the polar one. Nevertheless a plot between 2 points will still be a straight line between them.
What you want to do is define the arc yourself like this:
from matplotlib import pyplot as plt
from scipy.interpolate import interp1d
import numpy as np
with plt.style.context("seaborn-white"):
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(111, projection="polar")
# Draw 3 lines
for degree in [90, 210, 330]:
rad = np.deg2rad(degree)
ax.plot([rad,rad], [0,1], color="black", linewidth=2)
# Connect two points with a curve
for curve in [[[90, 210], [0.5, 0.8]]]:
curve[0] = np.deg2rad(curve[0])
x = np.linspace( curve[0][0], curve[0][1], 500)
y = interp1d( curve[0], curve[1])( x)
ax.plot(x, y)
plt.show()

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

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()

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.

matplotlib: how to plot concentric circles at a given set of radii

I would like to plot concentric circles at a given set of distances away from a source. The first thing I tried to do was draw an arc on polar plot, as this seemed like a logical substep:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, polar=True)
ax.plot([1.0,1.5], [5,5], color='r', linestyle='-')
plt.show()
The first problem I'm having is that this draws a straight line rather than an arc:
So the subquestion might be how do I draw an arc, in this case a 360 degree arc, at a given radius on a polar plot?. On the other hand, there might be a better solution altogether, perhaps one that doesn't involve a polar plot. Ultimately, as per the title, my objective is to draw concentric circles at a set of radii around a centre source.
easy, use it to make shooting targets all the time.:
ax.plot(np.linspace(0, 2*np.pi, 100), np.ones(100)*5, color='r', linestyle='-')
Just think of how you define a circle in a polar axis? Need two things, angle and radius. Those are np.linspace(0, 2*np.pi, 100) and np.ones(100)*5 here. If you just need a arc, change the first argument to something less than 0 to 2pi. And change the 2nd argument accordingly.
There are other ways to do this. plot() creates .lines.Line2D object objects, if you want .collections.PathCollection object instead of Line2D:
ax.scatter(1, 0, s=100000, facecolors='none')
Or you want to make patches:
ax.bar(0, 5, 2*np.pi, bottom=0.0, facecolor='None') #need to modified the edge lines or won't look right

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.

Categories

Resources