style histograma graficar bar gnuplot histogram binning

bar - graficar histograma en gnuplot



Histograma utilizando gnuplot? (9)

Sé cómo crear un histograma (solo use "con cuadros") en gnuplot si mi archivo .dat ya tiene datos correctamente almacenados. ¿Hay alguna forma de tomar una lista de números y hacer que gnuplot proporcione un histograma basado en los rangos y tamaños de contenedores que proporciona el usuario?


¿Quieres trazar una gráfica como esta? ¿sí? Entonces puedes echar un vistazo al artículo de mi blog: http://gnuplot-surprising.blogspot.com/2011/09/statistic-analysis-and-histogram.html

Líneas clave del código:

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


Como de costumbre, Gnuplot es una herramienta fantástica para trazar gráficos de aspecto dulce y se puede hacer para realizar todo tipo de cálculos. Sin embargo , está pensado para trazar datos en lugar de servir como una calculadora y, a menudo, es más fácil usar un programa externo (por ejemplo, Octave) para hacer los cálculos más "complicados", guardar estos datos en un archivo y luego usar Gnuplot para producir la gráfica. Para el problema anterior, compruebe que la función "hist" es Octave usando [freq,bins]=hist(data) , luego trace esto en Gnuplot usando

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


Con respecto a las funciones de agrupación, no esperaba el resultado de las funciones ofrecidas hasta ahora. Es decir, si mi binwidth es 0.001, estas funciones centraban las bandejas en 0.0005 puntos, mientras que creo que es más intuitivo tener las bandejas centradas en 0.001 límites.

En otras palabras, me gustaría tener

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

La función binning que se me ocurrió es

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

Aquí hay un script para comparar algunas de las funciones bin ofrecidas con esta:

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 }

y aquí está la salida

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


He encontrado esta discusión extremadamente útil, pero he experimentado algunos problemas de "redondeo".

Más precisamente, al usar un ancho de bote de 0.05, me he dado cuenta de que, con las técnicas presentadas aquí anteriormente, los puntos de datos que dicen 0.1 y 0.15 caen en el mismo bin. Este (comportamiento obviamente no deseado) es más probable debido a la función "piso".

De aquí en adelante es mi pequeña contribución para tratar de eludir esto.

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

Este método recursivo es para x> = 0; uno podría generalizar esto con más declaraciones condicionales para obtener algo aún más general.


No necesitamos usar el método recursivo, puede ser lento. Mi solución es utilizar una función definida por el usuario en lugar de la función intrínseca int o floor.

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

Esta función dará rint(0.0003/0.0001)=3 , mientras que int(0.0003/0.0001)=floor(0.0003/0.0001)=2 .

¿Por qué? Por favor mire la función int de Perl y los ceros de relleno.


Sí, y es rápido y simple aunque muy oculto:

binwidth=5 bin(x,width)=width*floor(x/width) plot ''datafile'' using (bin($1,binwidth)):(1.0) smooth freq with boxes

Echa un vistazo a la help smooth freq para ver por qué lo anterior hace un histograma

para lidiar con los rangos solo establece la variable xrange.


Tenga mucho cuidado: todas las respuestas en esta página están tomando la decisión de dónde comienza el agrupamiento: el borde izquierdo del contenedor que está más a la izquierda, si lo desea, fuera de las manos del usuario. Si el usuario está combinando cualquiera de estas funciones para compartir datos con su propia decisión acerca de dónde comienza la combinación (como se hace en el blog al que se ha vinculado anteriormente), todas las funciones anteriores son incorrectas. Con un punto de inicio arbitrario para agrupar ''Min'', la función correcta es:

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

Puede ver por qué esto es correcto secuencialmente (ayuda a dibujar unas cuantas bandejas y un punto en algún lugar de una de ellas). Reste Min de su punto de datos para ver qué tan lejos está en el rango de ubicación. Luego divida por binwidth para que esté trabajando efectivamente en unidades de ''contenedores''. Luego, "coloque" el resultado para ir al borde izquierdo de ese contenedor, agregue 0.5 para ir al centro del contenedor, multiplíquelo por el ancho para que ya no trabaje en unidades de contenedores sino en una escala absoluta de nuevo, luego, finalmente, agregue de nuevo el desplazamiento mínimo que restó al inicio.

Considera esta función en acción:

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

Por ejemplo, el valor 1.1 realmente cae en el contenedor izquierdo:

  • esta función la asigna correctamente al centro del contenedor izquierdo (0.75);
  • La respuesta de Born2Smile, bin (x) = ancho * piso (x / ancho), lo mapea incorrectamente a 1;
  • La respuesta de mas90, bin (x) = ancho * piso (x / ancho) + binwidth / 2.0, lo asigna incorrectamente a 1.5.

La respuesta de Born2Smile solo es correcta si los límites de bin se producen en (n + 0.5) * binwidth (donde n se ejecuta sobre enteros). La respuesta de mas90 solo es correcta si los límites de bin se producen en n * binwidth.


Tengo un par de correcciones / adiciones a la muy útil respuesta de Born2Smile:

  1. Los contenedores vacíos hicieron que la caja del contenedor adyacente se extendiera incorrectamente en su espacio; evitar esto utilizando set boxwidth binwidth
  2. En la versión de Born2Smile, los intervalos se representan como centrados en su límite inferior. Estrictamente deben extenderse desde el límite inferior al límite superior. Esto se puede corregir modificando la función bin : bin(x,width)=width*floor(x/width) + width/2.0

Tengo una pequeña modificación a la solución de Born2Smile.

Sé que eso no tiene mucho sentido, pero puede quererlo por si acaso. Si sus datos son enteros y necesita un tamaño de contenedor flotante (tal vez para comparar con otro conjunto de datos, o densidad de trazado en una cuadrícula más fina), deberá agregar un número aleatorio entre 0 y 1 dentro del piso. De lo contrario, habrá picos debido al error de redondeo. floor(x/width+0.5) no funcionará porque creará un patrón que no es fiel a los datos originales.

binwidth=0.3 bin(x,width)=width*floor(x/width+rand(0))