本文介绍了从 pandas 文件中绘制多个高斯的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从这种类型的数据框在一个具有不同高度,宽度和中心的绘图上绘制多个高斯:

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.1223481.82747298
    24.8282524.333549186
    26.8108121.728494276
    25.9978971.882424373
    24.5039442.222210471
    27.4885721.750039604
    31.5568233.844592683
    27.9209510.891394792
    27.0090541.917744897

    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 (and creates) 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 from import 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 文件中绘制多个高斯的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 05:45