how to draw a heart with pylab - python

How to draw a heart with pylab? I searched with google for ways to draw the picture but i want know how to draw it with pylab. Can someone help? The picture should look like this:

Using the linked formula in the other solution:
import pylab
x = scipy.linspace(-2,2,1000)
y1 = scipy.sqrt(1-(abs(x)-1)**2)
y2 = -3*scipy.sqrt(1-(abs(x)/2)**0.5)
pylab.fill_between(x, y1, color='red')
pylab.fill_between(x, y2, color='red')
pylab.xlim([-2.5, 2.5])
pylab.text(0, -0.4, 'Stack Overflow', fontsize=24, fontweight='bold',
color='white', horizontalalignment='center')
pylab.savefig('heart.png')

You can see here, how can you plot a 3D hearth.
The author of the article have put together the implicit function plotting can be found here and the implicit function of the hearth, and got the code below:
#!/usr/bin/env python3
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np
def heart_3d(x,y,z):
return (x**2+(9/4)*y**2+z**2-1)**3-x**2*z**3-(9/80)*y**2*z**3
def plot_implicit(fn, bbox=(-1.5, 1.5)):
''' create a plot of an implicit function
fn ...implicit function (plot where fn==0)
bbox ..the x,y,and z limits of plotted interval'''
xmin, xmax, ymin, ymax, zmin, zmax = bbox*3
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
A = np.linspace(xmin, xmax, 100) # resolution of the contour
B = np.linspace(xmin, xmax, 40) # number of slices
A1, A2 = np.meshgrid(A, A) # grid on which the contour is plotted
for z in B: # plot contours in the XY plane
X, Y = A1, A2
Z = fn(X, Y, z)
cset = ax.contour(X, Y, Z+z, [z], zdir='z', colors=('r',))
# [z] defines the only level to plot
# for this contour for this value of z
for y in B: # plot contours in the XZ plane
X, Z = A1, A2
Y = fn(X, y, Z)
cset = ax.contour(X, Y+y, Z, [y], zdir='y', colors=('red',))
for x in B: # plot contours in the YZ plane
Y, Z = A1, A2
X = fn(x, Y, Z)
cset = ax.contour(X+x, Y, Z, [x], zdir='x',colors=('red',))
# must set plot limits because the contour will likely extend
# way beyond the displayed level. Otherwise matplotlib extends the plot limits
# to encompass all values in the contour.
ax.set_zlim3d(zmin, zmax)
ax.set_xlim3d(xmin, xmax)
ax.set_ylim3d(ymin, ymax)
plt.show()
if __name__ == '__main__':
plot_implicit(heart_3d)
I have changed the python to python3 in the first row. If you use Python 2 you need to set it back.

Hint: Take a look at example from Sage: 3D Love Heart:
x, y, z = var('x, y, z')
f(x, y, z) = (x^2+(9/4)*y^2+z^2-1)^3-x^2*z^3-(9/80)*y^2*z^3
P = implicit_plot3d(f, (x, -3, 3), (y, -3, 3), (z, -3, 3),
frame=False, axes=True, figsize=6,color="red")
P.show(viewer='tachyon')

Related

How to join matplotlib 3D surfaces so that they aren't layers but intersecting planes?

Consider following code that plots the intersection of two planes at the origin
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
def func(x, y, z):
C=np.exp(-5*(x**2 + y**2 + z**2))
return C
x= np.linspace(-1, 1, 20)
y = np.linspace(0, 1, 30)
X, Y = np.meshgrid(x, y)
Z = 2*X + 3*Y
Z1 = 2*X - 3*Y
C = func(X, Y, Z)
C1 = func(X, Y, Z1)
ax = plt.axes(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
cmap='viridis', edgecolor='none', facecolors = cm.jet(C/np.amax(C)));
[![enter image description here][1]][1]ax.plot_surface(X, Y, Z1, rstride=1, cstride=1,
cmap='viridis', edgecolor='none', facecolors = cm.jet(C1/np.amax(C1)));
I am trying to plot surfaces that intersect without them showing as layers. I also created other planes and it seems the only way I have found so far is by varying "zorder" but that would still be layers. I recognize that this needs proper 3D plotting but unfortunately, mayavi and vtk cannot be installed on this computer so I am seeking a matplotlib only solution. Is there is way in matplotlib to stitch them together?

Plotting A 3D Hyperboloid

My teacher in class gave this formula
−0.3𝑥 **2−0.3𝑦 **2+𝑧 **2=1.
and showed its 3d graphic in class seen below. I just perform a half graphic, and I have no idea
how to plot the rest graphic. The following code
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
X = np.linspace(-5, 5, 100)
Y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(X, Y)
Z = np.sqrt(0.3*(X **2 + Y **2) + 1)
ax = plt.gca(projection='3d')
plot1 = ax.plot_surface(X, Y, Z, cmap='jet', alpha=0.6, vmin=-5, vmax=5)
plt.colorbar(plot1)
plt.show()
enter image description here
This is because when you change the expression about the z-axis, the result is positive no matter what value you substitute for x,y because of the square. Just adding -Z values is a simple solution.
ax.plot_surface(X, Y, Z, cmap='jet', alpha=0.6, vmin=-5, vmax=5)
ax.plot_surface(X, Y, -Z, cmap='jet', alpha=0.6, vmin=-5, vmax=5)

Plotting vertical cylindrical surfaces

Provided we have a contour on the xy plane, how can we plot "a curtain" raised from the contour to the limiting surface?
An example:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
def figure():
fig = plt.figure(figsize=(8,6))
axes = fig.gca(projection='3d')
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
x, y = np.meshgrid(x, y)
t1 = np.linspace(0, 8/9, 100)
x1 = t1
y1 = (2*t1)**0.5
f1 = lambda x, y: y
plt.plot(x1, y1)
axes.plot_surface(x, y, f1(x, y),color ='red', alpha=0.1)
axes.set_xlim(-2,2)
axes.set_ylim(-2,2)
figure()
How to plot a surface from the given line to the limiting surface?
Somebody wanted help plotting an intersection here cylinder "cuts" a sphere in python you could use the vertical cylinder part. It uses u, v parameters to generate x, y, z values

matplotlib plot surface too slow

I have a matrix S with 60 rows and 2000 columns. I need a 3d plot of this matrix.
This is what I have done:
S.dtype = 'float64'
S = sk.preprocessing.scale(S)
n, p = S.shape
X = np.arange(0, n)
Y = np.arange(0, p)
X, Y = np.meshgrid(X, Y)
def funz(x,y):
return S[x, y]
Z = funz(X, Y)
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
cmap=cm.RdBu,linewidth=0, antialiased=False)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
This works but the plot is too heavy in the sense that it is impossible to move it in order to visualize it better. How can I solve this?
In particular I need to find a nice view of the 3d plot to save it as a pdf figure.
matplotlib doesn't have "true" 3D plotting. Typically, you'd use something like mayavi for a complex or large surface, rather than matplotlib.
As a quick example:
import numpy as np
from mayavi import mlab
x, y = np.linspace(-15, 15, 200), np.linspace(-15, 15, 200)
xx, yy = np.meshgrid(x, y)
z = np.cos(np.hypot(xx, yy)) + np.sin(np.hypot(xx + 5, yy + 5))
mlab.figure(bgcolor=(1,1,1))
# We'll use "surf" to display a 2D grid...
# warp_scale='auto' guesses a vertical exaggeration for better display.
# Feel free to remove the "warp_scale" argument for "true" display.
mlab.surf(x, y, z, warp_scale='auto')
mlab.show()

matplotlib wireframe plot / 3d plot howTo

I would like to have a 3d plot with matplotlib.
Data are the following: I have a matrix with each row containing Y coordinates for the 3d plot. Each row first elements are the X coordinates for the 3d plot. Finally, a second matrix contains high for each point, at a X,Y position. This second matrix thus contains my Z coordinates. Both matrices are arrays of arrays with Python. I would like to know how to transform data so as to obtain:
a plot of each 1d signal corresponding to an X, like this (photo available online)
a wireframe plot for same data, like this
I have written an helper function for a wireframe work,
######## HELPER FOR PLOT 3-D
def plot_3d(name,X,Y,Z):
fig = plt.figure(name)
ax = fig.gca(projection='3d')
X = np.array(X)
Y = np.array(Y)
Z = np.array(Z)
ax.plot_wireframe(X,Y,Z,rstride=10,cstride=10)
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
plt.show()
but I dont know how to transform data X,Y,Z to make them fit requirements for matplotlib function, which want 2D lists for X, Y ,Z.
For first graph, I read help, and want to use 2d plot in 3d. Example source code gives:
x = np.linspace(0, 1, 100)
y = np.sin(x * 2 * np.pi) / 2 + 0.5
ax.plot(x, y, zs=0, zdir='z', label='zs=0, zdir=z')
where z is the constant coordinate. In my case, x is the constant coordinate. I adapt with
fig = plt.figure('2d profiles')
ax = fig.gca(projection='3d')
for i in range(10):
x = pt ## this is a scalar
y = np.array(y)
z = np.array(z)
ax.plot(xs = x, y, z, xdir='x')
plt.show()
but there is warning: non-keyword arg after keyword arg. How to fix?
Thanks and regards
Regarding the display of a serie of vectors in 3D, I came with following 'almost working' solution:
def visualizeSignals(self, imin, imax):
times = self.time[imin:imax]
nrows = (int)((times[(len(times)-1)] - times[0])/self.mod) + 1
fig = plt.figure('2d profiles')
ax = fig.gca(projection='3d')
for i in range(nrows-1):
x = self.mat1[i][0] + self.mod * i
y = np.array(self.mat1T[i])
z = np.array(self.mat2[i])
ax.plot(y, z, zs = x, zdir='z')
plt.show()
As for 2D surface or meshgrid plot, I come through using meshgrid. Note that you can reproduce a meshgrid by yourself once you know how a meshgrid is built. For more info on meshgrid, I refer to this post.
Here is the code (cannot use it as such since it refers to class members, but you can build your code based on 3d plot methods from matplotlib I am using)
def visualize(self, imin, imax, typ_ = "wireframe"):
"""
3d plot signal between imin and imax
. typ_: type of plot, "wireframce", "surface"
"""
times = self.retT[imin:imax]
nrows = (int)((times[(len(times)-1)] - times[0])/self.mod) + 1
self.modulate(imin, imax)
fig = plt.figure('3d view')
ax = fig.gca(projection='3d')
x = []
for i in range(nrows):
x.append(self.matRetT[i][0] + self.mod * i)
y = []
for i in range(len(self.matRetT[0])):
y.append(self.matRetT[0][i])
y = y[:-1]
X,Y = np.meshgrid(x,y)
z = [tuple(self.matGC2D[i]) for i in range(len(self.matGC))] # matGC a matrix
zzip = zip(*z)
for i in range(len(z)):
print len(z[i])
if(typ_ == "wireframe"):
ax.plot_wireframe(X,Y,zzip)
plt.show()
elif(typ_ == "contour"):
cset = ax.contour(X, Y, zzip, zdir='z', offset=0)
plt.show()
elif(typ_ == "surf_contours"):
surf = ax.plot_surface(X, Y, zzip, rstride=1, cstride=1, alpha=0.3)
cset = ax.contour(X, Y, zzip, zdir='z', offset=-40)
cset = ax.contour(X, Y, zzip, zdir='x', offset=-40)
cset = ax.contour(X, Y, zzip, zdir='y', offset=-40)
plt.show()

Categories