Plot a triangle contour/surface matplotlib python: tricontourf/meshgrid - python

Given the following image, where plt.Polygon was used to create the triangle and plt.contourf the contour, i would like to 'cut' off the regions marked in X so that i only get the contour inside the triangle. How would i do this?
I've tried placing NaN values in the mentioned regions but the edges are square and therefore requires a large meshgrid to generate a 'clean' cut between the unwanted and wanted regions. Rather is it more appropiate to use plt.tricontourf? If so how should one approach it?

Thanks #Zephyr for the tricontourf solution, Heres how i solved it without the use of tricontourf and simply a meshgrid
# =============== Define Points =============== #
left_point = np.array([8, 1])
top_point = np.array([10.75, 3.75])
right_point = np.array([13.5, 1])
# =============== Define Left Line Eq: y = mx+c =============== #
left_m = (top_point[-1] - left_point[-1]) / (top_point[0] - left_point[0])
left_c = left_point[-1] - left_m*left_point[0]
# =============== Define Right Line Eq: y = mx+c =============== #
right_m = (right_point[-1] - top_point[-1]) / (right_point[0] - top_point[0])
right_c = right_point[-1] - right_m*right_point[0]
# =============== Generate Spaced Points on Both Lines =============== #
n_points = 100
# x-coordinates on left line
X_left = np.linspace(left_point[0], top_point[0], n_points)
# y-coordinates on left line
Y_left = left_m * X_left + left_c
# x-coordinates on right line
X_right = np.linspace(right_point[0], top_point[0], n_points)
# y-coordinates on right line
Y_right = right_m * X_right + right_c
# Concatenate Left line X and Right line X: [X_left, X_right]
LR_X = np.hstack([X_left[:, None], X_right[:, None]])
# =============== Generate Spaced Points IN BETWEEN points on both lines =============== #
"""
# We can use lists to generate points between each adjacent points on the left/right line
# Then turn them into arrays
# NOTE: Y_left and Y_right are essentially equal so we could just use one of them
# XX = []
# YY = []
# for ii in range(n_points):
# XX.append(np.linspace(LR_X[ii, 0], LR_X[ii, 1], n_points).reshape(1, -1))
# YY.append(Y_left[ii]*np.ones(n_points).reshape(1, -1))
# XX = np.vstack(XX)
# YY = np.vstack(YY)
"""
# Or We could do this (Same thing)
XX = np.meshgrid(np.linspace(LR_X[:, 0], LR_X[:, 1], n_points))[0].reshape(n_points, n_points).T
YY = np.meshgrid([Y_left*np.ones(n_points)]*n_points)[0].reshape(n_points, n_points).T
# Im using a model to predict each point, so i had to flatten it out first
# i.e. XX.shape = (100, 100); YY.shape = (100, 100), WW.shape = (100*100, 2)
WW = np.c_[XX.ravel(), YY.ravel()]
ZZ = model.predict(WW).reshape(XX.shape)
# =============== Contour/Surface Plots =============== #
# Contour plot
fig1 = plt.figure(1, figsize=(8, 6))
ax1 = fig1.add_subplot(111)
levels = np.arange(Y.min(), Y.max())
contour_map = ax1.contourf(XX, YY, ZZ, cmap='viridis')
contour = ax1.contour(XX, YY, ZZ)
cbar = fig1.colorbar(contour_map, )
# Surface Plot
fig2 = plt.figure(2, figsize=(10, 6))
ax2 = fig2.add_subplot(projection='3d')
ax2.plot_surface(XX, YY, ZZ, cmap='viridis')

You could do it with matplotlib.pyplot.tricontourf, but it depends on the way you stored data.
You should have 4 arrays:
x array (1, N) with x coordinates
y array (1, N) with y coordinates
z array (1, N) with z values
triangles list of the index of x and y points which are the vertices of the clipping triangle
x = np.asarray([8, 10, 8, 14, 9, 11, 13, 10, 12, 11])
y = np.asarray([2, 2, 2, 2, 2.56666667, 2.56666667, 2.56666667, 3.13333333, 3.13333333, 3.7])
z = np.cos(2.5*x*x)*np.cos(1.5*y*x)
triangles = [[0, 3, 9]]
Then you can perform triangulation with:
triang = mtri.Triangulation(x, y, triangles)
Complete Code
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
import numpy as np
x = np.asarray([8, 10, 8, 14, 9, 11, 13, 10, 12, 11])
y = np.asarray([2, 2, 2, 2, 2.56666667, 2.56666667, 2.56666667, 3.13333333, 3.13333333, 3.7])
z = np.cos(2.5*x*x)*np.cos(1.5*y*x)
triangles = [[0, 3, 9]]
triang = mtri.Triangulation(x, y, triangles)
fig, ax = plt.subplots()
t = ax.tricontourf(triang, z)
plt.colorbar(t)
plt.show()
If your data are not in this shape, you should re-shaping your array in order to get x, y and z as above described and calculate the triangles indeces list. Please, provide your data if you need help.

Related

3D barplot in matplotlib, with scaled gradient colormap corresponding to a 4th dimension (range of values)

I am trying to create a 3D barplot using matplotlib in python, and apply a colormap which is tied some data (4th dimension) which is not explicitly plotted. I think what makes this even more complicated is that I want this 4th dimension to be a range of values as opposed to a single value.
So far I have managed to create the 3D bar plot with a colormap tied to the z-dimension thanks primarily to this post how to plot gradient fill on the 3d bars in matplotlib. The code can be found below.
import numpy as np
import glob,os
from matplotlib import pyplot as plt
import matplotlib.colors as cl
import matplotlib.cm as cm
from mpl_toolkits.mplot3d import Axes3D
os.chdir('./')
# axis details for the bar plot
x = ['1', '2', '3', '4', '5'] # labels
x_tick_locks = np.arange(0.1, len(x) + 0.1, 1)
x_axis = np.arange(len(x))
y = ['A', 'B']
y_tick_locks = np.arange(-0.1, len(y) - 0.1, 1)
y_axis = np.arange(len(y))
x_axis, y_axis = np.meshgrid(x_axis, y_axis)
x_axis = x_axis.flatten()
y_axis = y_axis.flatten()
x_data_final = np.ones(len(x) * len(y)) * 0.5
y_data_final = np.ones(len(x) * len(y)) * 0.5
z_axis = np.zeros(len(x)*len(y))
z_data_final = [[30, 10, 15, 20, 25], [10, 15, 15, 28, 40]]
values_min = [[5, 1, 6, 8, 3], [2, 1, 3, 9, 4]]
values_max = [[20, 45, 11, 60, 30], [11, 28, 6, 30, 40]]
cmap_max = max(values_max)
cmap_min = min(values_min)
############################### FOR 3D SCALED GRADIENT BARS ###############################
def make_bar(ax, x0=0, y0=0, width = 0.5, height=1 , cmap="plasma",
norm=cl.Normalize(vmin=0, vmax=1), **kwargs ):
# Make data
u = np.linspace(0, 2*np.pi, 4+1)+np.pi/4.
v_ = np.linspace(np.pi/4., 3./4*np.pi, 100)
v = np.linspace(0, np.pi, len(v_)+2 )
v[0] = 0 ; v[-1] = np.pi; v[1:-1] = v_
#print(u)
x = np.outer(np.cos(u), np.sin(v))
y = np.outer(np.sin(u), np.sin(v))
z = np.outer(np.ones(np.size(u)), np.cos(v))
xthr = np.sin(np.pi/4.)**2 ; zthr = np.sin(np.pi/4.)
x[x > xthr] = xthr; x[x < -xthr] = -xthr
y[y > xthr] = xthr; y[y < -xthr] = -xthr
z[z > zthr] = zthr ; z[z < -zthr] = -zthr
x *= 1./xthr*width; y *= 1./xthr*width
z += zthr
z *= height/(2.*zthr)
#translate
x += x0; y += y0
#plot
ax.plot_surface(x, y, z, cmap=cmap, norm=norm, **kwargs)
def make_bars(ax, x, y, height, width=1):
widths = np.array(width)*np.ones_like(x)
x = np.array(x).flatten()
y = np.array(y).flatten()
h = np.array(height).flatten()
w = np.array(widths).flatten()
norm = cl.Normalize(vmin=0, vmax=h.max())
for i in range(len(x.flatten())):
make_bar(ax, x0=x[i], y0=y[i], width = w[i] , height=h[i], norm=norm)
############################### FOR 3D SCALED GRADIENT BARS ###############################
# Creating graph surface
fig = plt.figure(figsize=(9,6))
ax = fig.add_subplot(111, projection= Axes3D.name)
ax.azim = 50
ax.dist = 10
ax.elev = 30
ax.invert_xaxis()
ax.set_box_aspect((1, 0.5, 1))
ax.zaxis.labelpad=7
ax.text(0.9, 2.2, 0, 'Group', 'x')
ax.text(-2, 0.7, 0, 'Class', 'y')
ax.set_xticks(x_tick_locks)
ax.set_xticklabels(x, ha='left')
ax.tick_params(axis='x', which='major', pad=-2)
ax.set_yticks(y_tick_locks)
ax.set_yticklabels(y, ha='right', rotation=30)
ax.tick_params(axis='y', which='major', pad=-5)
ax.set_zlabel('Number')
make_bars(ax, x_axis, y_axis, z_data_final, width=0.2, )
fig.colorbar(plt.cm.ScalarMappable(cmap = 'plasma'), ax = ax, shrink=0.8)
#plt.tight_layout() # doesn't seem to work properly for 3d plots?
plt.show()
As I mentioned, I don't want the colormap to be tied to the z-axis but rather a 4th dimension, which is a range. In other words, I want the colours of the colormap to range from cmap_min to cmap_max (so min is 1 and max is 60), then for the bar plot with a z_data_final entry of 30 for example, its colours should correspond with the range of 5 to 20.
Some other posts seem to provide a solution for a single 4th dimensional value, i.e. (python) plot 3d surface with colormap as 4th dimension, function of x,y,z or How to make a 4d plot using Python with matplotlib however I wasn't able to find anything specific to bar plots with a range of values as your 4th dimensional data.
I would appreciate any guidance in this matter, thanks in advance.
This is the 3D bar plot with colormap tied to the z-dimension

In Python, how do I plot a color-coded 2-D graph (X, Y, color) for inequally-spaced / random y values?

I'm plotting something similar to a spectogram. I have some 1D arrays of length N, each of which corresponds to one 'horizontal line' in a 2D graph. For a spectogram [M,N], I would need M such N-length arrays to fill all M horizontal lines.
However, I only have data for a smaller number of lines. Let's say I have m < M arrays. These don't correspond to equal-spaced values in the y axis. They're random values. For example, I might only have arrays corresponding to lines 6, 44, 44.5 and 92 (where M=4).
I want to have the y axis from 0 to 100, and plot these lines of values for only the y-values I have, and 0 otherwise. How do I do this?
If I had arrays for y values that are equally spaced on the Y axis, I can do this:
y_values = np.array(M) # ticks for y axis - equal-spaced. eg: [2, 2.5, 3, 3.5]. These are the only values for which data exists.
get_y_values(y_values)
data = np.array([M,N])
get_data(data)
fig = pyplot.figure()
vmax = np.amax(data)
ax = fig.add_subplot(1, 1, 1)
ax.imshow(data, origin='lower', aspect='auto', vmin=0, vmax=vmax)
ax.set_xlabel('Time')
ax.set_ylabel('Frequency')
ax.set_yticks(np.arange(0, y_values.size))
ax.set_yticklabels(yvalues)
pyplot.show()
But it won't work for random y-values, as they'll appear equal-spaced -when they aren't.
There are a number of ways to do this, but a quick and easy way would be to loop over each time series and plot them individually.
import numpy as np
import matplotlib.pyplot as plt
M = 4
N = 100
dy = 2.0 # The desired vertical thickness of each line
y_values = np.arange(0,100)
y_values = [6, 44, 47, 92]
x = np.arange(0, N)
data = np.random.rand(M,N)
fig = plt.figure()
vmax = np.amax(data)
ax = fig.add_subplot(1, 1, 1)
for i in range(M):
ax.pcolor(x, [y_values[i], y_values[i] + dy], [data[i],data[i]], vmin=0, vmax=vmax)
ax.set_xlabel('Time')
ax.set_ylabel('Frequency')
ax.set_yticks(y_values)
ax.set_ylim(0,100)
plt.show()
Here's a link to the output figure.
I set out to solve the problem of filling in the missing data points. This code assumes you want a list of xs from 0 to 100 and that you already have a few xs and a few corresponding ys. It then fills in the rest of the xs and sets their corresponding y values to 0. After that, it orders them by x values, zips, and prints. I figured you can adapt this from here. Hopefully, I haven't misunderstood.
current_xs = [6, 44, 44.5, 92] #the x values
current_ys = [7, 2, 45, 5] #corresponding y values I made up
def fill(current_xs, current_ys):
for i in range(0, 200):
if i/2 not in current_xs:
current_xs.append(i/2)
current_ys.append(0)
total = list(zip(current_xs, current_ys))
total = sorted(total, key=lambda x: x[0])
print(total)
fill(current_xs, current_ys)

How to plot circles with specific radiuses on the contour plot (heat map) with pyplot matplotlib

I have a waveform from an ultrasonic sensor, based on the peaks I have calculated the radiuses (object distance from the sensor) and I would like to use matplotlib to plot the radiuses on a colormap to accentuate all the possible locations for objects in the field of view of the sensor- that should result in a colormap that has circles with the calculated radiuses on it so, that the results with a bigger intensity at that radius (value) have a brighter color.
Based on measured radiuses: [ 0. 3.434 6.868 10.302]
And values: [1, 5, 1, 3]
This drawing would illustrate what I want (sorry for the bad gimp skills, these are supposed to be circles):
In real life the colourmap is supposed to be a lot more "fluctuating" with no such perfectly defined narrow circles.
Here's my code that only gives me a blank graph:
def plot_2D_heatmap(self, radiuses, values):
print(radiuses)
#[ 0. 3.434 6.868 10.302]
print(values)
#[1, 5, 1, 3]
#calculate the x and y coordinates in mm for each measured radius and angle
angles = np.linspace(0, 2*np.pi, 36) #every 10 degrees
no_of_coordinates = len(radiuses) * len(angles)
X = []
Y = []
Z = np.zeros((no_of_coordinates,no_of_coordinates))
for r in range(len(radiuses)):
for a in range(len(angles)):
x = radiuses[r] * np.cos(angles[a])
y = radiuses[r] * np.sin(angles[a])
X.append(x)
Y.append(y)
Z[a][r] = values[r]
'''
print(r)
print(a)
print(values[r])
'''
norm = cm.colors.Normalize(vmax=abs(np.array(Z)).max(), vmin=-abs(np.array(Z)).max())
fig, ax = plt.subplots()
cset1 = ax.contourf(
X, Y, Z, 4,
norm=norm)
plt.show()
And here is some code that produces kind of the result I want, but the circles are "inside out" - the centers should be (0,0) and I feel I shouldn't be doing this so "manually:
print(radiuses)
#[ 0. 3.434 6.868 10.302]
print(values)
#[1, 5, 1, 3]
#calculate the x and y coordinates in mm for each measured radius and angle
x = np.linspace(-20, 20, 40)
y = np.linspace(-20, 20, 40)
X, Y = np.meshgrid(y,x)
angles = np.linspace(0, 2*np.pi, 360) #every 1 degrees
no_of_coordinates = len(radiuses) * len(angles)
Z = np.zeros((40, 40))
for r in range(len(radiuses)):
for a in range(len(angles)):
x = radiuses[r] * np.sin(angles[a])
y = radiuses[r] * np.cos(angles[a])
x = round(x)
y = round(y)
Z[x][y] = values[r]
norm = cm.colors.Normalize(vmax=abs(np.array(Z)).max(), vmin=-abs(np.array(Z)).max())
fig, ax = plt.subplots()
print(X)
print(Y)
print(Z)
cset1 = ax.contourf(
X, Y, Z, [1, 2],
norm=norm)
plt.colorbar(cset1)
plt.show()
Your Z represents the plot but does not use the same coordinates as the plot. In other words, (0, 0) on the plot is actually about Z[20, 20]. Key changes when looping through Z should be:
x = int(round(x)) + 20
y = int(round(y)) + 20
Just to be clear, I made a few minor changes to your code so that it can run without errors and give what you've shown. In the end, key changes give the following plot, which is hopefully what you want.

Specify color of each point in scatter plot (matplotlib)

I have a 3D Plot that I created using matplotlib, and I have a list of rbg values that correspond to each point.
I have the X, Y, and Z data, and then I have a "color list" of the form:
[ (r,g,b), (r,g,b), ... , (r,g,b) ]
to match each (x, y, z) point.
Right now, I have
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
ax.scatter(X, Y, Z)
plt.show()
What's the appropriate way to incorporate those rgb tuples so that each point will be assigned a specific color?
If you don't want to use a for loop (which can be very slow for large lists) You can use the scatter command as is with an RGB color list, but you need to specify the colors as a vector of RGB (or RGBA) values between 0 and 1
X = [0, 1, 2]
Y = [0, 1, 2]
Z = [0, 1, 2]
C = np.array([[255, 0, 0], [0, 255, 0], [0, 0, 255]])
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
ax.scatter(X, Y, Z, c = C/255.0)
plt.show()
Here is an example where the colors are calculated instead of specified by a literal list.
import matplotlib.pyplot as plt
import numpy as np
phi = np.linspace(0, 2*np.pi, 60)
x = np.sin(phi)
y = np.cos(phi)
rgb_cycle = np.vstack(( # Three sinusoids
.5*(1.+np.cos(phi )), # scaled to [0,1]
.5*(1.+np.cos(phi+2*np.pi/3)), # 120° phase shifted.
.5*(1.+np.cos(phi-2*np.pi/3)))).T # Shape = (60,3)
fig, ax = plt.subplots(figsize=(3,3))
ax.scatter(x,y, c=rgb_cycle, s=90)
fig.show()
I used a for loop to individually assign each color to each point. Here is my code:
X = [1, 2, 3]
Y = [2, 5, 8]
Z = [6, 4, 5]
colors=["#0000FF", "#00FF00", "#FF0066"]
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
for i in range(len(X)):
ax.scatter(X[i], Y[i], Z[i], color=colors[i])
plt.show()
The for loop goes point by point (hence the [i] in front of each X,Y,Z value) and gives a color one by one. I used hex colors for my example, but you could probably use something else if you wanted.

How to correctly generate a 3d histogram using numpy or matplotlib built in functions in python?

This is more of a general question about 3d histogram creation in python.
I have attempted to create a 3d histogram using the X and Y arrays in the following code
import matplotlib
import pylab
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
from matplotlib import cm
def threedhist():
X = [1, 3, 5, 8, 6, 7, 1, 2, 4, 5]
Y = [3, 4, 3, 6, 5, 3, 1, 2, 3, 8]
fig = pylab.figure()
ax = Axes3D(fig)
ax.hist([X, Y], bins=10, range=[[0, 10], [0, 10]])
plt.xlabel('X')
plt.ylabel('Y')
plt.zlabel('Frequency')
plt.title('Histogram')
plt.show()
However, I am getting the following error
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
a3dhistogram()
File "C:/Users/ckiser/Desktop/Projects/Tom/Python Files/threedhistogram.py", line 24, in a3dhistogram
ax.hist([X, Y], bins=10, range=[[0, 10], [0, 10]])
File "C:\Python27\lib\site-packages\matplotlib\axes.py", line 7668, in hist
m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs)
File "C:\Python27\lib\site-packages\numpy\lib\function_base.py", line 169, in histogram
mn, mx = [mi+0.0 for mi in range]
TypeError: can only concatenate list (not "float") to list
I have tried the code with and without the "[" in the line
ax.hist([X, Y], bins=10, range=[[0, 10], [0, 10]])
I have also tried the function from numpy without success
H, xedges, yedges = np.histogram2d(x, y, bins = (10, 10))
Am I missing a step or a parameter? Any advice would be greatly appreciated.
I posted this in a related thread about colored 3d bar plots, but I think it's also relevant here as I couldn't find a complete answer for what I needed in either thread. This code generates a histogram scatterplot for any sort of x-y data. The height represents the frequency of values in that bin. So, for example, if you had many data point where (x,y) = (20,20) it would be high and red. If you had few data points in the bin where (x,y) = (100,100) it would be low and blue.
Note: result will vary substantially depending on how much data you have and how many bins your choose for you histogram. Adjust accordingly!
xAmplitudes = #your data here
yAmplitudes = #your other data here
x = np.array(xAmplitudes) #turn x,y data into numpy arrays
y = np.array(yAmplitudes)
fig = plt.figure() #create a canvas, tell matplotlib it's 3d
ax = fig.add_subplot(111, projection='3d')
#make histogram stuff - set bins - I choose 20x20 because I have a lot of data
hist, xedges, yedges = np.histogram2d(x, y, bins=(20,20))
xpos, ypos = np.meshgrid(xedges[:-1]+xedges[1:], yedges[:-1]+yedges[1:])
xpos = xpos.flatten()/2.
ypos = ypos.flatten()/2.
zpos = np.zeros_like (xpos)
dx = xedges [1] - xedges [0]
dy = yedges [1] - yedges [0]
dz = hist.flatten()
cmap = cm.get_cmap('jet') # Get desired colormap - you can change this!
max_height = np.max(dz) # get range of colorbars so we can normalize
min_height = np.min(dz)
# scale each z to [0,1], and get their rgb values
rgba = [cmap((k-min_height)/max_height) for k in dz]
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=rgba, zsort='average')
plt.title("X vs. Y Amplitudes for ____ Data")
plt.xlabel("My X data source")
plt.ylabel("My Y data source")
plt.savefig("Your_title_goes_here")
plt.show()
The results for about 75k data points of mine are below. Note, you can drag and drop to different perspectives and may want to save multiple views for presentations, posterity.
Have a look at
https://matplotlib.org/stable/gallery/mplot3d/hist3d.html, this has a working example script.
I've improved the code at that link to be more of a histogram:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = [1, 3, 5, 8, 6, 7, 1, 2, 4, 5]
y = [3, 4, 3, 6, 5, 3, 1, 2, 3, 8]
hist, xedges, yedges = np.histogram2d(x, y, bins=(4,4))
xpos, ypos = np.meshgrid(xedges[:-1]+xedges[1:], yedges[:-1]+yedges[1:])
xpos = xpos.flatten()/2.
ypos = ypos.flatten()/2.
zpos = np.zeros_like (xpos)
dx = xedges [1] - xedges [0]
dy = yedges [1] - yedges [0]
dz = hist.flatten()
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b', zsort='average')
plt.xlabel ("X")
plt.ylabel ("Y")
plt.show()
I'm not sure how to do it with Axes3D.hist ().
In this answer there is a solution for 2D and 3D Histograms of scattered points. The usage is simple:
points, sub = hist2d_scatter( radius, density, bins=4 )
points, sub = hist3d_scatter( temperature, density, radius, bins=4 )
Where sub is a matplotlib "Subplot" instance (3D or not) and pointscontains the points used for the scatter plot.
I've added to #lxop's answer to allow for arbitrary size buckets:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.array([0, 2, 5, 10, 2, 3, 5, 2, 8, 10, 11])
y = np.array([0, 2, 5, 10, 6, 4, 2, 2, 5, 10, 11])
# This example actually counts the number of unique elements.
binsOne = sorted(set(x))
binsTwo = sorted(set(y))
# Just change binsOne and binsTwo to lists.
hist, xedges, yedges = np.histogram2d(x, y, bins=[binsOne, binsTwo])
# The start of each bucket.
xpos, ypos = np.meshgrid(xedges[:-1], yedges[:-1])
xpos = xpos.flatten()
ypos = ypos.flatten()
zpos = np.zeros_like(xpos)
# The width of each bucket.
dx, dy = np.meshgrid(xedges[1:] - xedges[:-1], yedges[1:] - yedges[:-1])
dx = dx.flatten()
dy = dy.flatten()
dz = hist.flatten()
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b', zsort='average')

Categories