web-dev-qa-db-fra.com

Histogramme utilisant gnuplot?

Je sais comment créer un histogramme (il suffit d'utiliser "avec des boîtes") dans gnuplot si mon fichier .dat contient déjà des données correctement triées. Existe-t-il un moyen de prendre une liste de nombres et d’avoir gnuplot un histogramme basé sur les plages et les tailles de corbeille fournies par l’utilisateur?

198
mary

oui, et c'est simple et rapide mais très caché:

binwidth=5
bin(x,width)=width*floor(x/width)

plot 'datafile' using (bin($1,binwidth)):(1.0) smooth freq with boxes

consultez help smooth freq pour voir pourquoi ce qui précède crée un histogramme

pour traiter les plages, définissez simplement la variable xrange.

224
Born2Smile

J'ai quelques corrections/ajouts à la réponse très utile de Born2Smile:

  1. Des bacs vides ont provoqué un allongement incorrect de la boîte du bac adjacent. éviter cela en utilisant set boxwidth binwidth
  2. Dans la version de Born2Smile, les bacs sont rendus centrés sur leur limite inférieure. Strictement ils devraient s'étendre de la limite inférieure à la limite supérieure. Ceci peut être corrigé en modifiant la fonction bin: bin(x,width)=width*floor(x/width) + width/2.0
88
mas90

Soyez très prudent: toutes les réponses sur cette page prennent implicitement le choix du lieu de début du tri (le bord gauche du casier le plus à gauche, si vous le souhaitez), hors des mains de l'utilisateur. Si l'utilisateur combine l'une quelconque de ces fonctions pour le binning des données avec sa propre décision quant au début du binning (comme c'est le cas sur le blog qui est lié au précédent), les fonctions ci-dessus sont toutes incorrectes. Avec un point de départ arbitraire pour le binning 'Min', la fonction correcte est:

bin(x) = width*(floor((x-Min)/width)+0.5) + Min

Vous pouvez voir pourquoi ceci est correct séquentiellement (cela aide de dessiner quelques bacs et un point quelque part dans l’un d’eux). Soustrayez Min de votre point de données pour voir à quelle distance il se trouve dans la plage de tri. Divisez ensuite par binwidth afin que vous travailliez efficacement dans des unités de "bacs". Puis 'étage' le résultat pour aller au bord gauche de cette case, ajoutez 0,5 pour aller au milieu de la case, multipliez par la largeur pour que vous ne travailliez plus en unités de cases mais à une échelle absolue. à nouveau, puis ajoutez enfin le décalage Min que vous avez soustrait au début.

Considérez cette fonction en action:

Min = 0.25 # where binning starts
Max = 2.25 # where binning ends
n = 2 # the number of bins
width = (Max-Min)/n # binwidth; evaluates to 1.0
bin(x) = width*(floor((x-Min)/width)+0.5) + Min

par exemple. la valeur 1.1 tombe vraiment dans la corbeille de gauche:

  • cette fonction le mappe correctement au centre du bac de gauche (0,75);
  • La réponse de Born2Smile, bin (x) = width * floor (x/width), le mappe incorrectement à 1;
  • la réponse de mas90, bin (x) = width * floor (x/width) + binwidth/2.0, le mappe incorrectement à 1,5.

La réponse de Born2Smile n'est correcte que si les limites de la corbeille se situent à (n + 0,5) * binwidth (où n dépasse les entiers). La réponse de mas90 n'est correcte que si les limites de la corbeille se produisent à n * binwidth.

76
ChrisW

Voulez-vous tracer un graphique comme celui-ci? enter image description here Oui? Ensuite, vous pouvez consulter l'article de mon blog: http://gnuplot-surprising.blogspot.com/2011/09/statistic-analysis-and-histogram.html

Lignes principales du code:

n=100 #number of intervals
max=3. #max value
min=-3. #min value
width=(max-min)/n #interval width
#function used to map a value to the intervals
hist(x,width)=width*floor(x/width)+width/2.0
set boxwidth width*0.9
set style fill solid 0.5 # fill style

#count and plot
plot "data.dat" u (hist($1,width)):(1.0) smooth freq w boxes lc rgb"green" notitle
45
hsxz

Comme d'habitude, Gnuplot est un outil fantastique pour tracer des graphiques d'aspect attrayant et il peut être utilisé pour effectuer toutes sortes de calculs. Cependant, il est prévu de tracer les données plutôt que de servir de calculatrice et il est souvent plus facile d'utiliser un programme externe (par exemple Octave) pour effectuer les calculs plus "compliqués", enregistrez ces données dans un fichier. fichier, puis utilisez Gnuplot pour produire le graphique. Pour le problème ci-dessus, vérifiez la fonction "hist" est Octave en utilisant [freq,bins]=hist(data), puis tracez ceci dans Gnuplot en utilisant

set style histogram rowstacked gap 0
set style fill solid 0.5 border lt -1
plot "./data.dat" smooth freq with boxes
9
Dai

J’ai trouvé cette discussion extrêmement utile, mais j’ai rencontré quelques problèmes de "finalisation".

Plus précisément, en utilisant une largeur de corbeille de 0,05, j'ai remarqué qu'avec les techniques présentées ci-dessus, les points de données dont les valeurs sont 0,1 et 0,15 se trouvent dans la même corbeille. Ceci (comportement évidemment indésirable) est très probablement dû à la fonction "sol".

Voici ma petite contribution pour tenter de contourner cela.

bin(x,width,n)=x<=n*width? width*(n-1) + 0.5*binwidth:bin(x,width,n+1)
binwidth = 0.05
set boxwidth binwidth
plot "data.dat" u (bin($1,binwidth,1)):(1.0) smooth freq with boxes

Cette méthode récursive est pour x> = 0; on pourrait généraliser ceci avec des instructions plus conditionnelles pour obtenir quelque chose d'encore plus général.

7
Alex

Nous n'avons pas besoin d'utiliser la méthode récursive, elle peut être lente. Ma solution utilise une fonction définie par l'utilisateur rint instesd de fonction intrinsèque int ou floor.

rint(x)=(x-int(x)>0.9999)?int(x)+1:int(x)

Cette fonction donnera rint(0.0003/0.0001)=3, tandis que int(0.0003/0.0001)=floor(0.0003/0.0001)=2.

Pourquoi? Veuillez regarder Perl int function et padding zeros

6
JOE

J'ai une petite modification à la solution de Born2Smile.

Je sais que cela n’a pas beaucoup de sens, mais vous pouvez le vouloir au cas où. Si vos données sont entières et que vous avez besoin d'une taille de casier flottant (par exemple, pour la comparaison avec un autre ensemble de données ou la densité de tracé dans une grille plus fine), vous devrez ajouter un nombre aléatoire compris entre 0 et 1 à l'intérieur du sol. Sinon, il y aura des pics dus à une erreur d'arrondi. floor(x/width+0.5) ne le fera pas car cela créera un motif qui ne correspond pas aux données d'origine.

binwidth=0.3
bin(x,width)=width*floor(x/width+Rand(0))
4
path4

En ce qui concerne les fonctions de binning, je ne m'attendais pas au résultat des fonctions offertes jusqu'à présent. À savoir, si ma largeur de bande est de 0,001, ces fonctions centraient les bacs sur 0,0005 point, alors que j'estime qu'il est plus intuitif de centrer les bacs sur les limites de 0,001.

En d'autres termes, j'aimerais avoir

Bin 0.001 contain data from 0.0005 to 0.0014
Bin 0.002 contain data from 0.0015 to 0.0024
...

La fonction de binning que j'ai créée est

my_bin(x,width)     = width*(floor(x/width+0.5))

Voici un script permettant de comparer certaines des fonctions bin proposées à celle-ci:

rint(x) = (x-int(x)>0.9999)?int(x)+1:int(x)
bin(x,width)        = width*rint(x/width) + width/2.0
binc(x,width)       = width*(int(x/width)+0.5)
mitar_bin(x,width)  = width*floor(x/width) + width/2.0
my_bin(x,width)     = width*(floor(x/width+0.5))

binwidth = 0.001

data_list = "-0.1386 -0.1383 -0.1375 -0.0015 -0.0005 0.0005 0.0015 0.1375 0.1383 0.1386"

my_line = sprintf("%7s  %7s  %7s  %7s  %7s","data","bin()","binc()","mitar()","my_bin()")
print my_line
do for [i in data_list] {
    iN = i + 0
    my_line = sprintf("%+.4f  %+.4f  %+.4f  %+.4f  %+.4f",iN,bin(iN,binwidth),binc(iN,binwidth),mitar_bin(iN,binwidth),my_bin(iN,binwidth))
    print my_line
}

et voici la sortie

   data    bin()   binc()  mitar()  my_bin()
-0.1386  -0.1375  -0.1375  -0.1385  -0.1390
-0.1383  -0.1375  -0.1375  -0.1385  -0.1380
-0.1375  -0.1365  -0.1365  -0.1375  -0.1380
-0.0015  -0.0005  -0.0005  -0.0015  -0.0010
-0.0005  +0.0005  +0.0005  -0.0005  +0.0000
+0.0005  +0.0005  +0.0005  +0.0005  +0.0010
+0.0015  +0.0015  +0.0015  +0.0015  +0.0020
+0.1375  +0.1375  +0.1375  +0.1375  +0.1380
+0.1383  +0.1385  +0.1385  +0.1385  +0.1380
+0.1386  +0.1385  +0.1385  +0.1385  +0.1390
3
Winston Smith