Griff
Griff

Reputation: 2124

Create a stacked 2D histogram using different weights

Say I want to build up histogram of particle data which is smoothed over some bin range, nbin. Now I have 5 data sets with particles of different mass (each set of x,y has a different mass). Ordinarily, a histogram of particle positions is a simple case (using numpy):

heatmap, xedges, yedges = np.histogram2d(x, y, bins=nbin)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
heatmap = np.flipud(np.rot90(heatmap))
ax.imshow(heatmap, extent=extent)

However, if I want to add the next lot of particles, they have different masses and so the density will be different. Is there a way to weight the histogram by some constant such that the plotted heatmap will be a true representation of the density rather than just a binning of the total number of particles?

I know 'weights' is a feature, but is it a case of just setting weights = m_i where m_i is the mass of the particle for each dataset 1-5?

Upvotes: 5

Views: 4571

Answers (1)

unutbu
unutbu

Reputation: 880329

The weights parameter expects an array of the same length as x and y. np.histogram2d. It will not broadcast a constant value, so even though the mass is the same for each call to np.histogram2d, you still must use something like

weights=np.ones_like(x)*mass

Now, one problem you may run into if you use bin=nbin is that the bin edges, xedges, yedges may change depending on the values of x and y that you pass to np.histogram2d. If you naively add heatmaps together, the final result will accumulate particle density in the wrong places.

So if you want to call np.histogram2d more than once and add partial heatmaps together, you must determine in advance where you want the bin edges.

For example:

import numpy as np
import itertools as IT
import matplotlib.pyplot as plt
N = 50
nbin = 10

xs = [np.array([i,i,i+1,i+1]) for i in range(N)]
ys = [np.array([i,i+1,i,i+1]) for i in range(N)]
masses = np.arange(N)

heatmap = 0
xedges = np.linspace(0, N, nbin)
yedges = np.linspace(0, N, nbin)

for x, y, mass in IT.izip(xs, ys, masses):
    hist, xedges, yedges = np.histogram2d(
        x, y, bins=[xedges, yedges], weights=np.ones_like(x)*mass)
    heatmap += hist

extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
heatmap = np.flipud(np.rot90(heatmap))
fig, ax = plt.subplots()
ax.imshow(heatmap, extent=extent, interpolation='nearest')
plt.show()

yields

enter image description here

Upvotes: 5

Related Questions