Currently when I animate a surface in matplotlib, I generate snapshots manually and stitch together with ImageMagick. This is similar to the standard matplotlib animation in that it does not transition between the two frames.
Can I ease (in D3js terminology, and I'm sure of industry terminology more broadly - linear/cubic easing) during the transition? Or, is there a function in numpy to interpolate between two frames (the two surfaces) and end with a transition?
A simple example would be transitioning from the matplotlib example to any modification of the surface.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
to
Z = np.sin(2*R)
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
You could evaluate np.sin(a * R) for a range of a values using broadcasting:
n = 10 # or however many intermediate arrays you want
a = np.linspace(1, 2, n)
interp_z = np.sin(a[:, None, None] * R[None]) # an (n, 40, 40) array
Now you can plot each of the intermediate arrays, save it as an image, then stitch the images together however you like:
for i, Z in enumerate(interp_z):
ax.plot_surface(X, Y, Z, ...)
fig.savefig('image_{}.png'.format(i))
Related
I created 3d bar graph with matplotlib with the following code:
fig = plt.figure()
cmap = get_cmap(len(os.listdir(conv1d_kernel_path)))
ax = fig.add_subplot(111, projection='3d')
for f in os.listdir(conv1d_kernel_path):
step = int(re.findall(r'\d+', f)[0])
conv1d_kernel_histo[f]['bins'] = convert_bins(30, min_weight, max_weight, conv1d_kernel_histo[f])
bin_counts = conv1d_kernel_histo[f]['bins'][:, 2]
width = (max_weight-min_weight)/30 #ToDo change 30 to numbins
xs = conv1d_kernel_histo[f]['bins'][:, 0] + width / 2
ax.bar(xs, list(bin_counts), width=width, zs=step, zdir='y', color=cmap(step), ec=cmap(step+20), alpha=0.8)
ax.set_xlabel('weights')
ax.set_ylabel('step')
ax.set_zlabel('count')
plt.show()
The directory and convert bins function isn't so important, just that it gives me the info I can use to define the input data that I iteratively pass to the ax.bar function. Anyways, I receive the following output:
I want to invert the axis titled 'steps', and this question seems to be nearly what I need; however, when I used ax.invert_yaxis() the axis titled 'weights' is inverted. When I alternatively use ax.invert_xaxis() the same axis is inverted. Out of curiosity, I tried ax.invert_zaxis() but that worked as one would think, and flipped the whole graph upside down. Does anybody have a solution to this problem? A different method for inverting the axis? Thanks, all help is appreciated
Well inverting the axis limits like ax.set_ylim(150,0) should work fine. Sample plot:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Invert Y-Axis
ax.set_ylim(4,-4)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Original:
Inverted Y-Axis:
Trying to visualize hyperparamt and the result of them, I CAN NOT get to plot them in a 3d plot
I try to build a function as:
PlotGridSearch(grid,xparam,yparam,zlabels):
to be called as
gs= GridSearchCV(DecisionTreeClassifier()
,HyperParams
, scoring='accuracy'
, cv=50).fit(train_data,train_labels)
PlotGridSearch(gs
,'param_max_depth'
,'param_max_leaf_nodes'
,'mean_test_score')
But I can get to convert the mean_test_score columns to the necesary matrix (2 dimensional arrray) with the correct labels stracted from param_max_depth y param_max_leaf_nodes
any tips ?
There's a nice official documentation about 3D surface matplotlib plot.
# This import registers the 3D projection, but is otherwise unused.
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 unused import
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
If you are running python in Jupyter Notebook, you can use %matplotlib notebook to make it interactive.
And in your case, if you want to get the proper X,Y and Z, you could get the values from gs.cv_results_, which is:
m = len(param_grid['max_depth'])
n = len(param_grid['max_leaf_nodes'])
X = np.reshape(gs.cv_results_['param_max_depth'].data,[n,m]) # do mind the order of reshape, it might diff
Y = np.reshape(gs.cv_results_['param_max_leaf_nodes'].data,[n,m])
Z = np.reshape(gs.cv_results_['mean_test_score'],[n,m])
I'm using a newer version of matplotlib and the argument that sets the linewidth was removed. They seem to have changed it so I set it in Collections object, but I can't find a way of doing this.
I tried their example with a different linewidth:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=10, antialiased=False)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
But as the figure shows, it doesn't add lines to my surface.
What is the new method for setting linewidths?
Thanks!
The linewidth can of course only take effect if there is actually a line to be shown. So one would need to specify the color of the lines to show in order to see them.
surf = ax.plot_surface(X, Y, Z, cmap="RdYlGn", linewidth=2, edgecolor="limegreen")
I use matplotlib to simulate Y^2 + Z^2 = (SinX)^2
That is,the sine graph rotate 360 degrees based on x axis.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
t = np.arange(-5, 5, 0.25)
X,Y = np.meshgrid(t,t)
Z = np.sin(t)**2
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Following is the image
However,that seems not fit my expectation.
Is my way reasonable?
Or is there any way can implement in vpython?
Here is a VPython program that plots a function in 3D, which may be related to what you want to do.
http://www.glowscript.org/#/user/GlowScriptDemos/folder/Examples/program/Plot3D
Is it possible to disable the perspective when plotting in mplot3d, i.e. to use the orthogonal projection?
This is now official included since matplot version 2.2.2 Whats new | github
So for plotting a perspective orthogonal plot you have to add proj_type = 'ortho' then you should have something like that:
fig.add_subplot(121, projection='3d', proj_type = 'ortho')
Example Picture
]2
Example is taken from the official example script and edited
'''
======================
3D surface (color map)
======================
Demonstrates plotting a 3D surface colored with the coolwarm color map.
The surface is made opaque by using antialiased=False.
Also demonstrates using the LinearLocator and custom formatting for the
z axis tick labels.
'''
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
fig = plt.figure(figsize=(16,4))
ax.view_init(40, 60)
ax = fig.add_subplot(121, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
ax = fig.add_subplot(122, projection='3d', proj_type = 'ortho')
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.viridis, linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
plt.show()
NOTE: This has been updated see this answer instead.
Sort of, you can run this snippet of code before you plot:
import numpy
from mpl_toolkits.mplot3d import proj3d
def orthogonal_proj(zfront, zback):
a = (zfront+zback)/(zfront-zback)
b = -2*(zfront*zback)/(zfront-zback)
return numpy.array([[1,0,0,0],
[0,1,0,0],
[0,0,a,b],
[0,0,0,zback]])
proj3d.persp_transformation = orthogonal_proj
It is currently an open issue found here.