Etude d'une CCD¶

Jeu de données¶

  • images acquises en février 2023
  • CCD ATIK 460 EX () bin1
  • Températures: +5°C à -15°C pas de -5 °C
  • Poses: 0 (bias),1,2,5,10,20,30,60,120,240,300 sec
  • 16 images par série

darkb1(10)-0004-60.fit : "darkb1" + T +"-" + i +"-" + exp + ".fit" avec: T = temperature , notée (T) pour les temperatures négatives et i = n° pose unitaire au format ###0

Initialisations¶

In [1]:
import glob
from astropy.io import fits as fits
from matplotlib import pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np
import pandas as pd
import scipy
import scipy.stats
In [2]:
path = r'D:\Temp\\'
display_infos = 0

Fonctions¶

Optimisation nombre de bins

  • Référence : Shimazaki and Shinomoto. Neural Comput, 2007, 19(6), 1503-1527
  • Source : https://www.neuralengine.org//res/histogram.html

Ouverture et visualisation d'une image fit : un bias¶

In [17]:
# choix image
temp = "0"
exptime = "0"
no = "0001"
#list_images = glob.glob(path + "dark_b1_" + temp + "-" + no+ "-" + exptime + ".fit")
filename = path + "dark_b1_" + temp + "-" + no+ "-" + exptime + ".fit"

hdu=fits.open(filename)
hdr=hdu[0].header
image=hdu[0].data
if display_infos:
    print(repr(hdr))
x_size = hdr["NAXIS1"]
y_size = hdr["NAXIS2"]
df = pd.DataFrame(image)

fig = plt.figure()
plt.imshow(image, cmap='gray',norm=LogNorm())
plt.grid(False)
plt.text(20,50,"bias T = 0°C",color = "white", fontsize = 12)


print('Statistics values')
print('Min:', np.min(image))
print('Max:', np.max(image))
print('Mean:', np.round(np.mean(image),0))
print('Stdev:', np.round(np.std(image),1))



NameFig = "F:\_120aa.eps"
plt.savefig(NameFig, format='eps',bbox_inches='tight', dpi = 75)
NameFig = "F:\_120aa.png"
plt.savefig(NameFig, format='png',bbox_inches='tight', dpi = 75)
Statistics values
Min: 195
Max: 583
Mean: 344.0
Stdev: 29.3

Coupes horizontales et verticales¶

In [20]:
x = int(x_size/2)
y = int(y_size/2)
w = 30
df = pd.DataFrame(image)

df_slice_horizontal=df.iloc[:][y-w//2:y+w//2]
df_slice_vertical=df_slice_horizontal=df.iloc[x-w//2:x+w//2][:]

fig,(ax1,ax2) = plt.subplots(2,figsize=(3,2))
fig.subplots_adjust(hspace=0.35)
ax1.plot(df_slice_horizontal.median(),"o",markersize=2)

ax2.plot(df_slice_horizontal.std(),"ro",markersize=2)
ax1.set_title("Bias - Coupe horizontale");
In [37]:
fig = plt.figure()
plt.imshow(image, cmap='gray',norm=LogNorm())
plt.grid(False)
plt.text(20,50,"bias T = 0°C",color = "white", fontsize = 12)

from scipy.interpolate import CubicSpline
x = np.arange(x_size)
y = df_slice_horizontal.median()
f = CubicSpline(x, y)
plt.plot(x,(f(x)-350)*10+350,"y-",markersize=2)
Out[37]:
[<matplotlib.lines.Line2D at 0x22a37351250>]

Visualisation d'une partie de l'image¶

In [5]:
x = int(x_size/2)
y = int(y_size/2)

x = 100
y = 100
ws = 10

df = pd.DataFrame(image)
df_cut_square=df.iloc[10:20,10:20]
df_cut_square=df.iloc[x:x+ws,y:y+ws]
#display(df_cut_square)

fig = plt.figure()
ax = plt.axes()
plt.imshow(df_cut_square, cmap='gray',norm=LogNorm())
plt.grid(False)
plt.tick_params(left = False,bottom=False)
ax.set_xticks(np.arange(0,10))
ax.set_yticks(np.arange(0,10))
for i in np.arange(10):
    for j in np.arange(10):
        s= str(df_cut_square.iloc[i,j])
        plt.text(i-0.25,j,s,color = "w",fontsize = 8,fontweight="bold")
plt.title = ""

NameFig = "F:\_120a.eps"
plt.savefig(NameFig, format='eps',bbox_inches='tight', dpi = 75)
NameFig = "F:\_120a.png"
plt.savefig(NameFig, format='png',bbox_inches='tight', dpi = 75)

Analyse statistique sur une fraction du bias¶

In [6]:
# Préparation des données
# dimension
ws = 100 
# coordonnées
centre = 1
if centre:
    x0 = int(x_size/2)
    y0 = int(y_size/2)
else:
    x0 = 200
    y0 = 200

df = pd.DataFrame(image)
df_cut_square=df.iloc[x0:x0+ws,y0:y0+ws]
_cut_square_list = df_cut_square.values.flatten()
df_cut_square_list=pd.Series(_cut_square_list )
stats= df_cut_square_list.describe()
display(stats)
count    10000.000000
mean       337.679000
std         26.377265
min        230.000000
25%        321.000000
50%        338.000000
75%        355.000000
max        454.000000
dtype: float64
In [7]:
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt
  
data = _cut_square_list
  
# Fit  normal distribution
mu, std = norm.fit(data) 
# Tests de normalité
print(scipy.stats.normaltest(_cut_square_list))
print(scipy.stats.skewtest(_cut_square_list))
print(scipy.stats.kurtosistest(_cut_square_list))



fig,ax = plt.subplots(figsize=(3,3))
plt.hist(data, bins=20, density=True, alpha=0.9, color= 'w',edgecolor='b',lw=0.5)
xmin, xmax = plt.xlim()
x = np.linspace(xmin, xmax, 100)
p = norm.pdf(x, mu, std)
  
plt.plot(x, p, 'b', linewidth=1)

plt.yticks(fontsize=8)
plt.xticks(np.arange(200,500,50),fontsize=8)

plt.ylabel('', fontsize=10)
ax.set_xlabel("ADU", fontsize=8)
ax.tick_params(direction = 'in', length=3,width=1,bottom=True, top=True, left=True, right=True)

plt.text(210,0.0150,"median "+str(stats[5]),fontsize=7)
plt.text(210,0.0140,"min "+str(stats[3]),fontsize=7)
plt.text(210,0.0130,"max "+str(stats[7]),fontsize=7)
plt.text(210,0.0120,"std "+ format(stats[2],".2f"),fontsize=7)
plt.text(360,0.0120,"p-value = 1.9E-6",fontsize=7,color='b')
plt.show()


NameFig = "F:\_120b.eps"
plt.savefig(NameFig, format='eps',bbox_inches='tight', dpi = 75)
NameFig = "F:\_120b.png"
plt.savefig(NameFig, format='png',bbox_inches='tight', dpi = 75)
NormaltestResult(statistic=26.356590140587688, pvalue=1.8912074502850932e-06)
SkewtestResult(statistic=-0.15950748294293834, pvalue=0.8732690632611646)
KurtosistestResult(statistic=5.131388457666492, pvalue=2.8761264467574e-07)
<Figure size 640x480 with 0 Axes>

Tests de normalité¶

In [8]:
print(scipy.stats.shapiro(_cut_square_list))
print(scipy.stats.anderson(_cut_square_list, dist='norm'))
print(scipy.stats.normaltest(_cut_square_list))
print(scipy.stats.skewtest(_cut_square_list))
print(scipy.stats.kurtosistest(_cut_square_list))
ShapiroResult(statistic=0.9989916086196899, pvalue=7.810292117937934e-06)
AndersonResult(statistic=2.6657871228380827, critical_values=array([0.576, 0.656, 0.787, 0.918, 1.092]), significance_level=array([15. , 10. ,  5. ,  2.5,  1. ]))
NormaltestResult(statistic=26.356590140587688, pvalue=1.8912074502850932e-06)
SkewtestResult(statistic=-0.15950748294293834, pvalue=0.8732690632611646)
KurtosistestResult(statistic=5.131388457666492, pvalue=2.8761264467574e-07)
C:\Users\franc\Anaconda3\lib\site-packages\scipy\stats\_morestats.py:1800: UserWarning: p-value may not be accurate for N > 5000.
  warnings.warn("p-value may not be accurate for N > 5000.")

Construction master bias¶

In [9]:
temp = "0"
exptime = "0"

images = glob.glob(path+"dark_b1_" +temp + "-" +"*"+"-" + exptime + ".fit")
nb_images = len(images)
print("Nombre images = ",nb_images)
master = np.empty((y_size, x_size, nb_images))
for i in range(nb_images):
    
    hdu = fits.open(images[i])[0]
    
    # Each slice of the darks matrix is a dark frame
    master[:,:,i] = hdu.data
master_bias = np.median(master, axis=2)
Nombre images =  36

Bias : Etude du stacking¶

In [10]:
temp = "0"
exptime = "0"

ws = 100
centre = 1
if centre:
    x0 = int(x_size/2)
    y0 = int(y_size/2)
else:
    x0 = 200
    y0 = 200

images = glob.glob(path+"dark_b1_" +temp + "-" +"*"+"-" + exptime + ".fit")
nb_images = len(images)
crop = np.empty((ws, ws, nb_images))

data=[]
for i in range(nb_images):
    
    df = pd.DataFrame( master[:,:,i])
    df_cut_square=df.iloc[x0:x0+ws,y0:y0+ws]
    crop[:,:,i] = df_cut_square.values
    
    data.append([i,
                 int(np.median(crop[:,:,i])),
                 round((np.std(crop[:,:,i])),2),
                 int(np.min(crop[:,:,i])),
                 int(np.max(crop[:,:,i]))])              

df_stats = pd.DataFrame(data,columns=['no','Median', 'Std', 'Min','Max'])  
In [11]:
crop_stack = np.empty((ws, ws, nb_images))
data=[]
for i in range(nb_images):

    crop_stack[:,:,i] = np.median(crop[:,:,0:i+1], axis=2)
    
    data.append([i,
                 int(np.median(crop_stack[:,:,i])),
                 round((np.std(crop_stack[:,:,i])),2),
                 int(np.min(crop_stack[:,:,i])),
                 int(np.max(crop_stack[:,:,i]))])              

df_stats_stack = pd.DataFrame(data,columns=['no','Median', 'Std', 'Min','Max'])  
#display(df_stats_stack)

fig,ax =plt.subplots(2,figsize=(4,3))
fig.subplots_adjust(hspace=0.1)
"""
plt.fontsize=8
plt.yticks(fontsize=8)
plt.xticks(np.arange(0,37,6),fontsize=8)
"""


ax[0].tick_params(direction = 'in', length=3,width=1,bottom=True, top=True, left=True, right=True)
ax[0].errorbar(np.arange(36), df_stats_stack.Median, df_stats_stack.Std, fmt='ob', lw=3,ms=10,marker="_")
ax[0].errorbar(np.arange(36), df_stats_stack.Median, [df_stats_stack.Median - df_stats_stack.Min, df_stats_stack.Max - df_stats_stack.Median],
             fmt='.b', ecolor='b', lw=0.5)
ax[0].set_ylim(200,500)
ax[0].set_ylabel("stats",fontsize=9)
ax[0].tick_params(axis='y', labelsize=8)


ax[1].plot(df_stats_stack.Std,'bo',ms=2)
ax[1].set_ylim(0,30)
ax[1].set_xlabel("nombre de  bias",fontsize=9)
ax[1].set_ylabel("std",fontsize=9)
ax[1].tick_params(axis='y', labelsize=8)
ax[1].tick_params(direction = 'in', length=3,width=1,bottom=True, top=True, left=True, right=True)



NameFig = "F:\_120c.eps"
plt.savefig(NameFig, format='eps',bbox_inches='tight', dpi = 75)
NameFig = "F:\_120c.png"
plt.savefig(NameFig, format='png',bbox_inches='tight', dpi = 75)

plt.show()
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\3757231520.py:26: UserWarning: marker is redundantly defined by the 'marker' keyword argument and the fmt string "ob" (-> marker='o'). The keyword argument will take precedence.
  ax[0].errorbar(np.arange(36), df_stats_stack.Median, df_stats_stack.Std, fmt='ob', lw=3,ms=10,marker="_")
In [ ]:
 

Bias : Etude de la température¶

In [12]:
temp = "0"
exptime = "0"
temp_list = ["(10)","(5)","0","5"]
ws = 100
centre = 1
if centre:
    x0 = int(x_size/2)
    y0 = int(y_size/2)
else:
    x0 = 200
    y0 = 200
    
def stack(temp,exptime,x0,y0,ws):
    
    images = glob.glob(path+"dark_b1_" +temp + "-" +"*"+"-" + exptime + ".fit")
    nb_images = len(images)
    nb_images = 16
    print(nb_images)
    crop = np.empty((ws, ws, nb_images))

    
    for i in range(nb_images):
        global master
        hdu = fits.open(images[i])[0]
        df = pd.DataFrame(hdu.data)
        df_cut=df.iloc[x0:x0+ws,y0:y0+ws]
       
        
        crop[:,:,i] = df_cut.values
    master = np.median(crop, axis=2)
    return master


master_bias_crop=[]
data=[]
i=0

for temp in temp_list:
    i=i+1
    stack(temp,exptime,x0,y0,ws)
   
    data.append([temp,
                 int(np.median(master.flatten())),
                 round((np.std(master.flatten())),2),
                 int(np.min(master.flatten())),
                 int(np.max(master.flatten())),
                ])

df_stats1 = pd.DataFrame(data,columns=['temp','Median', 'Std', 'Min','Max'])  
df_stats1.temp[0] = -10
df_stats1.temp[1] = -5
display(df_stats1)
16
16
16
16
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\3031695872.py:50: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df_stats1.temp[0] = -10
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\3031695872.py:51: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df_stats1.temp[1] = -5
temp Median Std Min Max
0 -10 322 6.90 294 350
1 -5 327 7.24 297 357
2 0 337 7.74 306 369
3 5 356 8.47 322 388
In [13]:
fig,ax =plt.subplots(2,figsize=(4,3))
fig.subplots_adjust(hspace=0.1)
plt.fontsize=8


plt.yticks(fontsize=8)

ax[0].errorbar(np.arange(4),df_stats1.Median, df_stats1.Std, fmt='ob', lw=3,ms=10,marker="_")
ax[0].errorbar(np.arange(4), df_stats1.Median, [df_stats1.Median - df_stats1.Min, df_stats1.Max -df_stats1.Median],
             fmt='.b', ecolor='b', lw=0.5)
ax[0].set_ylim(250,400)
#ax[0].set_yscale("log")
ax[0].set_ylabel("stats",fontsize=9)
ax[0].tick_params(axis='y', labelsize=8)
ax[0].tick_params(direction = 'in', length=3,width=1,bottom=True, top=True, left=True, right=True)
ax[0].set_xticks([0,1,2,3])
ax[0].xaxis.set_ticklabels([])

ax[1].plot(df_stats1.Std,'ob',ms=3)
ax[1].set_ylim(5,10)
ax[1].set_xlabel("temperature",fontsize=9)
ax[1].set_ylabel("std",fontsize=9)
ax[1].tick_params(axis='y', labelsize=8)
ax[1].set_xticklabels(["-10","-5","0","5"])
ax[1].tick_params(direction = 'in', length=3,width=1,bottom=True, top=True, left=True, right=True)
ax[1].set_xticks([0,1,2,3])
NameFig = "F:\_120d.eps"
plt.savefig(NameFig, format='eps',bbox_inches='tight', dpi = 75)
NameFig = "F:\_120d.png"
plt.savefig(NameFig, format='png',bbox_inches='tight', dpi = 75)

plt.show()
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\814853149.py:8: UserWarning: marker is redundantly defined by the 'marker' keyword argument and the fmt string "ob" (-> marker='o'). The keyword argument will take precedence.
  ax[0].errorbar(np.arange(4),df_stats1.Median, df_stats1.Std, fmt='ob', lw=3,ms=10,marker="_")
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\814853149.py:24: UserWarning: FixedFormatter should only be used together with FixedLocator
  ax[1].set_xticklabels(["-10","-5","0","5"])
In [ ]:
 

temp = "0" exptime = "0" temp_list = ["(10)","(5)","0","5"] exptime_list = ["0","1","2","5","10","20","30","60","120","180","240","300"] ws = 100 centre = 1 if centre: x0 = int(x_size/2) y0 = int(y_size/2) else: x0 = 200 y0 = 200

def stack(temp,exptime,x0,y0,ws):

images = glob.glob(path+"dark_b1_" +temp + "-" +"*"+"-" + exptime + ".fit")
nb_images = len(images)
nb_images = 15

crop = np.empty((ws, ws, nb_images))


for i in range(nb_images):
    global master
    hdu = fits.open(images[i])[0]
    df = pd.DataFrame(hdu.data)
    df_cut_square=df.iloc[x0:x0+ws,y0:y0+ws]
    crop[:,:,i] = df_cut_square.values
master = np.median(crop, axis=2)
return master


master_crop=[] data=[]

for temp in temp_list: for exptime in exptime_list: i=i+1 stack(temp,exptime,x0,y0,ws)

    plt.show()
    data.append([temp, exptime,
             int(np.median(master.flatten())),
             round((np.std(master.flatten())),2),
             np.quantile(master.flatten(), 0.75),    
             int(np.min(master.flatten())),
             int(np.max(master.flatten())),
            ])

    import seaborn as sns


    sns.set_theme(style="ticks")



    f, ax = plt.subplots(figsize=(7, 5))
    sns.despine(f)

    g=sns.histplot(
        master.flatten(),
        edgecolor=".3",
        linewidth=.5,
        )
    g.set_yscale("log")
    g.set_xscale("log")



df_stats2 = pd.DataFrame(data,columns=["temp","exptime",'Median','75%', 'Std', 'Min','Max'])
display(df_stats2)

In [ ]:
 

Modification Header d'une série d'images

from astropy.io import fits as fits from matplotlib import pyplot as plt from matplotlib.colors import LogNorm import numpy as np import pandas as pd import warnings warnings.simplefilter("ignore") ### df.append depreciated

Create dataframe¶

df = pd.DataFrame(columns = ['n', 'min', 'max','mean','median','std'])

for i in np.arange(1,16): path = r'D:\DUAO\Darks\darks_2019_03\offset(-10)\' serie = "offset(-10)" imagename = serie + "-" + str(i) +".fit" filename= path + imagename hdu=fits.open(filename) hdu[0].header['UNIT'] = 'ADU'

hdu.writeto(path + '_' + imagename,overwrite = True)
hdu.close()
In [ ]:
 

Ouverture d'une série d'images

from astropy.io import fits as fits from matplotlib import pyplot as plt from matplotlib.colors import LogNorm import numpy as np import pandas as pd import warnings warnings.simplefilter("ignore") ### df.append depreciated

Create dataframe¶

df = pd.DataFrame(columns = ['n', 'min', 'max','mean','median','std'])

for i in np.arange(1,16): path = r'D:\DUAO\Darks\darks_2019_03\offset(-10)\' serie = "offset(-10)" imagename = serie + "-" + str(i) +".fit" filename= path + imagename hdu=fits.open(filename)

#hdu.info()
#header=hdu[0].header
image = hdu[0].data


hdu.close()
fig1 = plt.figure()
plt.imshow(image, cmap='gray',norm=LogNorm())
plt.grid(False)
plt.show()

fig2  = plt.figure()
#histogram = plt.hist(image.flatten(), bins='auto')
#histogram = plt.hist(image.flatten(), bins=1)
n, bins, patches = plt.hist(image.flatten(), 100, density=True, edgecolor='b', facecolor='none',  linewidth=0.5,alpha=0.75)



plt.show()

#nomimage = "image" +str(i)
dfim = pd.DataFrame(data = image) 

df = df.append({'n' : i, 'min':np.min(image), 'max':np.max(image),'mean' : np.round(np.mean(image),0),'median':np.round(np.median(image),0),'std':np.round(np.std(image),1)},ignore_index = True)
df.to_csv(serie + '.csv', index=False)

display(df)

In [40]:
temp = "-10"
exptime = "30"
temp_list = ["(10)","(5)","0","5"]
ws = 100
centre = 1
if centre:
    x0 = int(x_size/2)
    y0 = int(y_size/2)
else:
    x0 = 200
    y0 = 200
    
def stack(temp,exptime,x0,y0,ws):
    
    images = glob.glob(path+"dark_b1_" +temp + "-" +"*"+"-" + exptime + ".fit")
    nb_images = len(images)
    nb_images = 16
    print(nb_images)
    crop = np.empty((ws, ws, nb_images))

    
    for i in range(nb_images):
        global master
        hdu = fits.open(images[i])[0]
        df = pd.DataFrame(hdu.data)
        df_cut=df.iloc[x0:x0+ws,y0:y0+ws]
       
        
        crop[:,:,i] = df_cut.values
    master = np.median(crop, axis=2)
    return master


master_bias_crop=[]
data=[]
i=0

for temp in temp_list:
    i=i+1
    stack(temp,exptime,x0,y0,ws)
   
    data.append([temp,
                 int(np.median(master.flatten())),
                 round((np.std(master.flatten())),2),
                 int(np.min(master.flatten())),
                 int(np.max(master.flatten())),
                ])

df_stats1 = pd.DataFrame(data,columns=['temp','Median', 'Std', 'Min','Max'])  
df_stats1.temp[0] = -10
df_stats1.temp[1] = -5
display(df_stats1)


fig,ax =plt.subplots(2,figsize=(4,3))
fig.subplots_adjust(hspace=0.1)
plt.fontsize=8


plt.yticks(fontsize=8)

ax[0].errorbar(np.arange(4),df_stats1.Median, df_stats1.Std, fmt='ob', lw=3,ms=10,marker="_")
ax[0].errorbar(np.arange(4), df_stats1.Median, [df_stats1.Median - df_stats1.Min, df_stats1.Max -df_stats1.Median],
             fmt='.b', ecolor='b', lw=0.5)
ax[0].set_ylim(250,400)
#ax[0].set_yscale("log")
ax[0].set_ylabel("stats",fontsize=9)
ax[0].tick_params(axis='y', labelsize=8)
ax[0].tick_params(direction = 'in', length=3,width=1,bottom=True, top=True, left=True, right=True)
ax[0].set_xticks([0,1,2,3])
ax[0].xaxis.set_ticklabels([])

ax[1].plot(df_stats1.Std,'ob',ms=3)
#ax[1].set_ylim(5,10)
ax[1].set_xlabel("temperature",fontsize=9)
ax[1].set_ylabel("std",fontsize=9)
ax[1].tick_params(axis='y', labelsize=8)
ax[1].set_xticklabels(["-10","-5","0","5"])
ax[1].tick_params(direction = 'in', length=3,width=1,bottom=True, top=True, left=True, right=True)
ax[1].set_xticks([0,1,2,3])
NameFig = "F:\_120d.eps"
plt.savefig(NameFig, format='eps',bbox_inches='tight', dpi = 75)
NameFig = "F:\_120d.png"
plt.savefig(NameFig, format='png',bbox_inches='tight', dpi = 75)

plt.show()
16
16
16
16
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\1406913259.py:50: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df_stats1.temp[0] = -10
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\1406913259.py:51: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df_stats1.temp[1] = -5
temp Median Std Min Max
0 -10 323 42.94 294 4520
1 -5 327 71.33 298 7324
2 0 338 117.52 311 11863
3 5 357 188.10 322 18741
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\1406913259.py:62: UserWarning: marker is redundantly defined by the 'marker' keyword argument and the fmt string "ob" (-> marker='o'). The keyword argument will take precedence.
  ax[0].errorbar(np.arange(4),df_stats1.Median, df_stats1.Std, fmt='ob', lw=3,ms=10,marker="_")
C:\Users\franc\AppData\Local\Temp\ipykernel_9136\1406913259.py:78: UserWarning: FixedFormatter should only be used together with FixedLocator
  ax[1].set_xticklabels(["-10","-5","0","5"])
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]: