I wrote a simple function to plot log in python:
import matplotlib.pyplot as plt
import numpy as np
x = list(range(1, 10000, 1))
y = [-np.log(p/10000) for p in x]
plt.scatter(x, y) # also tried with plt.plot(x, y)
plt.show()
I just want to see how the plot looks.
fn.py:5: RuntimeWarning: divide by zero encountered in log
y = [-np.log(p/10000) for p in x]
I get the above error and on top of that I get a blank plot with even the ranges wrong.
It is strange why there is divide by zero warning, when I am dividing by a number?
How can I correctly plot the function?
Although you have tagged python-3.x, it seems that you are using python-2.x where p/10000 will result in 0 for values of p < 10000 because the division operator / performs integer division in python-2.x. If that is the case, you can explicitly use 10000.0 instead of 10000 to avoid that and get a float division.
Using .0 is not needed in python 3+ because by default it performs float division. Hence, your code works fine in python 3.6.5 though
import matplotlib.pyplot as plt
import numpy as np
x = list(range(1, 10000, 1))
y = [-np.log(p/10000.0) for p in x]
plt.scatter(x, y)
plt.show()
On a different note: You can simply use NumPy's arange to generate x and avoid the list completely and use vectorized operation.
x = np.arange(1, 10000)
y = -np.log(x/10000.0)
Why import numpy and then avoid using it? You could have simply done:
from math import log
import matplotlib.pyplot as plt
x = xrange(1, 10000)
y = [-log(p / 10000.0) for p in x]
plt.scatter(x, y)
plt.show()
If you're going to bring numpy into the picture, think about doing things in a numpy-like fashion:
import matplotlib.pyplot as plt
import numpy as np
f = lambda p: -np.log(p / 10000.0)
x = np.arange(1, 10000)
plt.scatter(x, f(x))
plt.show()
Related
I have an array containing 5 different numbers:
array([2.40064633, 4.10132553, 8.59968518, 2.40290345, 1.39988773]
and I want to plot the lines on the x axis (parallel to the y axis) equal to each of these numbers i.e.
x = 2.4006463
x = 4.10132553 so on and so forth for all of the numbers in the array.
I tried using plot(x = array[...]) but to no solution.
Is there a clean way of doing this using numpy or mathlab?
This will work:
import matplotlib.pyplot as plt
b =([2.40064633, 4.10132553, 8.59968518, 2.40290345, 1.39988773])
for l in b:
plt.axvline(l)
plt.show()
or is it an numpy array then:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(1,4)
for l in x:
plt.axvline(l)
plt.show()
here is my take. quite the similar as Rahul's only with the lines harshed.
import matplotlib.pyplot as plt
import numpy as np
xcoords = np.array([2.40064633, 4.10132553, 8.59968518, 2.40290345, 1.39988773])
for xc in xcoords:
plt.axvline(x=xc, color='k', linestyle='--')
What is the most efficient way to plot 3d array in Python?
For example:
volume = np.random.rand(512, 512, 512)
where array items represent grayscale color of each pixel.
The following code works too slow:
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
volume = np.random.rand(20, 20, 20)
for x in range(len(volume[:, 0, 0])):
for y in range(len(volume[0, :, 0])):
for z in range(len(volume[0, 0, :])):
ax.scatter(x, y, z, c = tuple([volume[x, y, z], volume[x, y, z], volume[x, y, z], 1]))
plt.show()
For better performance, avoid calling ax.scatter multiple times, if possible.
Instead, pack all the x,y,z coordinates and colors into 1D arrays (or
lists), then call ax.scatter once:
ax.scatter(x, y, z, c=volume.ravel())
The problem (in terms of both CPU time and memory) grows as size**3, where size is the side length of the cube.
Moreover, ax.scatter will try to render all size**3 points without regard to
the fact that most of those points are obscured by those on the outer
shell.
It would help to reduce the number of points in volume -- perhaps by
summarizing or resampling/interpolating it in some way -- before rendering it.
We can also reduce the CPU and memory required from O(size**3) to O(size**2)
by only plotting the outer shell:
import functools
import itertools as IT
import numpy as np
import scipy.ndimage as ndimage
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def cartesian_product_broadcasted(*arrays):
"""
http://stackoverflow.com/a/11146645/190597 (senderle)
"""
broadcastable = np.ix_(*arrays)
broadcasted = np.broadcast_arrays(*broadcastable)
dtype = np.result_type(*arrays)
rows, cols = functools.reduce(np.multiply, broadcasted[0].shape), len(broadcasted)
out = np.empty(rows * cols, dtype=dtype)
start, end = 0, rows
for a in broadcasted:
out[start:end] = a.reshape(-1)
start, end = end, end + rows
return out.reshape(cols, rows).T
# #profile # used with `python -m memory_profiler script.py` to measure memory usage
def main():
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
size = 512
volume = np.random.rand(size, size, size)
x, y, z = cartesian_product_broadcasted(*[np.arange(size, dtype='int16')]*3).T
mask = ((x == 0) | (x == size-1)
| (y == 0) | (y == size-1)
| (z == 0) | (z == size-1))
x = x[mask]
y = y[mask]
z = z[mask]
volume = volume.ravel()[mask]
ax.scatter(x, y, z, c=volume, cmap=plt.get_cmap('Greys'))
plt.show()
if __name__ == '__main__':
main()
But note that even when plotting only the outer shell, to achieve a plot with
size=512 we still need around 1.3 GiB of memory. Also beware that even if you have enough total memory but, due to a lack of RAM, the program uses swap space, then the overall speed of the program will
slow down dramatically. If you find yourself in this situation, then the only solution is to find a smarter way to render an acceptable image using fewer points, or to buy more RAM.
First, a dense grid of 512x512x512 points is way too much data to plot, not from a technical perspective but from being able to see anything useful from it when observing the plot. You probably need to extract some isosurfaces, look at slices, etc. If most of the points are invisible, then it's probably okay, but then you should ask ax.scatter to only show the nonzero points to make it faster.
That said, here's how you can do it much more quickly. The tricks are to eliminate all Python loops, including ones that would be hidden in libraries like itertools.
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
# Make this bigger to generate a dense grid.
N = 8
# Create some random data.
volume = np.random.rand(N, N, N)
# Create the x, y, and z coordinate arrays. We use
# numpy's broadcasting to do all the hard work for us.
# We could shorten this even more by using np.meshgrid.
x = np.arange(volume.shape[0])[:, None, None]
y = np.arange(volume.shape[1])[None, :, None]
z = np.arange(volume.shape[2])[None, None, :]
x, y, z = np.broadcast_arrays(x, y, z)
# Turn the volumetric data into an RGB array that's
# just grayscale. There might be better ways to make
# ax.scatter happy.
c = np.tile(volume.ravel()[:, None], [1, 3])
# Do the plotting in a single call.
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.scatter(x.ravel(),
y.ravel(),
z.ravel(),
c=c)
A similar solution can be achieved with product from itertools:
from itertools import product
from matplotlib import pyplot as plt
N = 8
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(projection="3d")
space = np.array([*product(range(N), range(N), range(N))]) # all possible triplets of numbers from 0 to N-1
volume = np.random.rand(N, N, N) # generate random data
ax.scatter(space[:,0], space[:,1], space[:,2], c=space/8, s=volume*300)
I would like to plot my intermediate results and want to see how is the algorithm progressing. I have posted a demo code too. Lets say my algorithm goes for 20 epochs and I want to plot the result of every epoch in a same file. I tried with following demo code. But I can not see any plot on a.png.
Could someone help me how could I do it?
import matplotlib.pylab as plt
import numpy as np
for i in range(20):
y = np.random.random()
plt.plot(i, y)
plt.savefig('a.png')
You have to provide the whole history in your variables e.g. as a list:
import matplotlib.pylab as plt
import numpy as np
# creates two lists with the same length
x = range(20)
y = [0] * 20
for i in x:
y.insert(i, np.random.random())
plt.plot(x, y)
plt.savefig('plot_%d.png' % i)
I've plotted a 3-d mesh in Matlab by below little m-file:
[x,n] = meshgrid(0:0.1:20, 1:1:100);
mu = 0;
sigma = sqrt(2)./n;
f = normcdf(x,mu,sigma);
mesh(x,n,f);
I am going to acquire the same result by utilization of Python and its corresponding modules, by below code snippet:
import numpy as np
from scipy.integrate import quad
import matplotlib.pyplot as plt
sigma = 1
def integrand(x, n):
return (n/(2*sigma*np.sqrt(np.pi)))*np.exp(-(n**2*x**2)/(4*sigma**2))
tt = np.linspace(0, 20, 2000)
nn = np.linspace(1, 100, 100)
T = np.zeros([len(tt), len(nn)])
for i,t in enumerate(tt):
for j,n in enumerate(nn):
T[i, j], _ = quad(integrand, -np.inf, t, args=(n,))
x, y = np.mgrid[0:20:0.01, 1:101:1]
plt.pcolormesh(x, y, T)
plt.show()
But the output of the Python is is considerably different with the Matlab one, and as a matter of fact is unacceptable.
I am afraid of wrong utilization of the functions just like linespace, enumerate or mgrid...
Does somebody have any idea about?!...
PS. Unfortunately, I couldn't insert the output plots within this thread...!
Best
..............................
Edit: I changed the linespace and mgrid intervals and replaced plot_surface method... The output is 3d now with the suitable accuracy and smoothness...
From what I see the equivalent solution would be:
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
x, n = np.mgrid[0:20:0.01, 1:100:1]
mu = 0
sigma = np.sqrt(2)/n
f = norm.cdf(x, mu, sigma)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(x, n, f, rstride=x.shape[0]//20, cstride=x.shape[1]//20, alpha=0.3)
plt.show()
Unfortunately 3D plotting with matplotlib is not as straight forward as with matlab.
Here is the plot from this code:
Your Matlab code generate 201 points through x:
[x,n] = meshgrid(0:0.1:20, 1:1:100);
While your Python code generate only 20 points:
tt = np.linspace(0, 19, 20)
Maybe it's causing accuracy problems?
Try this code:
tt = np.linspace(0, 20, 201)
The seminal points to resolve the problem was:
1- Necessity of the equivalence regarding the provided dimensions of the linespace and mgrid functions...
2- Utilization of a mesh with more density to make a bee line into a high degree of smoothness...
3- Application of a 3d plotter function, like plot_surf...
The current code is totally valid...
I have a signal that is not sampled equidistant; for further processing it needs to be. I thought that scipy.signal.resample would do it, but I do not understand its behavior.
The signal is in y, corresponding time in x.
The resampled is expected in yy, with all corresponding time in xx. Does anyone know what I do wrong or how to achieve what I need?
This code does not work: xx is not time:
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
x = np.array([0,1,2,3,4,5,6,6.5,7,7.5,8,8.5,9])
y = np.cos(-x**2/4.0)
num=50
z=signal.resample(y, num, x, axis=0, window=None)
yy=z[0]
xx=z[1]
plt.plot(x,y)
plt.plot(xx,yy)
plt.show()
Even when you give the x coordinates (which corresponds to the t argument), resample assumes that the sampling is uniform.
Consider using one of the univariate interpolators in scipy.interpolate.
For example, this script:
import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
x = np.array([0,1,2,3,4,5,6,6.5,7,7.5,8,8.5,9])
y = np.cos(-x**2/4.0)
f = interpolate.interp1d(x, y)
num = 50
xx = np.linspace(x[0], x[-1], num)
yy = f(xx)
plt.plot(x,y, 'bo-')
plt.plot(xx,yy, 'g.-')
plt.show()
generates this plot:
Check the docstring of interp1d for options to control the interpolation, and also check out the other interpolation classes.