Python - 2/3D scatter plot with surface plot from that data - python
Using: [python] [numpy] [matplotlib]
So I have a 3D array to create a scatter plot making a n * n * n cube. Those points have different values of potential represented by colors.
size = 11
z = y = x = size
potential = np.zeros((z, y, x))
Positive = 10
Negative = -10
""" ------- Positive Polo --------- """
polox = poloy = poloz = [1,2]
polos=[polox,poloy,poloz]
polop = [list(x) for x in np.stack(np.meshgrid(*polos)).T.reshape(-1,len(polos))] # Positive polos list
for coord in polop:
potential[coord] = Positive
""" ------- Negative Polo --------- """
polo2x = polo2y = polo2z = [size-3,size-2]
polos2=[polo2x,polo2y,polo2z]
polon = [list(x) for x in np.stack(np.meshgrid(*polos2)).T.reshape(-1,len(polos2))] # Negative polos list
for coord in polon:
potential[coord] = Negative
I have 2 polos of values -10 and 10 at the start and the rest of the points are calculated like this: (the mean of the surrounding points, no diagonals):
for z in range(1,size):
for y in range(1,size):
for x in range(1,size):
if [z,y,x] in polop:
potential[z,y,x] = Positive # If positive polo, keeps potential
elif [z,y,x] in polon:
potential[z,y,x] = Negative # If negative polo, keeps potential
elif z!=size-1 and y!=size-1 and x!=size-1: # Sets the potential to the mean potential of neighbors
potential[z][y][x] = (potential[z][y][x+1] + potential[z][y][x-1] + potential[z][y+1][x] + potential[z][y-1][x] + potential[z+1][y][x] + potential[z-1][y][x]) / 6
And for the outer cells:
for z in range(0,size):
for y in range(0,size):
for x in range(0,size):
potential[z,y,0] = potential[z,y,2]
potential[z,0,x] = potential[z,2,x]
potential[0,y,x] = potential[2,y,x]
if z == size-1:
potential[size-1,y,x] = potential[size-3,y,x]
elif y == size-1:
potential[z,size-1,x] = potential[z,size-3,x]
elif x == size-1:
potential[z,y,size-1] = potential[z,y,size-3]
What I need is to show a surface connecting the points that have the same value interval 'same colors' (like from 0 to 2.5).
I know that there are a lot of questions like this, but I can't adapt to my code, it either doesn't show (such as this) or it's not the same problem or it's not with python (as this one), that's why I'm asking again.
It can also be shown as a lot of subplots each with a surface.
Note: My 3D array is such that if I type print(potential[1,1,1]) it shows the value of that cell that, as you can see in the image below, is 10. And that's what I use to show the colors.
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
z,y,x = potential.nonzero()
cube = ax.scatter(x, y, z, zdir='z', c=potential[z,y,x], cmap=plt.cm.rainbow) # Plot the cube
cbar = fig.colorbar(cube, shrink=0.6, aspect=5) # Add a color bar which maps values to colors.
It would be beneficial for you to create a Minimum, Complete and Verifiable Example to make assistance easier.
It's still not clear to me how you mean to calculate your potential, nor how you mean to generate your surface, so I have included trivial functions.
The code below will generate a 3D Scatterplot of coloured points and a Surface with the average value of the colour.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
def fn(x, y):
"""Custom fuction to determine the colour (potential?) of the point"""
return (x + y) / 2 # use average as a placeholder
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
size = 11 # range 0 to 10
# Make the 3D grid
X, Y, Z = np.meshgrid(np.arange(0, size, 1),
np.arange(0, size, 1),
np.arange(0, size, 1))
# calculate a colour for point(x,y,z)
zs = np.array([fn(x, y) for x, y in zip(np.ravel(X), np.ravel(Y))])
ZZ = zs.reshape(X.shape) # this is used below
# create the surface
xx, yy = np.meshgrid(np.arange(0, size, 1), np.arange(0, size, 1))
# Calcule the surface Z value, e.g. average of the colours calculated above
zzs = np.array([np.average(ZZ[x][y]) for x, y in zip(np.ravel(xx), np.ravel(yy))])
zz= zzs.reshape(xx.shape)
cube = ax.scatter(X, Y, Z, zdir='z', c=zs, cmap=plt.cm.rainbow)
surf = ax.plot_surface(xx, yy, zz, cmap=plt.cm.rainbow)
cbar = fig.colorbar(cube, shrink=0.6, aspect=5) # Add a color bar
plt.show()
The image generated will look something like this:
EDIT: With your additional code, I'm able to replicate your cube.
Then use the following code to generate a surface:
xx, yy = np.meshgrid(np.arange(0, size, 1), np.arange(0, size, 1))
#define potential range
min_p = 1.0
max_p = 4.0
zz = np.zeros((size, size))
for i in range(size): # X
for j in range(size): # Y
for k in range(size): # Z
p = potential[k,j,i]
if min_p < p < max_p:
zz[j][i] = p # stop at the first element to meet the conditions
break # break to use the first value in range
Then to plot this surface:
surf = ax.plot_surface(xx, yy, zz, cmap=plt.cm.rainbow)
Note: include vmin and vmax keyword args to keep the same scale, I've left those out so the surface deviations are more visible. I also set the alpha on the cube to 0.2 to make it easier to see the surface.
Related
Matplotlib - 3D surface plot disappears when cmap colors are specified
I am writing a script that generates 3D plots from an initial set of x/y values that are not a mesh grid. The script runs well and converts the data into a mesh grid and plots it fine but when I specify a cmap color the plot disappears. Why would this happen? code: fig = plt.figure() ax = fig.add_subplot(111, projection='3d') x = [] y = [] rlim = -4 llim = 4 increment = np.absolute((llim-rlim)*5) linespace = np.array(np.linspace(rlim,llim,increment, endpoint = False)) for val in linespace: for val1 in linespace: x.append(val) y.append(val1) x = np.array(x) y = np.array(y) z = np.array(np.sin(np.sqrt(np.power(x,2)+np.power(y,2)))/np.sqrt(np.power(x,2)+np.power(y,2))) rows = len(np.unique(x[~pd.isnull(x)])) array_size = len(x) columns = int(array_size/rows) X = np.reshape(x, (rows, columns)) Y = np.reshape(y, (rows, columns)) Z = np.reshape(z, (rows, columns)) ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap = 'Blues', edgecolor='none') plt.show() This yields However if all I do is delete the cmap entry in ax.plot_surface I ge the following: Why simply adding a cmap delete the plot?
Matplotlib is having a hard time scaling your colormap with NaNs in the Z matrix. I didn't look too close at your function, but it seems like you will get a NaN at the origin (0,0), and it looks like 1 is a reasonable replacement. Therefore, right after Z = np.reshape(z, (rows, columns)) I added Z[np.isnan(Z)] = 1., resulting in the following pretty graph:
How to create a plot with a repeating color pattern?
For my report, I'm creating a special color plot in jupyter notebook. There are two parameters, x and y. import numpy as np x = np.arange(-1,1,0.1) y = np.arange(1,11,1) with which I compute a third quantity. Here is an example to demonstrate the concept: values = [] for i in range(len(y)) : z = y[i] * x**3 # in my case the value z represents phases of oscillators # so I will transform the computed values to the intervall [0,2pi) values.append(z) values = np.array(values) % 2*np.pi I'm plotting y vs x. For each y = 1,2,3,4... there will be a horizontal line with total length two. For example: The coordinate (0.5,8) stands for a single point on line 8 at position x = 0.5 and z(0.5,8) is its associated value. Now I want to represent each point on all ten lines with a unique color that is determined by z(x,y). Since z(x,y) takes only values in [0,2pi) I need a color scheme that starts at zero (for example z=0 corresponds to blue). For increasing z the color continuously changes and in the end at 2pi it takes the same color again (so at z ~ 2pi it becomes blue again). Does someone know how this can be done in python?
The kind of structure for x, y and z you need, is easier using a meshgrid. Also, to have a lot of x-values between -1 and 1, np.linspace(-1,1,N) divides the range in N even intervals. Using meshgrid, z can be calculated in one line using numpy's vectorization. This runs much faster. To set a repeating color, a cyclic colormap such as hsv can be used. There the last color is the same as the starting color. import numpy as np from matplotlib import pyplot as plt x, y = np.meshgrid(np.linspace(-1,1,100), np.arange(1,11,1)) z = (y * x**3) % 2*np.pi plt.scatter(x, y, c=z, s=6, cmap='hsv') plt.yticks(range(1,11)) plt.show() Alternatively, a symmetric colormap could be built taken the colors from and existing map and combining them with the same colors in reverse order. import numpy as np from matplotlib import pyplot as plt import matplotlib.colors as mcolors colors_orig = plt.cm.viridis_r(np.linspace(0, 1, 128)) # combine the colors with the reversed array and build a new colormap colors = np.vstack((colors_orig, colors_orig[::-1])) symcmap = mcolors.LinearSegmentedColormap.from_list('symcmap', colors) x, y = np.meshgrid(np.linspace(-1,1,100), np.arange(1,11,1)) z = (y * x**3) % 2*np.pi plt.scatter(x, y, c=z, s=6, cmap=symcmap) plt.yticks(range(1,11)) plt.show()
Multicolored lines are somewhat more complicated than just scatter plots. The docs have an example using LineCollections. Here is the adapted code. Note that the line segments are colored using their start point, so make sure there are enough x values. Also, the x and y limits aren't set automatically any more. The code also adds a colorbar to illustrate how the colors map to the z values. Some interesting code from Jake VanderPlas shows how to create ticks for multiples of π. import numpy as np from matplotlib import pyplot as plt from matplotlib.collections import LineCollection # code from Jake VanderPlas def format_func(value, tick_number): # find number of multiples of pi/2 N = int(np.round(2 * value / np.pi)) if N == 0: return "0" elif N == 1: return r"$\pi/2$" elif N == 2: return r"$\pi$" elif N % 2 > 0: return r"${0}\pi/2$".format(N) else: return r"${0}\pi$".format(N // 2) x = np.linspace(-1, 1, 500) y_max = 10 # Create a continuous norm to map from data points to colors norm = plt.Normalize(0, 2 * np.pi) for y in range(1, y_max + 1): z = (y * x ** 3) % 2 * np.pi y_array = y * np.ones_like(x) points = np.array([x, y_array]).T.reshape(-1, 1, 2) segments = np.concatenate([points[:-1], points[1:]], axis=1) lc = LineCollection(segments, cmap='hsv', norm=norm) lc.set_array(z) # Set the values used for colormapping lc.set_linewidth(2) line = plt.gca().add_collection(lc) # plt.scatter(x, y_array, c=z, s=10, norm=norm, cmap='hsv') cbar = plt.colorbar(line) # , ticks=[k*np.pi for k in np.arange(0, 2.001, 0.25)]) cbar.locator = plt.MultipleLocator(np.pi / 2) cbar.minor_locator = plt.MultipleLocator(np.pi / 4) cbar.formatter = plt.FuncFormatter(format_func) cbar.ax.minorticks_on() cbar.update_ticks() plt.yticks(range(1, y_max + 1)) # one tick for every y plt.xlim(x.min(), x.max()) # the LineCollection doesn't force the limits plt.ylim(0.5, y_max + 0.5) plt.show()
How can I plot an equation into an array with redefined indices
So I have an equation lets say: x^2 + y^2 Currently, I can make an array that defines the equation, calculates the array based off input parameters and and prints out an array: def equation(x,y): return x**2 + y**2 def calculate(x, y, xmin, ymin): out = [] for i in range(x_min, xs): row = [] for j in range(y_min, ys): row.append(equation(i, j)) out.append(row) return out The output array calculates the values based off the indicies output such that (0,0) is upper left. Given an array with length and width, how can I calculate the equation so that the (0,0) is centered and follows a cartesian plane?
To center your data around 0,0,0 and plot the result, you could do something like the following: import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D def equation(x,y): return x**2 + y**2 x = [(i-50)/10 for i in range(0,100,1)] y = x z = [equation(i, j) for i, j in zip(x, y)] # plot the function fig = plt.figure() ax = fig.gca(projection='3d') ax.scatter(x, y, z, c='r', marker='o') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') # rotate the plot so we can see the 3 dimensions for angle in range(0, 360): ax.view_init(30, angle) plt.draw() plt.pause(.001) Result:
Basically you would just need to redefine what you are iterating over to put (0, 0) in the middle. I would suggest that you use a library like numpy though and take advantage of vectorized functions to speed up (and simplify) your code. For example: import numpy as np x = np.linspace(-1, 1, 11) # create 11 points arranged from -1 to 1 X, Y = np.meshgrid(x, x) # this produces the input values you'd get out of your double loop result = np.square(X) + np.square(Y) # your equation, applied to everything at once I made an odd number of points centered at 0 so that we would actually have an input value of (0, 0) right in the center. We can plot the result with the following: from matplotlib import pyplot as plt plt.imshow(result) Note that the axis ticks are wrong here because imshow doesn't care what our original inputs were, but that dark spot in the center is your (0, 0) input point.
Why is my line clipping in matplotlib?
I am trying to draw a series of lines. The lines are all the same length, and randomly switch colors for a random length (blue to orange). I am drawing the lines in blue and then overlaying orange on top. You can see from my picture there are clipped parts of the lines where it is grey. I cannot figure out why this is happening. Also related I believe is that my labels are not moving to a left alignment like they should. Any help is greatly appreciated. import numpy as np import matplotlib.pyplot as plt import matplotlib.lines as mlines import random plt.close('all') fig, ax = plt.subplots(figsize=(15,11)) def label(xy, text): y = xy[1] - 2 ax.text(xy[0], y, text, ha="left", family='sans-serif', size=14) def draw_chromosome(start, stop, y, color): x = np.array([start, stop]) y = np.array([y, y]) line = mlines.Line2D(x , y, lw=10., color=color) ax.add_line(line) x = 50 y = 100 chr = 1 for i in range(22): draw_chromosome(x, 120, y, "#1C2F4D") j = 0 while j < 120: print j length = 1 if random.randint(1, 100) > 90: length = random.randint(1, 120-j) draw_chromosome(j, j+length, y, "#FA9B00") j = j+length+1 label([x, y], "Chromosome%i" % chr) y -= 3 chr += 1 plt.axis('equal') plt.axis('off') plt.tight_layout() plt.show()
You're only drawing the blue background from x = 50 to x = 120. Replace this line: draw_chromosome(x, 120, y, "#1C2F4D") with this: draw_chromosome(0, 120, y, "#1C2F4D") To draw the blue line all the way across. Alternately, if you also want to move your labels to the left, you can just set x=0 instead of setting it to 50.
I suggest using LineCollection for this. Below is a little helper function I wrote based on the example at http://matplotlib.org/examples/pylab_examples/multicolored_line.html (it looks long, but there is a lot of comments + docstrings) import numpy as np import matplotlib.pyplot as plt from matplotlib.collections import LineCollection from matplotlib.colors import ListedColormap, BoundaryNorm from matplotlib.ticker import NullLocator from collections import OrderedDict def binary_state_lines(ax, chrom_data, xmin=0, xmax=120, delta_y=3, off_color = "#1C2F4D", on_color = "#FA9B00"): """ Draw a whole bunch of chromosomes Parameters ---------- ax : Axes The axes to draw stuff to chrom_data : OrderedDict The chromosome data as a dict, key on the label with a list of pairs of where the data is 'on'. Data is plotted top-down xmin, xmax : float, optional The minimum and maximum limits for the x values delta_y : float, optional The spacing between lines off_color, on_color : color, optional The colors to use for the the on/off state Returns ------- collections : dict dictionary of the collections added keyed on the label """ # base offset y_val = 0 # make the color map and norm cmap = ListedColormap([off_color, on_color]) norm = BoundaryNorm([0, 0.5, 1], cmap.N) # sort out where the text should be txt_x = (xmax + xmin) / 2 # dictionary to hold the returned artists ret = dict() # loop over the input data draw each collection for label, data in chrom_data.items(): # increment the y offset y_val += delta_y # turn the high windows on to alternating # high/low regions x = np.asarray(data).ravel() # assign the high/low state to each one state = np.mod(1 + np.arange(len(x)), 2) # deal with boundary conditions to be off # at start/end if x[0] > xmin: x = np.r_[xmin, x] state = np.r_[0, state] if x[-1] < xmax: x = np.r_[x, xmax] state = np.r_[state, 0] # make the matching y values y = np.ones(len(x)) * y_val # call helper function to create the collection coll = draw_segments(ax, x, y, state, cmap, norm) ret[label] = coll # set up the axes limits ax.set_xlim(xmin, xmax) ax.set_ylim(0, y_val + delta_y) # turn off x-ticks ax.xaxis.set_major_locator(NullLocator()) # make the y-ticks be labeled as per the input ax.yaxis.set_ticks((1 + np.arange(len(chrom_data))) * delta_y) ax.yaxis.set_ticklabels(list(chrom_data.keys())) # invert so that the first data is at the top ax.invert_yaxis() # turn off the frame and patch ax.set_frame_on(False) # return the added artists return ret def draw_segments(ax, x, y, state, cmap, norm, lw=10): """ helper function to turn boundary edges into the input LineCollection expects. Parameters ---------- ax : Axes The axes to draw to x, y, state : array The x edges, the y values and the state of each region cmap : matplotlib.colors.Colormap The color map to use norm : matplotlib.ticker.Norm The norm to use with the color map lw : float, optional The width of the lines """ points = np.array([x, y]).T.reshape(-1, 1, 2) segments = np.concatenate([points[:-1], points[1:]], axis=1) lc = LineCollection(segments, cmap=cmap, norm=norm) lc.set_array(state) lc.set_linewidth(lw) ax.add_collection(lc) return lc An example: synthetic_data = OrderedDict() for j in range(21): key = 'data {:02d}'.format(j) synthetic_data[key] = np.cumsum(np.random.randint(1, 10, 20)).reshape(-1, 2) fig, ax = plt.subplots(tight_layout=True) binary_state_lines(ax, synthetic_data, xmax=120) plt.show() Separating the plotting logic from everything else will make your code easier to maintain and more reusable. I also took the liberty of moving your labels from between the lines (where they can be ambiguous) to the yaxis tick labels.
How do you create a 3D surface plot with missing values matplotlib?
I am trying to create a 3D surface energy diagram where an x,y position on a grid contains an associated z level. The issue is that the grid is not uniform (ie, there is not a z component for every x,y position). Is there a way to refrain from plotting those values by calling them NaN in the corresponding position in the array? Here is what I have tried so far: import numpy as np from matplotlib import pyplot as plt from mpl_toolkits.mplot3d import Axes3D import pylab from matplotlib import cm #Z levels energ = np.array([0,3.5,1,-0.3,-1.5,-2,-3.4,-4.8]) #function for getting x,y associated z values? def fun(x,y,array): return array[x] #arrays for grid x = np.arange(0,7,0.5) y = np.arange(0,7,0.5) #create grid X, Y = np.meshgrid(x,y) zs = np.array([fun(x,y,energ) for x in zip(np.ravel(X))]) Z = zs.reshape(X.shape) plt3d = plt.figure().gca(projection='3d') #gradients now with respect to x and y, but ideally with respect to z only Gx, Gz = np.gradient(X * Y) G = (Gx ** 2 + Gz ** 2) ** .5 # gradient magnitude N = G / G.max() # normalize 0..1 plt3d.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=cm.jet(N), edgecolor='k', linewidth=0, antialiased=False, shade=False) plt.show() I cannot post image here of this plot but if you run the code you will see it But I would like to not plot certain x,y pairs, so the figure should triangle downward to the minimum. Can this be accomplished by using nan values? Also would like spacing between each level, to be connected by lines. n = np.NAN #energ represents the z levels, so the overall figure should look like a triangle. energ = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,2.6,n,2.97,n,2.6,n,2.97,n,2.6,n,3.58,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,1.09,n,1.23,n,1.09,n,1.23,n,1.7,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,-0.65,n,-0.28,n,-0.65,n,0.33,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,-2.16,n,-2.02,n,-1.55,n,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,-3.9,n,-2.92,n,n,n,n,n,],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,n,-4.8,n,n,n,n,n,n,]]) plt3d = plt.figure().gca(projection='3d') Gx, Gz = np.gradient(X * energ) # gradients with respect to x and z G = (Gx ** 2 + Gz ** 2) ** .5 # gradient magnitude N = G / G.max() # normalize 0..1 x = np.arange(0,13,1) y = np.arange(0,13,1) X, Y = np.meshgrid(x,y) #but the shapes don't seem to match up plt3d.plot_surface(X, Y, energ, rstride=1, cstride=1, facecolors=cm.jet(N), edgecolor='k', linewidth=0, antialiased=False, shade=False ) Using masked arrays generates the following error: local Python[7155] : void CGPathCloseSubpath(CGMutablePathRef): no current point. n = np.NAN energ = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,2.6,n,2.97,n,2.6,n,2.97,n,2.6,n,3.58,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,1.09,n,1.23,n,1.09,n,1.23,n,1.7,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,-0.65,n,-0.28,n,-0.65,n,0.33,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,-2.16,n,-2.02,n,-1.55,n,n,n,n],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,-3.9,n,-2.92,n,n,n,n,n,],[n,n,n,n,n,n,n,n,n,n,n,n,n],[n,n,n,n,n,n,-4.8,n,n,n,n,n,n,]]) x = np.arange(0,13,1) y = np.arange(0,13,1) X, Y = np.meshgrid(x,y) #create masked arrays mX = ma.masked_array(X, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]]) mY = ma.masked_array(Y, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]]) m_energ = ma.masked_array(energ, mask=[[0,0,0,0,0,0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,0,1,0,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,1,0,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1]]) plt3d = plt.figure().gca(projection='3d') plt3d.plot_surface(mX, mY, m_energ, rstride=1, cstride=1, edgecolor='k', linewidth=0, antialiased=False, shade=False) plt.show()
I was playing around with the code from this forum post, and I was able to make the graph have missing values. You can try the code yourself! I got it to work using float("nan") for the missing values. import plotly.graph_objects as go import numpy as np x = np.arange(0.1,1.1,0.1) y = np.linspace(-np.pi,np.pi,10) #print(x) #print(y) X,Y = np.meshgrid(x,y) #print(X) #print(Y) result = [] for i,j in zip(X,Y): result.append(np.log(i)+np.sin(j)) result[0][0] = float("nan") upper_bound = np.array(result)+1 lower_bound = np.array(result)-1 fig = go.Figure(data=[ go.Surface(z=result), go.Surface(z=upper_bound, showscale=False, opacity=0.3,colorscale='purp'), go.Surface(z=lower_bound, showscale=False, opacity=0.3,colorscale='purp')]) fig.show()