Pergunta

Eu sei como criar um histograma (basta usar "com caixas") no GNUPLOT se meu arquivo .dat já tiver dados devidamente binned. Existe uma maneira de obter uma lista de números e ter o GNUPLOT fornece um histograma com base em intervalos e tamanhos de compartimento que o usuário fornece?

Foi útil?

Solução

Sim, e é rápido e simples, embora muito escondido:

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

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

Verificação de saída help smooth freq Para ver por que o exposto acima faz um histograma

Para lidar com intervalos, basta definir a variável xRange.

Outras dicas

Tenho algumas correções/adições à resposta muito útil do Born2Smile:

  1. As caixas vazias fizeram com que a caixa para que o compartimento adjacente se estendesse incorretamente ao seu espaço; Evite isso usando set boxwidth binwidth
  2. Na versão do Born2Smile, os caixotes são renderizados como centrados no limite inferior. Estritamente eles devem se estender do limite inferior ao limite superior. Isso pode ser corrigido modificando o bin função: bin(x,width)=width*floor(x/width) + width/2.0

Seja muito cuidadoso: todas as respostas nesta página estão tomando implicitamente a decisão de onde o binning começa - a borda esquerda da lixeira mais à esquerda, se você quiser - fora das mãos do usuário. Se o usuário estiver combinando alguma dessas funções para dados de binning com sua própria decisão sobre onde o binning começa (como é feito no blog que está vinculado acima), as funções acima estão incorretas. Com um ponto de partida arbitrário para binning 'min', a função correta é:

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

Você pode ver por que isso está correto sequencialmente (ajuda a desenhar algumas caixas e um ponto em algum lugar de uma delas). Subtraia o MIN do seu ponto de dados para ver a que distância está no intervalo de binning. Em seguida, divida -se por Binwidth para que você esteja efetivamente trabalhando em unidades de 'caixas'. Em seguida, 'piso', o resultado de ir para a borda esquerda daquela lixeira, adicione 0,5 para ir ao meio da lixeira, multiplique pela largura para que você não esteja mais trabalhando em unidades de caixas, mas em uma escala absoluta Novamente, finalmente adicione novamente o deslocamento MIN que você subtraiu no início.

Considere esta função em ação:

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 exemplo, o valor 1.1 realmente cai na lixeira esquerda:

  • Esta função o mapeia corretamente para o centro da lixeira esquerda (0,75);
  • A resposta de Born2Smile, bin (x) = largura*piso (x/largura), mapeia incorretamente para 1;
  • Resposta do MAS90, bin (x) = largura*piso (x/largura) + binwidth/2.0, mapeia incorretamente para 1.5.

A resposta do Born2Smile só está correta se os limites do compartimento ocorrem em (n+0,5)*BinWidth (onde n atropela os números inteiros). A resposta do MAS90 só está correta se os limites do compartimento ocorrerem em n*BinWidth.

Você quer traçar um gráfico como este?enter image description heresim? Então você pode dar uma olhada no artigo do meu blog: http://gnuplot-surprising.blogspot.com/2011/09/statistic-analysis-and-histogram.html

Linhas -chave do 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 sempre, o GNUplot é uma ferramenta fantástica para plotar gráficos de aparência doce e pode ser feito para executar todos os tipos de cálculos. No entanto, destina -se a plotar dados, em vez de servir como calculadora e geralmente é mais fácil usar um programa externo (por exemplo, oitava) para fazer os cálculos mais "complicados", salvar esses dados em um arquivo e depois usar o GNuplot para produzir o gráfico. Para o problema acima, consulte a função "Hist" é oitava usando [freq,bins]=hist(data), então plote isso em gneplot usando

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

Achei essa discussão extremamente útil, mas experimentei alguns problemas de "arredondamento".

Mais precisamente, usando uma largura de 0,05, notei que, com as técnicas apresentadas aqui acima, os pontos de dados que leram 0,1 e 0,15 caem na mesma caixa. Esse comportamento (obviamente indesejado) é provavelmente devido à função "piso".

A seguir, é minha pequena contribuição para tentar contornar isso.

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 é para x> = 0; Pode -se generalizar isso com declarações mais condicionais para obter algo ainda mais geral.

Não precisamos usar o método recursivo, pode ser lento. Minha solução está usando uma função definida pelo usuário, Rint, da função Instrinsic Int ou Floor.

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

Esta função dará rint(0.0003/0.0001)=3, enquanto int(0.0003/0.0001)=floor(0.0003/0.0001)=2.

Por quê? Por favor, olhe para Função perl int e estofamento zeros

Eu tenho uma pequena modificação na solução do Born2Smile.

Eu sei que isso não faz muito sentido, mas você pode querer isso apenas por precaução. Se seus dados forem inteiros e você precisar de um tamanho de lixeira (talvez para comparação com outro conjunto de dados ou densidade de plotagem na grade mais fina), você precisará adicionar um número aleatório entre 0 e 1 piso interno. Caso contrário, haverá picos devido a um erro de arredondamento. floor(x/width+0.5) não será feito porque criará um padrão que não é verdadeiro aos dados originais.

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

Com relação às funções de binning, não esperava o resultado das funções oferecidas até agora. Ou seja, se minha largura for de 0,001, essas funções estavam centralizando as caixas em 0,0005 pontos, enquanto eu sinto que é mais intuitivo ter os compartimentos centrados nos limites de 0,001.

Em outras palavras, eu gostaria de ter

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

A função de binning que eu inventei é

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

Aqui está um script para comparar algumas das funções oferecidas com 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
}

E aqui está a saída

   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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top