4

I am having an issue plotting a polar equation in python using matplotlib.

The way I understand it, I am to create a variable that represents theta.. or all angles that is to be used in the plot. In my case from 0 to 2(pi), with 1000 steps in between.

Then I should just be able to input the polar equation as R and, plot it.

My issue is that I know this equation* is supposed to be a circle. But my code does not plot a circle.

*r = 2sinθ + 2cosθ

Here is what is produces by wolfram alpha, which I know is the correct graph, vs my result

Wolfram Alpha Expected graph

Result of my python code Python output

Now if I change r to be this instead:

r = abs(2 * np.cos(theta) + 2 * np.sin(theta))

The graph produced is as shown here

This graphs "top half" is what i expect from my original code, and cannot figure out why the graph produces a cardioid instead of a circle

import numpy as np
from matplotlib import pyplot as plt

#Produce theta variable
theta = np.arange(0, 2*np.pi, .01)[1:]

#Input polar equation of 2sinθ + 2cosθ 
r = 2 * np.cos(theta) + 2 * np.sin(theta) 
# Adding "()" around eq doesn't change anything

#Make plt figure
fig = plt.figure()

#Make sub-plot with attribute "polar"
ax = fig.add_subplot(polar=True)

#Plot function
ax.plot(theta, r)

#Show plot
plt.show()
4
  • 2
    The main confusion is that Matplotlib doesn't draw negative r values at the negative side. Instead, it makes an r-range from -3 to 3. Commented Aug 20, 2021 at 9:57
  • 1
    Possible duplicates: Polar plot of a function with negative radii using matplotlib, Plotting rose curve in python with even petals. Commented Aug 23, 2021 at 14:04
  • 1
    Just replace ax.plot(t, r) by ax.plot(t+(r<0)*np.pi, np.abs(r)) for the reason explained in the second link provided by @Stef. Commented Jan 7, 2024 at 11:03
  • "1000 steps in between", this is not necessary to sample the curve with this precision for plotting. You can take 60 to 80 samples along the horizontal axis, the curve will looks like perfectly continuous with the default size. E.g. for a circle, take 2*60=120 samples (t = np.linspace(0, 2*np.pi, 120)) Commented Jan 7, 2024 at 11:06

2 Answers 2

7

The main confusion is that Matplotlib doesn't draw negative r values at the negative side. Instead, it makes an r-range from -3 to 3 and draws everything at the same side.

You can obtain a more conventional interpretation by rotating theta by 180º for negative r and taking the absolute value of r:

import numpy as np
from matplotlib import pyplot as plt

theta = np.arange(0, 2 * np.pi, .01)[1:]
r = 2 * np.cos(theta) + 2 * np.sin(theta)

fig = plt.figure()
ax = fig.add_subplot(polar=True)

# change negative r values to positive, rotating theta by 180º
theta = np.where(r >= 0, theta, theta + np.pi)
r = np.abs(r)
ax.plot(theta, r)

plt.show()

rotating theta 180º for negative r

Here is another example to show the difference between the default and moving negative r-values to the other side, using r = theta - pi for theta between 0 and 2 pi. The part of the curve where r is positive is drawn in blue, the negative in red. Note the labeling of the r axis: from -3 to 3 for the default and from 0 to 3 for the modified version. (With the original example, the red and blue curves occupy the same location.)

import numpy as np
from matplotlib import pyplot as plt

theta = np.arange(0, 2 * np.pi, .01)[1:]
r = theta - np.pi
positive_r = r >= 0

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 5), subplot_kw={'polar': True})

for ax in (ax1, ax2):
    if ax == ax2:
        # change negative r values to positive, rotating theta by 180º
        theta = np.where(r >= 0, theta, theta + np.pi)
        r = np.abs(r)
    ax.plot(theta[positive_r], r[positive_r], color='skyblue')
    ax.plot(theta[~positive_r], r[~positive_r], color='tomato')
ax1.set_title('Default: negative $r$\non same side as $theta$')
ax2.set_title('Negative $r$ on other side')

plt.show()

comparing polar plots with negative r

Sign up to request clarification or add additional context in comments.

1 Comment

Fantastic. This is exactly what I was looking for. Not quite sure I understand the math behind why that works. But I will look into it. Much appreciated!
4

If I understand correctly what you want, you express your curve in polar coordinates, but you should convert it in cartesian coordinates.

x = r*np.cos(theta)
y = r*np.sin(theta)

In this way, the plot call in cartesian coordinates gives the circle:

fig = plt.figure(figsize = (5, 5))
ax = fig.add_subplot(polar = False)
ax.plot(x, y)

enter image description here

while in polar coordinates gives:

fig = plt.figure(figsize = (5, 5))
ax = fig.add_subplot(polar = True)
ax.plot(x, y)

enter image description here

2 Comments

Is it completely required to convert this to cartesian? I have a different equation that is represented rather perfectly in the polar form. (r=np.sqrt(4*np.sin(2*theta))). But if this is the best way to represent this graph, then of course I will just convert it.
@matrucious: There is no need to convert to Cartesian coordinates. As soon as the subplot type is set to polar (e.g. fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})), then ax.plot(theta, r) expects being provided polar coordinates, not Cartesian ones. It's plot which does the coordinate transformation, as expected (see elaborated map projections used in Cartopy).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.