Как регрессировать несколько гауссовских пиков из спектрограммы с помощью scipy?

У меня есть код, который предназначен для размещения данных здесь DriveFilelink

Функция read_file используется для структурированного извлечения информации. Однако я сталкиваюсь с проблемами при подгонке по Гауссу, о чем свидетельствуют несоответствия, наблюдаемые в изображении подгонки по Гауссу . Эта проблема, по-видимому, связана с ограничениями, налагаемыми на определенные параметры, например, фиксирование среднего значения всех гауссиан и трех из четырех амплитуд. Несмотря на эти ограничения, они необходимы, поскольку основаны на доступной информации.

Кто-нибудь знает, как я могу решить эту проблему? Чтобы лучше приспособиться.

Код следующий:

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
from scipy.optimize import curve_fit
from google.colab import drive
import os
# Mount Google Drive
drive.mount('/content/drive')


# Function to read numeric data from a file
def read_numeric_data(file_path):
    with open(file_path, 'r', encoding='latin1') as f:
        data = []
        live_time = None
        real_time = None
        for line in f:
            if 'LIVE_TIME' in line:
                live_time = line.strip()
            elif 'REAL_TIME' in line:
                real_time = line.strip()
            elif all(char.isdigit() or char in ".-+e" for char in line.strip()):
                row = [float(x) for x in line.split()]
                data.extend(row)
    return np.array(data), live_time, real_time



file_path = '/content/drive/MyDrive/ProjetoXRF_Manuel/April2024/20240402_In.mca'
data, _, _ = read_numeric_data(file_path)

a = -0.0188026396003431
b = 0.039549044037714
Data = data





# Función para convolucionar múltiples gaussianas
def multi_gaussian(x, *params):
    
    eps = 1e-10
    y = np.zeros_like(x)
    amplitude_relations = [1,0.5538, 0.1673 , 0.1673*0.5185 ]
    meanvalues= [24.210, 24.002 , 27.276 , 27.238]
    amplitude = params[0]

    for i in range(4):
        sigma = params[i * 3 + 2]  # Get the fitted standard deviation for this Gaussian
        
        y += amplitude*amplitude_relations[i]* np.exp(-(x - meanvalues[i])**2 / (2 * sigma**2 + eps))
    return y


sigma=[]
area=[]

# Función para graficar el espectro de energía convolucionado
def plot_convolved_spectrum(Data, a, b,i, ax=None):

    maxim = np.max(Data)
    workingarray = np.squeeze(Data)

    # Definir puntos máximos
    peaks, _ = find_peaks(workingarray / maxim, height=0.1)
    peak_values = workingarray[peaks] / maxim
    peak_indices = peaks

    # Calcular valores de energía correspondientes a los picos
    energy_spectrum = a + b * peak_indices

    # Preparar datos para convolución
    data = workingarray[:885] / maxim
    data_y = data / data.max()
    data_x = a + b * np.linspace(0, 885, num=len(data_y))

    # Ajustar múltiples gaussianas al espectro de energía
    peak_indices2, _ = find_peaks(data_y, height=0.1)
    peak_amplitudes = [1,0.5538, 0.1673 , 0.1673*0.5185 ]
    peak_means = [24.210, 24.002 , 27.276 , 27.238]
    peak_sigmas = [0.1] * 4

    params_init = list(zip(peak_amplitudes, peak_means, peak_sigmas))
    params_init = np.concatenate(params_init)

    # Ajustar curva
    params, params_cov = curve_fit(multi_gaussian, data_x, data_y, p0=params_init)

    # Obtener una interpolación de alta resolución del ajuste
    x_fine = np.linspace(data_x.min(), data_x.max(), num=20000)

    y_fit = multi_gaussian(x_fine, *params)

    #  Data Graphic
    ax.scatter(data_x, data_y, color='black', marker='o', s=20, label = 'Data' )
    y_data_error =np.sqrt(workingarray[:885])
    ax.plot(data_x, data_y + y_data_error/maxim, color='black',linestyle='--')
    ax.plot(data_x, data_y - y_data_error/maxim, color='black',linestyle='--')
    # Fit Graphic

    ax.plot(x_fine, y_fit, label = "Fit", linewidth=1.5)



    # Extraer desviaciones estándar y amplitudes
    sigmas_array = params[2::3]
    # Calcular sigma promedio
    sigma.append(np.mean(sigmas_array))

    # Configuración del gráfico
    ax.set_xlabel('Energy (KeV)')
    ax.set_ylabel('Normalized Data')
    ax.legend()
    ax.set_title('Convolved Energy Spectrum')

    # Imprimir información
    print("Standard deviations:", sigmas_array)






fig, ax = plt.subplots()
plot_convolved_spectrum(Data, a, b,1,ax=ax)
ax.set_xlim(22, 28)
plt.show()

Примечание Я экспериментировал с установкой границ и уточнением первоначальных предположений, чтобы улучшить соответствие Гаусса. Однако важно отметить, что работа с границами не эквивалентна исправлению параметров. Моя цель — сохранить степень свободы всего двух параметров: амплитуды первой гауссианы и стандартного отклонения всех гауссиан. Изучая эти настройки, я стремлюсь найти баланс между ограничениями и гибкостью для достижения желаемой точности подгонки.

Примечание Это модель:

Параметры функции Гаусса определяются следующим образом: A представляет амплитуду, x_0 обозначает среднее значение, а сигма представляет собой стандартное отклонение. В контексте анализа энергетических спектров я обладаю предварительными знаниями о средних значениях и отношениях, определяющих амплитуды. Следовательно, я стремлюсь ограничить определенные параметры (такие как A и среднее значение) на основе этой известной информации. В частности, я намерен подогнать только первую амплитуду, а затем использовать известные соотношения, например A2 = 0,1673 * A1 для второго пика. И чтобы соответствовать соответствующему стандартному отклонению.

Зачем использовать сумму гауссиан?

Очевидная сингулярность первого пика на графике может указывать на наличие единственного гауссиана. Однако, это не так. Гауссиан, представляющий этот энергетический пик, на самом деле состоит из двух гауссиан, которые суммируются. Эта сложность возникает потому, что выброс энергии на этом уровне включает два разных значения: 24,002 и 24,210. И из-за разрешающей способности эксперимента мы не можем их отличить, просто увидев сюжет.

И по всем этим причинам я пытаюсь исправить некоторые параметры.

Если у кого-то есть проблемы с данными, вот они:

извлеченный data.txt

Сумма гауссиан известна как «модель гауссовой смеси». Здесь много глубокой теории, и вы можете быстро получить MLE с помощью алгоритмов максимизации ожидания. Наверное, лучше не реализовывать самостоятельно, используйте sklearn

Him 26.04.2024 15:17
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вот MCVE, показывающий, как регрессировать переменное количество пиков из значительной части вашего сигнала.

import itertools
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import signal, stats, optimize

Мы загружаем вам данные и подвергаем их постобработке, чтобы получить физические ряды:

data = pd.read_csv("20240402_In.mca", encoding = "latin-1", names=["y"]).loc[12:2058]
data["y"] = pd.to_numeric(data["y"])
data["y"] /= data["y"].max()
data["x"] = -0.0188026396003431 + 0.039549044037714 * data.index

data = data.loc[(20. <= data["x"]) & (data["x"] <= 30.), :]

Мы создаем модель, которая принимает переменное количество пиков (определяется решением find_peaks):

def peak(x, A, s, x0):
    law = stats.norm(loc=x0, scale=s)
    return A * law.pdf(x) / law.pdf(x0)

def model(x, *parameters):
    n = len(parameters) // 3
    y = np.zeros_like(x)
    for i in range(n):
        y += peak(x, *parameters[(i * 3):((i + 1) * 3)])
    return y

Выявляем вершины:

indices, bases = signal.find_peaks(data.y, prominence=0.0125)
#(array([ 67, 118, 195, 210]),
# {'prominences': array([0.01987281, 0.99920509, 0.18918919, 0.03338633]),
#  'left_bases': array([  1,   1, 179, 205]),
#  'right_bases': array([ 76, 160, 219, 219])})

Это ключевой момент: на основе идентификации мы создаем обоснованное предположение:

x0s = data.x.values[indices]
As = bases["prominences"]
ss = (data.x.values[bases["right_bases"]] - data.x.values[bases["left_bases"]]) / 8.
p0 = list(itertools.chain(*zip(As, ss, x0s)))
#[0.01987281399046105,
# 0.37077228785356864,
# 22.682348638047493,
# 0.9992050874403816,
# 0.7860372502495658,
# 24.699349883970907,
# 0.1891891891891892,
# 0.19774522018856988,
# 27.744626274874886,
# 0.033386327503974564,
# 0.06921082706599968,
# 28.337861935440593]

Теперь мы регрессируем модель относительно вашего набора данных:

popt, pcov = optimize.curve_fit(model, data.x, data.y, p0=p0)
#array([1.03735804e-02, 9.61270732e-01, 2.29030214e+01, 9.92651381e-01,
#   1.59694755e-01, 2.46561911e+01, 1.85332645e-01, 1.21882422e-01,
#   2.77807838e+01, 3.67805911e-02, 1.21890416e-01, 2.83583849e+01])

Теперь мы можем оценить модель:

yhat = model(data.x, *popt)

Графически это приводит к:

Это вполне удовлетворительно для неограниченной подгонки, но определенно не соответствует ограничениям, которые вы хотите обеспечить.

Не могли бы вы опубликовать в своем посте свои данные, готовые для кодирования, в виде массивов?

Я признаю, что ваш код удовлетворительно подходит и решает некоторые аспекты проблемы. Однако это достигается без использования аппроксимации по Гауссу или ограничения переменных, которые были центральными в моей первоначальной концепции. Свертка гауссовских аппроксимаций является подходящей моделью для этого набора данных, поскольку это энергетический спектр. Спасибо за ваш ответ. Возможно, мы сможем придумать, как решить проблему использования ограничений для аппроксимации по Гауссу.

Manuel Borra 26.04.2024 13:15

Добро пожаловать в СО. Подогнанные пики, безусловно, являются гауссовыми (см. документацию, чтобы убедиться в этом). Не могли бы вы обновить свой пост, указав формулу точной модели, которую вы ожидаете, в основном то, что вы подразумеваете под сверткой в ​​​​вашем контексте (я не вижу никакого оператора свертки в предоставленном вами коде). Тогда нам не придется копаться в коде, чтобы понять, чего вы пытаетесь достичь. Это определенно помогло бы.

jlandercy 26.04.2024 13:26

Также не могли бы вы подтвердить, что четыре пика, показанные в ответе, являются именно теми пиками, которые вас интересуют. В вашем вопросе дополнительно подчеркивается, как ограничения должны быть добавлены в вашу модель.

jlandercy 26.04.2024 13:37

Чтобы уточнить, аппроксимация кривой на самом деле включает в себя сумму гауссиан, а не свернутую аппроксимацию Гаусса. Спасибо, что подняли этот вопрос. Я бы выложил модель. Насколько я понимаю, предоставленное вами решение не использует функции Гаусса, верно? Возможно, я ошибаюсь, но я так это истолковал. И еще раз спасибо за ответ

Manuel Borra 26.04.2024 13:43

Нет, модель, которую вы видите, включает в себя сумму Гаусса с небольшой разницей в том, как вычисляется A. Я просто использую удобство scipy для их вычисления, поскольку я не справлюсь лучше, чем библиотека. То, что вы просите об ограничении, важно, поскольку оно изменит стратегию решения этой проблемы. На первый взгляд вы можете проверить регрессированные параметры и выполнить с ними некоторые арифметические действия, чтобы проверить, являются ли они допустимыми параметрами в пределах ошибок (матрица отклонений).

jlandercy 26.04.2024 13:53

Я так и сделаю, добавил в пост дополнительную информацию, скажите, теперь будет легче понять.

Manuel Borra 26.04.2024 14:01

Таким образом, большой заметный пик представляет собой сумму двух гауссовских значений с очень близкими значениями x0. И два последующих пика справа зависят от двух первых. Вот почему у вас есть 4 пика для регресса, и мы можем забыть о маленьком слева. Я правильно понимаю?

jlandercy 26.04.2024 14:04

Да, это верно, и насколько близко расположены x_0, одинаково для двух других пиков. Как вы можете видеть по средним значениям. А это амплитуды и средние значения. Таким образом, фиксированные значения будут всеми средствами и этими отношениями [0,5538, 0,1673, 0,1673*0,5185]. Это будет умножено на подобранную амплитуду первого пика.

Manuel Borra 26.04.2024 14:08

Мммм, кажется, данные, которые у меня есть, не проходят мимо x0, который вы хотите использовать в качестве ограничений. Не могли бы вы опубликовать в своем сообщении именно то подмножество, которое вы хотите разместить, правильно масштабированное как массив x и y.

jlandercy 26.04.2024 14:30

Извините, я не понял эту часть: кажется, мои данные не проходят мимо x0. Вы имеете в виду, что экспериментальные значения не совпадают с теоретическими? Обратите внимание, что для значений 24,002 и 27,238 данные не предоставляют этой информации, поскольку разрешение эксперимента не позволяет различить эти пики.

Manuel Borra 26.04.2024 14:39

Мы должны быть уверены, что работаем с одним и тем же набором данных. Моя версия масштабированного ряда из вашего файла не проходит мимо х0. Поэтому мы не работаем с одними и теми же данными. Не могли бы вы опубликовать свой набор данных, отфильтрованный и масштабированный, в виде кода в своем сообщении. Смотрите мой ответ, отредактируйте.

jlandercy 26.04.2024 14:42

Я уверен, что мы работаем с одними и теми же данными.

Manuel Borra 26.04.2024 14:46

Аааа теперь я понимаю. Первая часть моего кода предназначена для этого. Если вы знаете, в каком каталоге вы работаете, функция read_numeric_data выдает на выходе данные в виде массива. Но я могу добавить в сообщение массив из 2048 значений. Я не знаю, будет ли так же ясно, как работать с функцией, которая призвана делать это автоматически.

Manuel Borra 26.04.2024 14:49

Я уверен, что нет, просто потому, что мы анализируем необработанный файл по-другому. Поэтому, пожалуйста, просто обновите свой пост, указав именно тот набор данных, который вы хотите разместить в виде массивов в коде.

jlandercy 26.04.2024 14:49

я только что добавил текстовый файл с извлеченными данными. Но это то, что есть: я ничего не меняю в числовых значениях, когда извлекаю их с помощью функции read:numeric.

Manuel Borra 26.04.2024 15:10

На данный момент это самый эффективный метод фиксации параметров в Python, который я обнаружил. В этом случае я использую тот же набор данных, что и раньше. Однако я подгоняю параметры только для первого гауссиана, не учитывая тот факт, что на самом деле это комбинация двух гауссиан.

Я разделил оценку на две части: приблизительную и уточненную. Уточненная аппроксимация ограничивает данные в пределах ±3 сигмы, поскольку она имеет тенденцию давать лучшую производительность.

import numpy as np
import matplotlib.pyplot as plt
from lmfit import Model
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes


# Define the Gaussian function
def gaussian(x, amplitude, mean, stddev):
    return amplitude * np.exp(-((x - mean) / stddev)**2 / 2)

# Data that is going to be analysed

x_data= a + b * np.linspace(0, 885, 885)
y_data =data[:885]/np.max(data[:885])


#### Bounds for the first gaussian

# Define bounds for the parameters
bounds = ([0, 24.21, 0], [1, 24.22, 2])
y_data_error =np.sqrt(data[:885])/np.max(data[:885])
# Fit the data to the Gaussian function with bounds
params, covariance = curve_fit(gaussian, x_data, y_data, bounds=bounds)

# Create the model
gaussian_model = Model(gaussian)

# Create parameters with initial values
A_value = 1.0  # Initial value for amplitude
mu_value = 24.21  # Initial value for mean
sigma_value = 1.0  # Initial value for standard deviation
params = gaussian_model.make_params(amplitude=A_value, mean=mu_value, stddev=sigma_value)

# Fix amplitude and mean
#params['amplitude'].vary = False
params['mean'].vary = False

# Fit the model to the data
result = gaussian_model.fit(y_data, params, x=x_data)

# Extract the parameters
amplitude = result.params['amplitude'].value
mean = result.params['mean'].value
stddev = result.params['stddev'].value

# Data interpolation
x_fine = np.linspace(x_data.min(), x_data.max(), num=1000)
y_fit= result.eval(x=x_fine)

ylower_limit = ( (24.21  - 3 * stddev)-a )/b
yupper_limit = ( (24.21  + 3 * stddev)-a )/b

# Selecciona los valores dentro del intervalo

y_limitado = y_data[int(ylower_limit):int(yupper_limit)]

x_limitado = a + b*np.linspace(int(ylower_limit), int(yupper_limit), 24)

ylimit_error=np.sqrt(data[int(ylower_limit):int(yupper_limit)])/np.max(data[int(ylower_limit):int(yupper_limit)])


params1, covariance1 = curve_fit(gaussian, x_limitado, y_limitado, bounds=bounds)

# Create the model
gaussian_model = Model(gaussian)

# Create parameters with initial values
A_value1 = 1.0  # Initial value for amplitude
mu_value1 = 24.21  # Initial value for mean
sigma_value1 = 1.0  # Initial value for standard deviation
params1 = gaussian_model.make_params(amplitude=A_value1, mean=mu_value1, stddev=sigma_value1,sigma=ylimit_error)

# Fix amplitude and mean
#params['amplitude'].vary = False
params1['mean'].vary = False

# Fit the model to the data
result1 = gaussian_model.fit(y_limitado, params1, x=x_limitado)

# Extract the parameters
amplitude1 = result1.params['amplitude'].value
mean1 = result1.params['mean'].value
stddev1 = result1.params['stddev'].value


# Data interpolation
x_fine1 = np.linspace(x_limitado.min(), x_limitado.max(), num=1000)
y_fit1 = result1.eval(x=x_fine1)


fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(x_limitado,y_limitado, color='black', marker='o')
ax.plot(x_fine1,y_fit1,color='blue')
ax.plot(x_fine,y_fit,color='green')

ax.errorbar(x_limitado,y_limitado,yerr=ylimit_error, fmt='o', color='red', label='errorbar')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('Gaussian Fit to Data')
ax.set_xlim((24.21  - 3 * stddev, 24.21  + 3 * stddev))
ax.legend()
ax.grid(True)
plt.show()


print("Amplitude:", amplitude)
print("Mean:", mean)
print("Standard Deviation:", stddev)
print("Amplitude:", amplitude1)
print("Mean:", mean1)
print("Standard Deviation:", stddev1)

Редактировать

Теперь у меня есть возможность зафиксировать больше параметров, что позволяет мне точно настроить подгонку суммы первых двух гауссиан. Однако меня озадачивает наличие дополнительного пика в посадке. Я не уверен в его происхождении.

import numpy as np
import matplotlib.pyplot as plt
from lmfit import Model
from scipy.optimize import curve_fit

# Define Gaussian function
def gaussian(x, amplitude, mean, stddev):
    return amplitude * np.exp(-((x - mean) / stddev)**2 / 2)

# Generate x values for the data
x_data = a + b * np.linspace(0, 885, 885)

# Normalize y data
y_data = data[:885] / np.max(data[:885])
y_data_error = np.sqrt(data[:885]) / np.max(data[:885])

# Fit first Gaussian
bounds = ([1 - 0.0001, 24.21, 0], [1, 24.22, 2])  # Define bounds for the parameters
params, covariance = curve_fit(gaussian, x_data, y_data, bounds=bounds)  # Fit Gaussian to data

# Create the model
gaussian_model = Model(gaussian)

# Initial values for parameters
A_value = 1.0
mu_value = 24.21
sigma_value = 1.0
params = gaussian_model.make_params(amplitude=A_value, mean=mu_value, stddev=sigma_value)
params['mean'].vary = False  # Fix mean parameter

# Fit the model to the data
result = gaussian_model.fit(y_data, params, x=x_data)

# Extract parameters
amplitude = result.params['amplitude'].value
mean = result.params['mean'].value
stddev = result.params['stddev'].value

# Data interpolation
x_fine = np.linspace(x_data.min(), x_data.max(), num=1000)
y_fit = result.eval(x=x_fine)

# Determine y limits for data subset
ylower_limit = ((24.21 - 3 * stddev) - a) / b
yupper_limit = ((24.21 + 3 * stddev) - a) / b

# Select subset of data within the limits
y_limitado = y_data[int(ylower_limit):int(yupper_limit)]
x_limitado = a + b * np.linspace(int(ylower_limit), int(yupper_limit), 24)
ylimit_error = np.sqrt(data[int(ylower_limit):int(yupper_limit)]) / np.max(data[int(ylower_limit):int(yupper_limit)])

# Constrained fit
bounds_sum = ([0, 24.21, 0, 0, 24.0, 0], [1, 24.22, 1, 1, 24.1, 1])  # Bounds for parameters

# Define function for sum of Gaussians
def sum_of_gaussians(x, amplitude1, mean1, stddev1, amplitude2, mean2, stddev2):
    gaussian1 = amplitude1 * np.exp(-((x - mean1) / stddev1)**2 / 2)
    gaussian2 = amplitude2 * np.exp(-((x - mean2) / stddev2)**2 / 2)
    return gaussian1 + gaussian2

# Fit the sum of Gaussians to the subset of data
params1, covariance1 = curve_fit(sum_of_gaussians, x_limitado, y_limitado, bounds=bounds_sum, sigma=ylimit_error)

# Create the model
multigaussian_model = Model(sum_of_gaussians)

# Initial values for parameters
A_value1 = amplitude
mu_value1 = 24.22
sigma_value1 = 0.1

A_value2 = amplitude * 0.5388
mu_value2 = 24.002
sigma_value2 = 0.1

# Set parameters for the model
params1 = multigaussian_model.make_params(amplitude1=A_value1, mean1=mu_value1, stddev1=sigma_value1,
                                          amplitude2=A_value2, mean2=mu_value2, stddev2=sigma_value2, sigma=ylimit_error)

# Fix certain parameters
params1['amplitude1'].vary = False
params1['mean1'].vary = False
params1['amplitude2'].vary = False
params1['mean2'].vary = False

# Fit the model to the data
result1 = multigaussian_model.fit(y_limitado, params1, x=x_limitado)

# Extract parameters
amplitude1 = result1.params['amplitude1'].value
mean1 = result1.params['mean1'].value
stddev1 = result1.params['stddev1'].value

amplitude2 = result1.params['amplitude2'].value
mean2 = result1.params['mean2'].value
stddev2 = result1.params['stddev2'].value

# Data interpolation
x_fine1 = np.linspace(x_limitado.min(), x_limitado.max(), num=1000)
y_fit1 = result1.eval(x=x_fine1)

# Individual Gaussians
x = np.linspace(min(mean1 - 3 * stddev1, mean2 - 3 * stddev2),
                max(mean1 + 3 * stddev1, mean2 + 3 * stddev2), 1000)
y1 = gaussian(x, amplitude1, mean1, stddev1)
y2 = gaussian(x, amplitude2, mean2, stddev2)

# Plotting
fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(x_limitado, y_limitado, color='black', marker='o')
ax.plot(x_fine1, y_fit1, color='blue')
ax.errorbar(x_limitado, y_limitado, yerr=ylimit_error, fmt='o', color='red', label='errorbar')
ax.plot(x, y1, label='Gaussian 1')
ax.plot(x, y2, label='Gaussian 2')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('Gaussian Fit to Data')
ax.set_xlim((24.21 - 3 * stddev, 24.21 + 3 * stddev))
ax.legend()
ax.grid(True)
plt.show()

# Print parameters
print("Amplitude1:", amplitude1)
print("Mean1:", mean1)
print("Standard Deviation1:", stddev1)
print("")
print("Amplitude2:", amplitude2)
print("Mean2:", mean2)
print("Standard Deviation2:", stddev2)

Другие вопросы по теме