How to put text on polar chart using matplotlib? - python

This is a demo from the document of matplotlib
Scatter plot on polar axis
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
# Compute areas and colors
N = 150
r = 2 * np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = 200 * r**2
colors = theta
fig = plt.figure()
ax = fig.add_subplot(projection='polar')
c = ax.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75)
Now I want to replace these dots with some texts, like
What modification should I do to these code?
Further more, I also want to put picture instead of texts, is that possible?
Thanks!!!

This is the original code:
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
# Compute areas and colors
N = 150
r = 2 * np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = 200 * r**2
colors = theta
fig = plt.figure()
ax = fig.add_subplot(projection='polar')
c = ax.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75)
If you add this two lines:
plt.text(0.67, 0.9, 'I am cartesian coordinate', transform=plt.gcf().transFigure)
plt.text(np.pi, r[len(r)-1], 'I am polar coordinate')
You will get
and if you add this code:
im = Image.open('smurf.png')
newax = fig.add_axes([0.5, 0.5, 0.2, 0.2], zorder=1)
newax.imshow(im)
newax.axis('off')
newax = fig.add_axes([0.3, 0.3, 0.2, 0.2], zorder=1)
newax.imshow(im)
newax.axis('off')
You will get
But it requires conversion calculation to get to polar coordinate

You remove the ax.scatter part and instead use ax.text. But be aware that you need to pass the coordinates for the text also in polar coordinates. E.g.:
ax.text(np.pi / 2, 60, 'people', fontsize=20, color='red').

Here you go:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(projection='polar')
for text,xytext, color in zip(*[['cat', 'car', 'people'],[(0.5, 0.3),(0.5, 0.7),(0.1, 0.5)],['b', 'g','r']]):
ax.annotate(text,
xy=(0,0), # theta, radius
xytext=xytext, # fraction, fraction
textcoords='figure fraction',
horizontalalignment='left',
verticalalignment='bottom',
color=color,
size=20
)
plt.show()
For inserting images there is the following demo.

Related

Isochrone plot in polar coordinates

So I have some data in spherical coords, but r is not important. So I really have (theta,phi,value), where theta goes 0-360 deg and phi 0-90 deg... Values go from -40 to 40 ... I can plot this data using pcolormesh on a polar diagram,
phis2 = np.linspace(0.001,63,201)
thetas2 = np.linspace(0,2*np.pi,201)
# Using same number of samples in phi and thera to simplify plotting
print(phis2.shape,thetas2.shape)
X,Y = np.meshgrid(thetas2,phis2)
doppMap2 =orbits.doppler(X*units.rad,Y*deg) # Calling function with a vector: MUCH faster than looping as above
fig, ax = plt.subplots(figsize=(8,7),subplot_kw=dict(projection='polar'))
im=ax.pcolormesh(X,Y,doppMap2,cmap=mpl.cm.jet_r, edgecolors='face')
ax.set_theta_direction(-1)
ax.set_theta_offset(np.pi / 2.0)
ax.set_xticks([x for x in np.linspace(0,2*np.pi,13)][:-1]) # ignore label 360
ax.grid(True)
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.text(.6, 1.025, "Nadir ang", transform=ax.transAxes, fontsize=14)
## Add colorbar
cbar_ax = fig.add_axes([0.95, 0.15, 0.015, 0.7])
cbar = fig.colorbar(im, cax=cbar_ax)
cbar.ax.tick_params(labelsize=14)
#cbar.ax.set_yticklabels(['1', '2', '4', '6', '10', maxCV], size=24)
#cbar.set_label(r"log ($P(\overline{Z_{G}} /Z_{\odot})$ / $d(M_{G}/M_{\odot})$)",fontsize=36)
cbar.set_label(r"$d$f [kHz]",fontsize=24)
gc.collect()
but I'd like to generate isochrone lines instead. How would I do that?
Data for doppMap2 is here...
Matplotlib calls that a contour map:
# answering https://stackoverflow.com/questions/74073323/isochrone-plot-in-polar-coordinates
import numpy as np
import pandas
import matplotlib as mpl
import matplotlib.pyplot as plt
phis2 = np.linspace(0.001,63,201)
thetas2 = np.linspace(0,2*np.pi,201)
# Using same number of samples in phi and thera to simplify plotting
print(phis2.shape,thetas2.shape)
X,Y = np.meshgrid(thetas2,phis2)
# doppMap2 = orbits.doppler(X*units.rad,Y*deg) # Calling function with a vector: MUCH faster than looping as above
doppMap2 = pandas.read_csv('dopMap.csv', header=None)
print(doppMap2.shape)
fig, ax = plt.subplots(figsize=(8,7),subplot_kw=dict(projection='polar'))
im = ax.contour(X, Y, doppMap2, 12)
ax.set_theta_direction(-1)
ax.set_theta_offset(np.pi / 2.0)
ax.set_xticks([x for x in np.linspace(0,2*np.pi,13)][:-1]) # ignore label 360
ax.grid(True)
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.text(.6, 1.025, "Nadir ang",
transform=ax.transAxes, fontsize=14)
## Add colorbar
cbar_ax = fig.add_axes([0.95, 0.15, 0.015, 0.7])
cbar = fig.colorbar(im, cax=cbar_ax)
cbar.ax.tick_params(labelsize=14)
cbar.set_label(r"$d$f [kHz]",fontsize=24)
plt.show()

Add constant x, y , z lines into matplotlib 3D scatter plot in Python

I want to add constant x, y, z lines into a matplotlib 3D scatter plot in Python which extended from this limit point, may I know how could I do so?
x_limit = [-0.5] y_limit = [151] z_limit = [1090]
Example code:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import pandas as pd
from scipy.stats import multivariate_normal
fig = plt.figure(figsize=(8,8)) # size 4 inches X 4 inches
ax = fig.add_subplot(111, projection='3d')
np.random.seed(42)
xs = np.random.random(100)*-0.8
ys = np.random.random(100)*300
zs = np.random.random(100)*10500
plot = ax.scatter(xs,ys,zs)
ax.set_title("3D plot with limit")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
x_limit = [-0.5]
y_limit = [151]
z_limit = [1090]
ax.scatter(x_limit, y_limit, z_limit, c = 'g', marker = "s", s = 50)
plt.show()
This code should do the trick. There are a couple important things to note though. First, the mesh grid created only worked because each of the three axes share the same limits. Second, while the x_limit and y_limit values work as the X and Y arguments it appears that the Z argument is expected to be of a higher dimensionality (hence why I used full_like to fill an array of the same shape as x_1 and x_2 with the Z limit).
x_1, x_2 = np.meshgrid(np.arange(0, 1.1, 0.1), np.arange(0, 1.1, 0.1))
ax.plot_surface(x_limit, x_1, x_2, color='r', alpha=0.5)
ax.plot_surface(x_1, y_limit, x_2, color='g', alpha=0.5)
ax.plot_surface(x_1, x_2, np.full_like(x_1, z_limit), color='b', alpha=0.5)

Modifying saved plot with matplotlib

I am having a problem right now. I have run an extremely heavy simulation and, thus, generated a plot with matplotlib containing the results and saved it (as .jpg). However, there are some elemnts of the plot I would like to change, such as labels size and one vertical line. Is there a straighforward way to do this using matplotlib? I know I could have stored the data and now just replot changing the parameters (and, actually, I have done this), but I was wondering whether there is an easier way. Maybe something like:
fig, ax = plt.figure(path_to_figure)
ax.set_ylabel("Y_label")
...
You can refer to below example, which gives you more idea on how you can do this while plotting everything.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
%matplotlib inline
plt.rc('text', usetex=True)
def f(t):
return t ** 2
t1 = np.arange(0.0, 2.0, 0.1)
noise = np.random.randn(len(t1)) * 0.04
# x coordinates for the lines
xcoords = [0.1, 0.3, 0.5]
# colors for the lines
colors = ['r','k','b']
fig = plt.figure(figsize=(4, 3), dpi=200)
ax = fig.add_subplot(1, 1, 1)
plt.scatter(t1, f(t1 + noise), color = 'hotpink', label='Values obtained by experiment', edgecolors='k')
plt.plot(t1, f(t1), ls='solid', label='Theoretical expectation', color='b')
plt.title(r'This is latex title example $\mathbf{E = m \times c^2}$', fontsize='small')
for xc,c in zip(xcoords,colors):
plt.axvline(x=xc, label='line at x = {}'.format(xc), c=c)
plt.grid()
plt.legend(loc=0)
If you want to make all the fonts bold, you can also use below code to make everything bold:
font = {'weight' : 'bold',
'size' : 14 }
plt.rc('font', **font)
def f(t):
return t ** 2
t1 = np.arange(0.0, 2.0, 0.1)
noise = np.random.randn(len(t1)) * 0.04
# x coordinates for the lines
xcoords = [0.1, 0.3, 0.5]
# colors for the lines
colors = ['r','k','b']
fig = plt.figure(figsize=(4, 3), dpi=200)
ax = fig.add_subplot(1, 1, 1)
plt.scatter(t1, f(t1 + noise), color = 'hotpink', label='Values obtained by experiment', edgecolors='k')
plt.plot(t1, f(t1), ls='solid', label='Theoretical expectation', color='b')
plt.title(r'This is latex title example $\mathbf{E = m \times c^2}$', fontsize='small')
plt.xlabel("This is X-label.", fontsize=12)
plt.ylabel("This is Y-label.", fontsize=16)
for xc,c in zip(xcoords,colors):
plt.axvline(x=xc, label='line at x = {}'.format(xc), c=c)
plt.grid()
plt.legend(loc=(1.15,0.2))

Save specific part of matplotlib figure

I want to save only a specific part of a matplotlib figure by giving coordinates of a rectangle. The below code creates and saves the whole figure:
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = (30 * np.random.rand(N))**2
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
plt.savefig('Plot.png', format='png')
I want to save only a specific part inside the plot determined by 4 points (in data coordinates), for example only the highlighted rectangular area:
Desired result: Save only the part highlighted in green
You can use the parameter bbox_inches= of savefig() to delimit the region to save. The problem is finding out the coordinates of the region in inches. For that, you have to use transforms:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
# Fixing random state for reproducibility
np.random.seed(19680801)
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = (30 * np.random.rand(N))**2
fig, ax = plt.subplots()
ax.scatter(x, y, s=area, c=colors, alpha=0.5)
fig.canvas.draw() # force draw
x0,x1 = 0.2, 0.6
y0,y1 = 0.4, 0.8
bbox = Bbox([[x0,y0],[x1,y1]])
bbox = bbox.transformed(ax.transData).transformed(fig.dpi_scale_trans.inverted())
fig.savefig('test.png', bbox_inches=bbox)
test.png

matplotlib polar scatter plot: How do I change the units to anything but degrees?

In the matplotlib polar scatter plot, how can I change the units of the theta axis from angle to arbitrarily-specified units?
Starting from https://matplotlib.org/gallery/pie_and_polar_charts/polar_scatter.html (where all the examples are in degrees),
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
# Compute areas and colors
N = 150
r = 2 * np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = 200 * r**2
colors = theta
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
c = ax.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75)
plt.show()
The theta axis is always in degrees. What if I want it in, say, days, for a given function degrees=days2degrees(days)? Should I make use of
ax.set_thetalim()
ax.set_thetamin()
ax.set_thetamax()
etc.? These seem to require inputs in degrees.
Not sure this answers your question:
Just add something like
t = ax.get_xticks()
# your function
days = t/(2 * np.pi) * 365
ax.set_xticklabels(days, fontsize=12)

Categories