问题描述
我正在尝试从这种类型的数据框在一个具有不同高度,宽度和中心的绘图上绘制多个高斯:
24.122348 | 1.827472 | 98 |
24.828252 | 4.333549 | 186 |
26.810812 | 1.728494 | 276 |
25.997897 | 1.882424 | 373 |
24.503944 | 2.222210 | 471 |
27.488572 | 1.750039 | 604 |
31.556823 | 3.844592 | 683 |
27.920951 | 0.891394 | 792 |
27.009054 | 1.917744 | 897 |
有什么想法吗?
我们将重复使用
中定义的高斯绘图仪-
编辑
由于问题现在要求使用不同的分布,因此可以使用以下方法在
create
(和create
)方法中调整代码,以获取不同类型的分布:def create(self,dim = 1,fwhm = 3,center = None):"在一定宽度的中心上生成高斯分布."中心=中心,如果中心不是其他则self.center [:dim]distance = sum((ax_center的ax(ax -ax_center),zip中的ax(center,self.axis))分布= sps.beta.pdf(距离/最大(距离),a = 3,b = 100)收益分配
sps.beta
来自import scipy.stats as sps
,并且也可以通过伽马分布进行更改.例如distribution = sps.gamma.pdf(distance,10,40)
.请注意,距离不再是平方,并且可以将参数
fwhm
替换为分布所需的参数.I am trying to plot multiple gaussians on one plot with different heights, widths and centers from this type of dataframe:
24.122348 1.827472 98 24.828252 4.333549 186 26.810812 1.728494 276 25.997897 1.882424 373 24.503944 2.222210 471 27.488572 1.750039 604 31.556823 3.844592 683 27.920951 0.891394 792 27.009054 1.917744 897 Any idea on how to go about it?
解决方案We will reuse the Gaussian plotter as defined in
(The code is repeated here)
Data
The following code generates the above dataframe.
data = [ (24.122348, 1.827472, 98), (24.828252, 4.333549, 186), (26.810812, 1.728494, 276), (25.997897, 1.882424, 373), (24.503944, 2.222210, 471), (27.488572, 1.750039, 604), (31.556823, 3.844592, 683), (27.920951, 0.891394, 792), (27.009054, 1.917744, 897), ] df = pd.DataFrame(data, columns=["height", "fwhm", "center"])
Gaussian
Taken from the reference post above.
import matplotlib.cm as mpl_cm import matplotlib.colors as mpl_colors import matplotlib.pyplot as plt import numpy as np from scipy.spatial.distance import cdist class Gaussian: def __init__(self, size): self.size = size self.center = np.array(self.size) / 2 self.axis = self._calculate_axis() def _calculate_axis(self): """ Generate a list of rows, columns over multiple axis. Example: Input: size=(5, 3) Output: [array([0, 1, 2, 3, 4]), array([[0], [1], [2]])] """ axis = [np.arange(size).reshape(-1, *np.ones(idx, dtype=np.uint8)) for idx, size in enumerate(self.size)] return axis def update_size(self, size): """ Update the size and calculate new centers and axis. """ self.size = size self.center = np.array(self.size) / 2 self.axis = self._calculate_axis() def create(self, dim=1, fwhm=3, center=None): """ Generate a gaussian distribution on the center of a certain width. """ center = center if center is not None else self.center[:dim] distance = sum((ax - ax_center) ** 2 for ax_center, ax in zip(center, self.axis)) distribution = np.exp(-4 * np.log(2) * distance / fwhm ** 2) return distribution def creates(self, dim=2, fwhm=3, centers: np.ndarray = None): """ Combines multiple gaussian distributions based on multiple centers. """ centers = np.array(centers or np.array([self.center]).T).T indices = np.indices(self.size).reshape(dim, -1).T distance = np.min(cdist(indices, centers, metric='euclidean'), axis=1) distance = np.power(distance.reshape(self.size), 2) distribution = np.exp(-4 * np.log(2) * distance / fwhm ** 2) return distribution @staticmethod def plot(distribution, show=True): """ Plotter, in case you do not know the dimensions of your distribution, or want the same interface. """ if len(distribution.shape) == 1: return Gaussian.plot1d(distribution, show) if len(distribution.shape) == 2: return Gaussian.plot2d(distribution, show) if len(distribution.shape) == 3: return Gaussian.plot3d(distribution, show) raise ValueError(f"Trying to plot {len(distribution.shape)}-dimensional data, " f"Only 1D, 2D, and 3D distributions are valid.") @staticmethod def plot1d(distribution, show=True, vmin=None, vmax=None, cmap=None): norm = mpl_colors.Normalize( vmin=vmin if vmin is not None else distribution.min(), vmax=vmax if vmin is not None else distribution.max() ) cmap = mpl_cm.ScalarMappable(norm=norm, cmap=cmap or mpl_cm.get_cmap('jet')) cmap.set_array(distribution) c = [cmap.to_rgba(value) for value in distribution] # defines the color fig, ax = plt.subplots() ax.scatter(np.arange(len(distribution)), distribution, c=c) ax.plot(distribution) fig.colorbar(cmap) if show: plt.show() return fig @staticmethod def plot2d(distribution, show=True): fig, ax = plt.subplots() img = ax.imshow(distribution, cmap='jet') fig.colorbar(img) if show: plt.show() return fig @staticmethod def plot3d(distribution, show=True): m, n, c = distribution.shape x, y, z = np.mgrid[:m, :n, :c] out = np.column_stack((x.ravel(), y.ravel(), z.ravel(), distribution.ravel())) x, y, z, values = np.array(list(zip(*out))) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # Standalone colorbar, directly creating colorbar on fig results in strange artifacts. img = ax.scatter([0, 0], [0, 0], [0, 0], c=[0, 1], cmap=mpl_cm.get_cmap('jet')) img.set_visible = False fig.colorbar(img) ax.scatter(x, y, z, c=values, cmap=mpl_cm.get_cmap('jet')) if show: plt.show() return fig
Solution
Since it is unclear to me how you want to the Gaussian distributions to interact when they are in part of multiple widths, I will assume that you want the maximum value.
Then the main logic is that we can now generate a unique Gaussian distribution for every center with given full width half maximum (fwhm), and take the maximum of all the distrubutions.
distribution = np.zeros((1200,)) df = pd.DataFrame(data, columns=["height", "fwhm", "center"]) gaussian = Gaussian(size=distribution.shape) for idx, row in df.iterrows(): distribution = np.maximum(distribution, gaussian.create(fwhm=row.fwhm, center=[row.center])) gaussian.plot(distribution, show=True)
Result
Edit
Since the question now asks for a different distribution, you can adjust the code in the
create
(andcreates
) method with the following to get different types of distributions:def create(self, dim=1, fwhm=3, center=None): """ Generate a gaussian distribution on the center of a certain width. """ center = center if center is not None else self.center[:dim] distance = sum((ax - ax_center) for ax_center, ax in zip(center, self.axis)) distribution = sps.beta.pdf(distance / max(distance), a=3, b=100) return distribution
Where
sps.beta
comes fromimport scipy.stats as sps
, and can be changed with a gamma distribution as well. e.g.distribution = sps.gamma.pdf(distance, 10, 40)
.Note that the distance is no longer squared, and that the argument
fwhm
, could be replaced by the parameters required for the distribution.这篇关于从 pandas 文件中绘制多个高斯的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!