Plot Mandelbrot with matplotlib / pyplot / numpy / python - python

I am new to python and learning by following Python "Scientific lecture notes Release 2013.1" tutorial. Please help me solve this Mandelbrot problem in the srcreenshot below (Pg 71). Please provide step-wise commands with explanation if possible because programming concepts are new to me.
http://dl.dropbox.com/u/50511173/mandelbrot.png
I tried to solve this as follows:
import numpy as np
import matplotlib.pyplot as plt
x,y=np.ogrid[-2:1:10j,-1.5:1.5:10j]
c=x + 1j*y
z=0
for g in range(50):
z=z**2 + c
plt.imshow(z.T, extent=[-2,1,-1.5,1.5])
I encountered the following error "TypeError: Image data can not convert to float"
What does this error exactly mean and how to correct it? I am finding it difficult to understand the imshow() function. What do the individual terms inside imshow() mean?
Thank You.

The Mandelbrot set is not the values of z you are trying to plot, which are giving you problems because they are complex numbers. The Mandelbrot set is made up of the points p of the complex plane for which the recurrence relation z_n = z_n-1**2 + p remains bounded. This is checked in a practical way by comparing the result after a few iterations to some threshold. In your case, if you add the following lines after your for loop:
threshold = 2
mask = np.abs(z) < threshold
and then plot mask you should see the set plot on screen.
To understand the general workings of imshow's arguments, you will be better off reading the docs than asking here.

Thanks to #Jan and #Jaime. I got it working as follows, takes too much time to calculate though:
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
x,y=np.ogrid[-2:1:5000j,-1.5:1.5:5000j]
print('')
print('Grid set')
print('')
c=x + 1j*y
z=0
for g in range(500):
print('Iteration number: ',g)
z=z**2 + c
threshold = 2
mask=np.abs(z) < threshold
print('')
print('Plotting using imshow()')
plt.imshow(mask.T,extent=[-2,1,-1.5,1.5])
print('')
print('plotting done')
print('')
plt.gray()
print('')
print('Preparing to render')
print('')
plt.show()

You get this error because plt.imshow does not accept arrays of complex numbers. You can address the real or imaginary part of an array Z as Z.real or Z.imag. Thus if you want to plot the real part
plt.imshow(z.real.T, extent=[-2,1,-1.5,1.5])
would do the job.
The arguments in 'imshow' define the following things.
If z is a N-by-M matrix, it is interpreted as point values on a regular grid. By extent you specify how this grid extends in space...

You're trying to plot a complex value with imshow which is why you're getting that error, can use a threshold as others have suggested, but you might want to consider using np.angle or np.abs as well. You can also simplify your calculation of z using Python's built-in reduce method.
Had some fun with this one, but this shows the general idea:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
x, y = np.ogrid[-2:1:500j, -1.5:1.5:500j]
# Increase this to improve the shape of the fractal
iterations = 9
c = x + 1j*y
z = reduce(lambda x, y: x**2 + c, [1] * iterations, c)
plt.figure(figsize=(10, 10))
plt.imshow(np.angle(z));
plt.figure(figsize=(10, 10))
plt.imshow(np.log(np.abs(z)));

Related

Using Newton's Method in Python, no error messages but does not print/plot

I'm trying to use Newton's method to approximate the root for the Colebrook equation with Python. Currently the code gives no error but also does not print/plot. I understand this could be an individual case and thanks for all the help in advance!
enter image description here
numpy as np
import random
import matplotlib.pyplot as plt
#Define Variables, k=e/D, E+04<=x=Re<=E+07
k=0.0001
#Define Colebrook function, f=x=independent variable
def f(x):
return -0.86*(np.log(( 2.51/(Re*np.sqrt(x))) + ( k/3.7))) - (1/np.sqrt(x))
#Define derivative function by definition & approximation
def derivative(f,x,h):
return (f(x + h) - f(x))/h
#Newton's method approximation with initial gussed x value
x=0.01
for Re in range (10^4,10^7, 10000):
m=derivative(f,x,h=0.01)
b=f(x)-m*x #y=mx+b
newx=-b/m #new x value determined by the tangent line
if abs(g(newx))<= (1/10000000000):
print ('root =' + newx)
else:
x=newx
#plot
for Re in range (10^4, 10^7,10000):
x=newx
plt.plot (f(x))
I already know the root I'm looking for is approx. 0.03.
The most obvious problem:
range (10^4,10^7, 10000)
gives no output. You should look up the definition of range: the third input is the step size, not the number of steps; and I suppose you wanted to use "power", 10**4, 10**7. The ^ symbol is bitwise XOR.
I see several issues:
As mdurant pointed out, your range needs some proper rewriting.
Your first loop calls a g(x) function you don't have defined anywhere.
Even after that though, your second loop is saying "Let x be xnew, then add f(x) to the plot, and repeat that many times (without ever changing the value of x)".
Also, I think plt.plot() just adds data to the plot. You need plt.show() to see the graph. You may also want to define your plots axes, colors, etc. Some sample scripts using matplotlib can show you the syntax.

Python Overflow error multiplication

My code structure for a equation i am working on goes like this.
import matplotlib.pyplot as plt
for x in range (0 ,20):
temp = x * (-1*10**(-9)*(2.73**(x/0.0258*0.8) - 1) + 3.1)
P.append(temp)
Q.append(x)
print temp
plt.plot(Q,P)
plt.show()
Printing temp gives me this
4.759377049180328889121938118
-33447.32349862001706705983714
-2238083697441414267.104517188
-1.123028419942448387512537968E+32
-5.009018636753031534804021565E+45
-2.094526332030486492065138064E+59
-8.407952213322881981287736804E+72
-3.281407666305436036872349205E+86
-1.254513385166959745710275399E+100
-4.721184644539803475363811828E+113
-1.754816222227633792004755288E+127
-6.457248346728221564046430946E+140
-2.356455347384037854507854340E+154
-8.539736787129928434375037129E+167
-3.076467506425168063232368199E+181
-1.102652635599075169095479067E+195
-3.934509583907661118429424988E+208
-1.398436369682635574296418585E+222
-4.953240988408539700713401539E+235
-1.749015740500628326472633516E+249
The results shown are highly inaccurate. I know this because, the graph obtained is not what i am supposedly to get. A quick plotting of the same equation in google gave me this
This pic shows the differences in the graphs
The actual plot is the google.com one.
I m fairly certain that the errors are due to the floating point calculations. Can someone help me correct the formulated equations ?
Beginning from around 0.7 your scores drop into nothingness. Google is very clever to figure that out and limits the y-axis to a reasonable scale. In matplotlib you have to set this scale manually.
Also note that you are plotting integers from 0 to 19. When plotting continuous functions, linearly spaced points in an interval often make more sense.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 0.8, 100)
y = x * (-1e-9 *(2.73**(x/0.0258*0.8) - 1) + 3.1)
plt.plot(x,y)
plt.ylim(-0.5, 2)

Discrete fourier transformation from a list of x-y points

What I'm trying to do is, from a list of x-y points that has a periodic pattern, calculate the period. With my limited mathematics knowledge I know that Fourier Transformation can do this sort of thing.
I'm writing Python code.
I found a related answer here, but it uses an evenly-distributed x axis, i.e. dt is fixed, which isn't the case for me. Since I don't really understand the math behind it, I'm not sure if it would work properly in my code.
My question is, does it work? Or, is there some method in numpy that already does my work? Or, how can I do it?
EDIT: All values are Pythonic float (i.e. double-precision)
For samples that are not evenly spaced, you can use scipy.signal.lombscargle to compute the Lomb-Scargle periodogram. Here's an example, with a signal whose
dominant frequency is 2.5 rad/s.
from __future__ import division
import numpy as np
from scipy.signal import lombscargle
import matplotlib.pyplot as plt
np.random.seed(12345)
n = 100
x = np.sort(10*np.random.rand(n))
# Dominant periodic signal
y = np.sin(2.5*x)
# Add some smaller periodic components
y += 0.15*np.cos(0.75*x) + 0.2*np.sin(4*x+.1)
# Add some noise
y += 0.2*np.random.randn(x.size)
plt.figure(1)
plt.plot(x, y, 'b')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
dxmin = np.diff(x).min()
duration = x.ptp()
freqs = np.linspace(1/duration, n/duration, 5*n)
periodogram = lombscargle(x, y, freqs)
kmax = periodogram.argmax()
print("%8.3f" % (freqs[kmax],))
plt.figure(2)
plt.plot(freqs, np.sqrt(4*periodogram/(5*n)))
plt.xlabel('Frequency (rad/s)')
plt.grid()
plt.axvline(freqs[kmax], color='r', alpha=0.25)
plt.show()
The script prints 2.497 and generates the following plots:
As starting point:
(I assume all coordinates are positive and integer, otherwise map them to reasonable range like 0..4095)
find max coordinates xMax, yMax in list
make 2D array with dimensions yMax, xMax
fill it with zeros
walk through you list, set array elements, corresponding to coordinates, to 1
make 2D Fourier transform
look for peculiarities (peaks) in FT result
This page from Scipy shows you basic knowledge of how Discrete Fourier Transform works:
http://docs.scipy.org/doc/numpy-1.10.0/reference/routines.fft.html
They also provide API for using DFT. For your case, you should look at how to use fft2.

Plotting orbits in Python from orbital elements

I have created a program to take position and velocity state vectors and calculate all of the Keplerian orbital elements. The next step I want to do is plot the orbit! Any advice on how to approach this using Python 3? Also, any advice about where to migrate this question (if this spot is not appropriate) would be much appreciated.
The best plotting package is, by far, pyplot. It is essentialy a port of the matlab plotting system to python, but it works better than the original. Install numpy & matplotlib and look at the simple plotting tutorials. Plotting would be something like:
import matplotlib.pyplot as plt;
plt.plot(X, Y, color);
plt.show();
where X and Y are 1D arrays of the corresponding x, y values. The answer can't be more specific, since you don't give details about how the variables are stored.
I recommend OpenCV. Here I used CV2 for Python.
import numpy as np
import cv2
cv2.namedWindow("Orbit",cv2.WINDOW_AUTOSIZE)
im_old = np.zeros((100,100))
for i in range(360*4):
xc = 50
yc = 50
im = im_old.copy()
x = 25*np.cos(i*np.pi/180.0)+xc
y = 25*np.sin(i*np.pi/180.0)+yc
im[(x-2):(x+3),(y-2):(y+3)] = 255
im_old[x,y] = 128
cv2.imshow("Orbit",im)
cv2.waitKey(10);
This is for Python 2.7, but I think it should still work.
EDIT: This is for visualizing the actual motion, if that's what you're looking for.

Plotting functions at a specific y-interval

I need to plot a few exponential curves on the same plot - with the constraint that the plot ends at y=1.
For reference, here is the code:
from numpy import arange
from matplotlib import pyplot as plt
T = arange(60,89)
curve1 = 2**(T - 74)
curve2 = 2**(T - 60)
plt.plot(T,curve1 )
plt.plot(T,curve2 )
plt.show()
Here's the result:
The second curve is just barely visible, since the values are comparatively so low.
The problem I'm having is that all of these curves blow up to 700000+ fairly rapidly, but I'm only interested in the range being (0,1). How do I plot just these bits, but with nice smooth curves (so that one curve doesn't just stop halfway along)?
As you've found, this is easy to do if you adjust the range (T) for each function you add. However, if you need to change the functions, you'll need to recheck it.
The problem you're dealing with, generically, is calculating the x-range of some functions given their y-range - or, as a mathematician may put it, determining the domain of a function that corresponds to a range of its image. While, for a arbitrary function, this is impossible, it's possible if your function is injective, as is the case.
Let's say we have a function y=f(x), and the yrange is [y1,y2]. The x-range will be [f^(-1)(y1), f^(-1)(y2] (f^-1 being the inverse function of f)
Since we have multiple functions that we need to plot, the x_range is simply the greatest range - of all - the lower portion of the final range is the minimum of the lower portion of all the ranges, and the upper portion is the maximum of the upper portions.
Here's some code that exemplifies all this, by taking as a parameter the number of steps, and calculating the proper T over the x-range:
from numpy import arange
from matplotlib import pyplot as plt
from sympy import sympify, solve
f1= '2**(T - 74)' #note these are strings
f2= '2**(T - 60)'
y_bounds= (0.001, 1) #exponential functions never take 0 value, so we use 0.001
mm= (min, max)
x_bounds= [m(solve(sympify(f+"-"+str(y)))[0] for f in (f1,f2)) for y,m in zip(y_bounds, mm)]
print x_bounds
N_STEPS=100 #distributed over x_bounds
T = arange(x_bounds[0], x_bounds[1]+0.001, (x_bounds[1]-x_bounds[0])/N_STEPS)
curve1 = eval(f1) #this evaluates the function over the range, by evaluating the string as a python expression
curve2 = eval(f2)
plt.plot(T,curve1)
plt.plot(T,curve2)
plt.ylim([0,1])
plt.show()
The code outputs both the x-range (50.03, 74) and this plot:
This one was really easy: sorry to have wasted time on it.
Just set the y limits to be [0,1] via
plt.ylim([0,1])
and you're done.
In addition to the other answers, it may be worth plotting on a log-scale, since the growth of your functions is essentially exponential. For example:
from numpy import arange
from matplotlib import pyplot as plt
T = arange(60,89)
curve1 = 2**(T - 74)
curve2 = 2**(T - 60)
plt.semilogy(T,curve1 )
plt.semilogy(T,curve2 )
plt.show()

Categories